--- /dev/null
+/*
+ * sensorctl
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <sensor_internal.h>
+
+#include "shared/socket.h"
+#include "shared/stream_socket.h"
+
+#include "log.h"
+#include "test_bench.h"
+
+using namespace ipc;
+
+#define MAX_BUF_SIZE 4096
+#define TEST_PATH "/run/.sensord_test.socket"
+
+typedef bool (*process_func_t)(const char *msg, int size, int count);
+
+static pid_t run_process(process_func_t func, const char *msg, int size, int count)
+{
+ pid_t pid = fork();
+ if (pid < 0)
+ return -1;
+
+ if (pid == 0) {
+ if (!func(msg, size, count))
+ _E("Failed to run process\n");
+ exit(0);
+ }
+
+ return pid;
+}
+
+/* Socket */
+static bool run_socket_echo_server(const char *msg, int size, int count)
+{
+ char buf[MAX_BUF_SIZE] = {0, };
+ bool ret = false;
+ int send_size = 0;
+ int recv_size = 0;
+ int recv_count = 0;
+ int send_count = 0;
+ int total_recv_size = 0;
+ int total_send_size = 0;
+ stream_socket accept_sock;
+ stream_socket client_sock;
+
+ accept_sock.create(TEST_PATH);
+ accept_sock.set_blocking_mode(true);
+ accept_sock.bind();
+ accept_sock.listen(10);
+ accept_sock.accept(client_sock);
+
+ /* receive message */
+ while (recv_count++ < count) {
+ recv_size = client_sock.recv(&buf, size);
+ total_recv_size += recv_size;
+ }
+ ASSERT_EQ(total_recv_size, (size * count));
+
+ usleep(10000);
+ /* echo message */
+ while (send_count++ < count) {
+ send_size = client_sock.send(buf, size);
+ total_send_size += send_size;
+ }
+ ASSERT_EQ(total_send_size, (size * count));
+
+ ret = strncmp(buf, msg, size);
+ ASSERT_EQ(ret, 0);
+
+ accept_sock.close();
+ client_sock.close();
+
+ return true;
+}
+
+static bool run_socket_client(const char *msg, int size, int count)
+{
+ char buf[MAX_BUF_SIZE] = {0, };
+ bool ret = false;
+ int send_size = 0;
+ int recv_size = 0;
+ int send_count = 0;
+ int recv_count = 0;
+ int total_recv_size = 0;
+ int total_send_size = 0;
+ stream_socket sock;
+
+ usleep(100000);
+
+ sock.create(TEST_PATH);
+ sock.set_blocking_mode(true);
+ sock.connect();
+
+ while (send_count++ < count) {
+ send_size = sock.send(msg, size);
+ total_send_size += send_size;
+ }
+
+ ASSERT_EQ(total_send_size, (size * count));
+
+ while (recv_count++ < count) {
+ recv_size = sock.recv(&buf, size);
+ total_recv_size += recv_size;
+ }
+
+ ASSERT_EQ(total_recv_size, (size * count));
+
+ ret = strncmp(buf, msg, size);
+ ASSERT_EQ(ret, 0);
+
+ sock.close();
+
+ usleep(100000);
+
+ return true;
+}
+
+/**
+ * @brief Test socket class with simple message
+ * @details 1. connect socket and listen event by socket
+ * 2. send/recv "TEST" text by using echo server
+ * 3. check "TEST" message
+ * @remarks we can test only regular socket, not systemd-based socket.
+ */
+TESTCASE(sensor_ipc_socket, socket_p_0)
+{
+ const char *msg = "TEST";
+ int size = 4;
+ int count = 1;
+
+ pid_t pid = run_process(run_socket_echo_server, msg, size, count);
+ EXPECT_GE(pid, 0);
+
+ bool ret = run_socket_client(msg, size, count);
+ ASSERT_TRUE(ret);
+
+ return true;
+}
+
+/**
+ * @brief Test socket class with 40K message
+ * @details 1. connect socket and listen event by socket
+ * 2. send/recv 40960 bytes(4096 bytes * 10) by using echo server
+ * 3. check total size
+ * @remarks we can test only regular socket, not systemd-based socket.
+ */
+TESTCASE(sensor_ipc_socket, socket_p_10)
+{
+ const char msg[MAX_BUF_SIZE] = {1, };
+ int size = MAX_BUF_SIZE;
+ int count = 10;
+
+ pid_t pid = run_process(run_socket_echo_server, msg, size, count);
+ EXPECT_GE(pid, 0);
+
+ bool ret = run_socket_client(msg, size, count);
+ ASSERT_TRUE(ret);
+
+ return true;
+}
+
+/**
+ * @brief Test socket class with 4M message
+ * @details 1. connect socket and listen event by socket
+ * 2. send/recv 4096000 bytes(4096 bytes * 1000) by using echo server
+ * 3. check total size
+ * @remarks we can test only regular socket, not systemd-based socket.
+ */
+TESTCASE(sensor_ipc_socket, socket_p_1000)
+{
+ const char msg[MAX_BUF_SIZE] = {1, };
+ int size = MAX_BUF_SIZE;
+ int count = 1000;
+
+ pid_t pid = run_process(run_socket_echo_server, msg, size, count);
+ EXPECT_GE(pid, 0);
+
+ bool ret = run_socket_client(msg, size, count);
+ ASSERT_TRUE(ret);
+
+ return true;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "seqpacket_socket.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "sensor_log.h"
+
+using namespace ipc;
+
+seqpacket_socket::seqpacket_socket()
+: socket()
+{
+}
+
+seqpacket_socket::~seqpacket_socket()
+{
+}
+
+bool seqpacket_socket::create(const std::string &path)
+{
+ return socket::create_by_type(path, SOCK_SEQPACKET);
+}
+
+ssize_t seqpacket_socket::on_send(const void *buffer, size_t size) const
+{
+ ssize_t err, len;
+
+ do {
+ len = ::send(socket::get_fd(),
+ reinterpret_cast<const char *>(buffer),
+ size,
+ socket::get_mode());
+
+ err = len < 0 ? errno : 0;
+ } while (err == EINTR);
+
+ if (err) {
+ _ERRNO(errno, _E, "Failed to send(%d, %#x, %d) = %d",
+ socket::get_fd(), buffer, size, len);
+ }
+
+ return err == 0 ? len : -err;
+}
+
+ssize_t seqpacket_socket::on_recv(void *buffer, size_t size) const
+{
+ ssize_t err, len;
+
+ do {
+ len = ::recv(socket::get_fd(),
+ reinterpret_cast<char *>(buffer),
+ size,
+ socket::get_mode());
+
+ if (len > 0) {
+ err = 0;
+ } else if (len == 0) {
+ _E("Failed to recv(%d, %#p , %d) = %d, because the peer performed shutdown!",
+ socket::get_fd(), buffer, size, len);
+ err = 1;
+ } else {
+ err = errno;
+ }
+ } while (err == EINTR);
+
+ if ((err == EAGAIN) || (err == EWOULDBLOCK))
+ return 0;
+
+ if (err) {
+ _ERRNO(errno, _E, "Failed to recv(%d, %#x, %d) = %d",
+ socket::get_fd(), buffer, size, len);
+ }
+
+ return err == 0 ? len : -err;
+}
+
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __SEQPACKET_SOCKET_H__
+#define __SEQPACKET_SOCKET_H__
+
+#include "socket.h"
+
+namespace ipc {
+
+class seqpacket_socket : public socket {
+public:
+ seqpacket_socket();
+ ~seqpacket_socket();
+
+ bool create(const std::string &path);
+
+private:
+ ssize_t on_send(const void *buffer, size_t size) const;
+ ssize_t on_recv(void *buffer, size_t size) const;
+
+};
+
+}
+
+#endif /* __SEQPACKET_SOCKET_H__ */
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "socket.h"
+
+#include <fcntl.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <systemd/sd-daemon.h>
+
+#include "sensor_log.h"
+
+using namespace ipc;
+
+static bool set_close_on_exec(int fd)
+{
+ if (::fcntl(fd, F_SETFL, FD_CLOEXEC) == -1)
+ return false;
+
+ return true;
+}
+
+static int create_systemd_socket(const std::string &path, int type)
+{
+ int n;
+ int listening;
+
+ listening = (type == SOCK_STREAM) ? 1 : -1;
+
+ n = sd_listen_fds(0);
+ retvm_if(n < 0, -EPERM, "Failed to listen fds from systemd");
+
+ for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
+ if (sd_is_socket_unix(fd, type, listening, path.c_str(), 0) > 0) {
+ set_close_on_exec(fd);
+ return fd;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int create_unix_socket(int type)
+{
+ int sock_fd = ::socket(AF_UNIX, type, 0);
+
+ if (sock_fd < 0) {
+ _ERRNO(errno, _E, "Failed to create socket");
+ return -EPERM;
+ }
+
+ set_close_on_exec(sock_fd);
+
+ int optval = 1;
+ if (::setsockopt(sock_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
+ _ERRNO(errno, _E, "Failed to create socket[%d]", sock_fd);
+ ::close(sock_fd);
+ return -EPERM;
+ }
+
+ return sock_fd;
+}
+
+static bool select_fds(int fd, fd_set *read_fds, fd_set *write_fds, const int timeout)
+{
+ struct timeval tv;
+ int err;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ while (true) {
+ err = ::select(fd + 1, read_fds, write_fds, NULL, &tv);
+ if (err <= 0)
+ return false;
+
+ if (read_fds && FD_ISSET(fd, read_fds))
+ break;
+ if (write_fds && FD_ISSET(fd, write_fds))
+ break;
+ }
+
+ return true;
+}
+
+socket::socket()
+: m_sock_fd(-1)
+, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL)
+, m_listening(false)
+{
+}
+
+socket::socket(int sock_fd)
+: m_sock_fd(sock_fd)
+, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL)
+, m_listening(false)
+{
+}
+
+socket::socket(const socket &sock)
+: m_sock_fd(-1)
+, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL)
+, m_listening(false)
+{
+ if (this == &sock)
+ return;
+
+ m_sock_fd = sock.m_sock_fd;
+ m_mode = sock.m_mode;
+ m_listening.store(sock.m_listening);
+}
+
+socket::~socket()
+{
+ close();
+}
+
+bool socket::connect(void)
+{
+ const int TIMEOUT = 3;
+ sockaddr_un addr;
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ FD_SET(m_sock_fd, &write_fds);
+
+ retvm_if(m_path.size() >= sizeof(sockaddr_un::sun_path), false,
+ "Failed to create socket[%s]", m_path.c_str());
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, m_path.c_str(), sizeof(sockaddr_un::sun_path));
+ addr.sun_path[m_path.size()] = '\0';
+
+ if (::connect(m_sock_fd,
+ reinterpret_cast<struct sockaddr *>(&addr),
+ sizeof(struct sockaddr_un)) < 0) {
+ _ERRNO(errno, _E, "Failed to connect() for socket[%d]", m_sock_fd);
+ close();
+ return false;
+ }
+
+ if (!select_fds(m_sock_fd, NULL, &write_fds, TIMEOUT)) {
+ _E("Failed to select for socket[%d]", m_sock_fd);
+ close();
+ return false;
+ }
+
+ if (!has_connected()) {
+ close();
+ return false;
+ }
+
+ _D("Connected[%d]", m_sock_fd);
+
+ return true;
+}
+
+bool socket::bind(void)
+{
+ sockaddr_un addr;
+ int file_mode;
+
+ retvm_if(m_path.size() >= sizeof(sockaddr_un::sun_path), false,
+ "Failed to create socket[%s]", m_path.c_str());
+ retv_if(m_listening.load(), true);
+
+ if (!access(m_path.c_str(), F_OK))
+ unlink(m_path.c_str());
+
+ addr.sun_family = AF_UNIX;
+ ::strncpy(addr.sun_path, m_path.c_str(), sizeof(sockaddr_un::sun_path));
+ addr.sun_path[m_path.size()] = '\0';
+
+ if (::bind(m_sock_fd,
+ reinterpret_cast<struct sockaddr *>(&addr),
+ sizeof(struct sockaddr_un)) < 0) {
+ _ERRNO(errno, _E, "Failed to bind for socket[%d]", m_sock_fd);
+ close();
+ return false;
+ }
+
+ /* TODO: Is this really necessary? */
+ file_mode = (S_IRWXU | S_IRWXG | S_IRWXO);
+ if (chmod(m_path.c_str(), file_mode) < 0) {
+ _ERRNO(errno, _E, "Failed to create socket[%d]", m_sock_fd);
+ close();
+ return false;
+ }
+
+ _D("Bound to path[%d, %s]", m_sock_fd, m_path.c_str());
+
+ return true;
+}
+
+bool socket::listen(const int max_connections)
+{
+ retv_if(m_listening.load(), true);
+
+ if (::listen(m_sock_fd, max_connections) < 0) {
+ _ERRNO(errno, _E, "Failed to listen() for socket[%d]", m_sock_fd);
+ close();
+ return false;
+ }
+
+ m_listening.store(true);
+
+ _D("Listened[%d]", m_sock_fd);
+
+ return true;
+}
+
+bool socket::accept(socket &client_sock)
+{
+ int fd;
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(m_sock_fd, &read_fds);
+
+ fd = ::accept(m_sock_fd, NULL, NULL);
+
+ if (fd < 0) {
+ _ERRNO(errno, _E, "Failed to accept[%d]", m_sock_fd);
+ return false;
+ }
+
+ set_close_on_exec(fd);
+ client_sock.set_fd(fd);
+ /* TODO : socket type should be adjusted here */
+
+ _D("Accepted[%d, %d]", m_sock_fd, fd);
+
+ return true;
+}
+
+bool socket::close(void)
+{
+ retv_if(m_sock_fd < 0, false);
+
+ if (::close(m_sock_fd) < 0) {
+ _ERRNO(errno, _E, "Failed to close socket[%d]", m_sock_fd);
+ return false;
+ }
+
+ _D("Closed[%d]", m_sock_fd);
+
+ m_sock_fd = -1;
+ m_listening.store(false);
+
+ return true;
+}
+
+int socket::get_fd(void) const
+{
+ return m_sock_fd;
+}
+
+void socket::set_fd(int sock_fd)
+{
+ m_sock_fd = sock_fd;
+}
+
+int socket::get_mode(void) const
+{
+ return m_mode;
+}
+
+bool socket::set_mode(int mode)
+{
+ /* TODO : implement send/recv message mode */
+ return true;
+}
+
+bool socket::create(const std::string &path)
+{
+ return false;
+}
+
+ssize_t socket::send(const void *buffer, size_t size, bool select) const
+{
+ if (select) {
+ const int TIMEOUT = 1;
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ FD_SET(m_sock_fd, &write_fds);
+
+ if (!select_fds(m_sock_fd, NULL, &write_fds, TIMEOUT)) {
+ _E("Failed to send message(timeout)");
+ return 0;
+ }
+ }
+
+ return on_send(buffer, size);
+}
+
+ssize_t socket::recv(void* buffer, size_t size, bool select) const
+{
+ /* WARNING: if select() is called here, it affects performance */
+ return on_recv(buffer, size);
+}
+
+bool socket::create_by_type(const std::string &path, int type)
+{
+ m_sock_fd = ::create_systemd_socket(path, type);
+ if (m_sock_fd < 0) {
+ _D("Creating the UDS instead of systemd socket..");
+ m_sock_fd = create_unix_socket(type);
+ } else {
+ m_listening.store(true);
+ }
+
+ retvm_if((m_sock_fd < 0), false, "Failed to create socket");
+
+ /* non-blocking mode */
+ retvm_if(!set_blocking_mode(false), false, "Failed to set non-blocking mode");
+ /* recv timeout */
+ retvm_if(!set_recv_timeout(1), false, "Failed to set timeout");
+ /* TODO */
+ /*retvm_if(!set_reuse_addr(), false, "Failed to reuse address"); */
+
+ _D("Created[%d]", m_sock_fd);
+
+ m_path = path;
+
+ return true;
+}
+
+int socket::get_sock_type(void)
+{
+ socklen_t opt_len;
+ int sock_type;
+ opt_len = sizeof(sock_type);
+
+ retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd);
+
+ if (getsockopt(m_sock_fd, SOL_SOCKET, SO_TYPE, &sock_type, &opt_len) < 0) {
+ _ERRNO(errno, _E, "Failed to getsockopt from socket[%d]", m_sock_fd);
+ return false;
+ }
+
+ return sock_type;
+}
+
+bool socket::set_recv_timeout(int sec)
+{
+ struct timeval timeout = {sec, 0};
+
+ retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd);
+
+ if (setsockopt(m_sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
+ _ERRNO(errno, _E, "Failed to setsockopt[%d]", m_sock_fd);
+ return false;
+ }
+
+ return true;
+}
+
+bool socket::set_sock_type(int type)
+{
+ socklen_t opt_len;
+ int sock_type;
+ opt_len = sizeof(sock_type);
+
+ retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd);
+
+ if (setsockopt(m_sock_fd, SOL_SOCKET, SO_TYPE, &sock_type, opt_len) < 0) {
+ _ERRNO(errno, _E, "Failed to setsockopt[%d]", m_sock_fd);
+ return false;
+ }
+
+ return true;
+}
+
+bool socket::set_blocking_mode(bool blocking)
+{
+ int flags;
+
+ flags = fcntl(m_sock_fd, F_GETFL);
+ retvm_if(flags == -1, false, "Failed to fcntl(F_GETFL)[%d]", m_sock_fd);
+
+ flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
+
+ flags = fcntl(m_sock_fd, F_SETFL, flags);
+ retvm_if(flags == -1, false, "Failed to fcntl(F_SETFL)[%d]", m_sock_fd);
+
+ return true;
+}
+
+bool socket::has_connected(void)
+{
+ int so_error;
+ socklen_t len = sizeof(so_error);
+
+ if (getsockopt(m_sock_fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
+ _E("Failed to call getsockopt[%d]", m_sock_fd);
+ return false;
+ }
+
+ if (so_error) {
+ _E("Failed to connect[%d]: %d", so_error);
+ return false;
+ }
+
+ return true;
+}
+
+bool socket::set_buffer_size(int type, int size)
+{
+ retv_if(m_sock_fd < 0, false);
+
+ int ret = 0;
+
+ ret = setsockopt(m_sock_fd, SOL_SOCKET, type, &size, sizeof(size));
+ retvm_if(ret < 0, false, "Failed to call setsocketopt()");
+
+ return true;
+}
+
+int socket::get_buffer_size(int type)
+{
+ retv_if(m_sock_fd < 0, false);
+
+ int ret = 0;
+ int buf_size = 0;
+ socklen_t len;
+
+ ret = getsockopt(m_sock_fd, SOL_SOCKET, type, &buf_size, &len);
+ retvm_if(ret < 0, -EPERM, "Failed to call getsocketopt()");
+
+ return buf_size;
+}
+
+int socket::get_current_buffer_size(void)
+{
+ retv_if(m_sock_fd < 0, false);
+
+ int queue_size = 0;
+ ioctl(m_sock_fd, TIOCOUTQ, &queue_size);
+
+ return queue_size;
+}
+
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __SOCKET_H__
+#define __SOCKET_H__
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string>
+#include <atomic>
+
+namespace ipc {
+
+class socket {
+public:
+ socket();
+ socket(int sock_fd);
+ socket(const socket &sock);
+ virtual ~socket();
+
+ virtual bool create(const std::string &path);
+
+ bool connect(void);
+ bool bind(void);
+ bool listen(const int max_connections);
+ bool accept(socket &client_sock);
+
+ bool close(void);
+
+ int get_fd(void) const;
+ void set_fd(int sock_fd);
+
+ int get_mode(void) const;
+ bool set_mode(int mode);
+
+ bool set_blocking_mode(bool blocking);
+ bool set_recv_timeout(int timeout);
+
+ /* type : SO_SNDBUF, SO_RCVBUF */
+ bool set_buffer_size(int type, int size);
+ int get_buffer_size(int type);
+ int get_current_buffer_size(void);
+
+ ssize_t send(const void *buffer, size_t size, bool select = false) const;
+ ssize_t recv(void* buffer, size_t size, bool select = false) const;
+
+protected:
+ bool create_by_type(const std::string &path, int type);
+
+private:
+ virtual ssize_t on_send(const void *buffer, size_t size) const = 0;
+ virtual ssize_t on_recv(void* buffer, size_t size) const = 0;
+
+ int get_sock_type(void);
+ bool set_sock_type(int type);
+ bool has_connected(void);
+
+ int m_sock_fd;
+ int m_mode;
+ std::atomic<bool> m_listening;
+ std::string m_path;
+};
+
+}
+
+#endif /* __SOCKET_H__ */
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "stream_socket.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "sensor_log.h"
+
+using namespace ipc;
+
+stream_socket::stream_socket()
+: socket()
+{
+}
+
+stream_socket::~stream_socket()
+{
+}
+
+bool stream_socket::create(const std::string &path)
+{
+ return socket::create_by_type(path, SOCK_STREAM);
+}
+
+ssize_t stream_socket::on_send(const void *buffer, size_t size) const
+{
+ ssize_t len = 0;
+ size_t total_size = 0;
+
+ do {
+ len = ::send(get_fd(),
+ reinterpret_cast<const char *>(buffer) + total_size,
+ size - total_size, get_mode());
+
+ if (len < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ usleep(1);
+ continue;
+ }
+
+ _ERRNO(errno, _E, "Failed to send(%d, %#p, %x, %d) = %d",
+ get_fd(), buffer, total_size, size - total_size, len);
+ return -errno;
+ }
+
+ total_size += len;
+ } while (total_size < size);
+
+ return total_size;
+}
+
+ssize_t stream_socket::on_recv(void *buffer, size_t size) const
+{
+ ssize_t len = 0;
+ size_t total_size = 0;
+
+ do {
+ len = ::recv(get_fd(),
+ reinterpret_cast<char *>(buffer) + total_size,
+ size - total_size,
+ socket::get_mode());
+
+ if (len == 0) {
+ _E("Failed to recv(%d, %#p + %x, %d) = %d, because the peer performed shutdown",
+ get_fd(), buffer, total_size, size - total_size, len);
+ return -1;
+ }
+
+ if (len < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ usleep(10000);
+ continue;
+ }
+
+ _ERRNO(errno, _E, "Failed to recv(%d, %#p, %x, %d) = %d",
+ get_fd(), buffer, total_size, size - total_size, len);
+ return -errno;
+ }
+
+ total_size += len;
+ } while (total_size < size);
+
+ return total_size;
+}
--- /dev/null
+/*
+ * sensord
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __STREAM_SOCKET_H__
+#define __STREAM_SOCKET_H__
+
+#include "socket.h"
+
+namespace ipc {
+
+class stream_socket : public socket {
+public:
+ stream_socket();
+ ~stream_socket();
+
+ bool create(const std::string &path);
+
+private:
+ ssize_t on_send(const void *buffer, size_t size) const;
+ ssize_t on_recv(void *buffer, size_t size) const;
+};
+
+}
+
+#endif /* __STREAM_SOCKET_H__ */