Add socket methods 21/73321/4
authorOskar Świtalski <o.switalski@samsung.com>
Tue, 7 Jun 2016 05:35:29 +0000 (07:35 +0200)
committerOskar Świtalski <o.switalski@samsung.com>
Fri, 10 Jun 2016 15:48:31 +0000 (17:48 +0200)
Change-Id: I91b3566ec0abe2034e3a9dac29271ca5280f507a
Signed-off-by: Oskar Świtalski <o.switalski@samsung.com>
src/common/CMakeLists.txt
src/common/socket/SelectRead.cpp [new file with mode: 0644]
src/common/socket/SelectRead.h [new file with mode: 0644]
src/common/socket/Socket.cpp [new file with mode: 0644]
src/common/socket/Socket.h [new file with mode: 0644]

index da7fe96..8d1e37e 100644 (file)
@@ -37,6 +37,8 @@ INCLUDE_DIRECTORIES(
 
 SET(COMMON_SOURCES
     ${COMMON_PATH}/log/alog.cpp
+    ${COMMON_PATH}/socket/Socket.cpp
+    ${COMMON_PATH}/socket/SelectRead.cpp
     ${COMMON_PATH}/translator/Translator.cpp
     ${COMMON_PATH}/types/AgentErrorMsg.cpp
     ${COMMON_PATH}/util/SafeFunction.cpp
diff --git a/src/common/socket/SelectRead.cpp b/src/common/socket/SelectRead.cpp
new file mode 100644 (file)
index 0000000..aaf1343
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co.
+ *
+ *  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
+ */
+/**
+ * @file        SelectRead.cpp
+ * @author      Oskar Świtalski <o.switalski@samsung.com>
+ * @brief       Definition of SelectRead class
+ */
+
+#include "SelectRead.h"
+
+#include <exception/ErrnoException.h>
+
+namespace AskUser {
+
+namespace Socket {
+
+SelectRead::SelectRead() : m_exec(true), m_timeout({0, 0}) {}
+
+void SelectRead::add(int fd) {
+    if (m_exec) {
+        FD_ZERO(&m_set);
+        m_exec = false;
+    }
+
+    FD_SET(fd, &m_set);
+    m_nfds = m_nfds > fd ? m_nfds : fd;
+}
+
+int SelectRead::exec() {
+    int result = 0;
+
+    m_exec = true;
+
+    result = select(m_nfds + 1, &m_set, nullptr, nullptr, &m_timeout);
+    if (result == -1)
+        throw ErrnoException("Select failed");
+
+    return result;
+}
+
+bool SelectRead::isSet(int fd) {
+    return FD_ISSET(fd, &m_set);
+}
+
+void SelectRead::setTimeout(int ms) {
+    m_timeout.tv_usec = ms * 1000;
+}
+
+} /* namespace Socket */
+
+} /* namespace AskUser */
diff --git a/src/common/socket/SelectRead.h b/src/common/socket/SelectRead.h
new file mode 100644 (file)
index 0000000..3646ef5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co.
+ *
+ *  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
+ */
+/**
+ * @file        SelectRead.h
+ * @author      Oskar Świtalski <o.switalski@samsung.com>
+ * @brief       Declaration of SelectRead class
+ */
+
+#pragma once
+
+#include <sys/select.h>
+
+namespace AskUser {
+
+namespace Socket {
+
+class SelectRead {
+public:
+    SelectRead();
+
+    void add(int fd);
+    int exec();
+    bool isSet(int fd);
+    void setTimeout(int ms);
+private:
+    bool m_exec;
+
+    fd_set m_set;
+    int m_nfds;
+
+    timeval m_timeout;
+};
+
+} /* namespace Socket */
+
+} /* namespace AskUser */
diff --git a/src/common/socket/Socket.cpp b/src/common/socket/Socket.cpp
new file mode 100644 (file)
index 0000000..e9186b0
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co.
+ *
+ *  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
+ */
+/**
+ * @file        Socket.cpp
+ * @author      Oskar Świtalski <o.switalski@samsung.com>
+ * @brief       Implementation of Socket methods
+ */
+
+#include "Socket.h"
+
+#include <exception/ErrnoException.h>
+#include <log/alog.h>
+
+#include <stdexcept>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+namespace AskUser {
+
+namespace Socket {
+
+int accept(int fd) {
+    int retFd = TEMP_FAILURE_RETRY(::accept(fd, nullptr, nullptr));
+    if (retFd < 0)
+        throw ErrnoException("Accept socket error");
+
+    ALOGD("Accepted socket <" << retFd << ">");
+
+    return retFd;
+}
+
+void close(int fd) {
+    int result = TEMP_FAILURE_RETRY(::close(fd));
+    if (result < 0) {
+        ALOGE("Close socket <" << fd << "> failed");
+        return;
+    }
+
+    ALOGD("Closed socket <" << fd << ">");
+}
+
+int connect(const std::string &path) {
+    int fd = -1;
+    int result = 0;
+    size_t length = 0;
+
+    sockaddr_un remote;
+    remote.sun_family = AF_UNIX;
+
+    if (path.size() >= sizeof(remote.sun_path))
+        throw std::invalid_argument("Path length is too big");
+    strcpy(remote.sun_path, path.c_str());
+
+    length = strlen(remote.sun_path) + sizeof(remote.sun_family);
+
+    fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1)
+        throw ErrnoException("Socket creation failed");
+
+    result = TEMP_FAILURE_RETRY(::connect(fd, (struct sockaddr *)&remote, length));
+    if (result == -1)
+        throw ErrnoException("Connecting to <" + path + "> socket failed");
+
+    ALOGD("Connected to <" << path << "> socket");
+
+    return fd;
+}
+
+int listen(const std::string &path) {
+    int fd = -1;
+    int result = 0;
+    size_t length = 0;
+
+    sockaddr_un local;
+    local.sun_family = AF_UNIX;
+
+    if (path.size() >= sizeof(local.sun_path))
+        throw std::invalid_argument("Socket path too long");
+    strcpy(local.sun_path, path.c_str());
+
+    length = strlen(local.sun_path) + sizeof(local.sun_family);
+
+    result = unlink(path.c_str());
+    if (result == -1 && errno != ENOENT)
+        throw ErrnoException("Unlink " + path + " failed");
+
+    fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd == -1)
+        throw ErrnoException("Socket creation failed");
+
+    result = ::bind(fd, (struct sockaddr *)&local, length);
+    if (result == -1)
+        throw ErrnoException("Binding to <" + path + "> failed");
+
+    result = ::listen(fd, 10);
+    if (result == -1)
+        throw ErrnoException("Listen on socked failed");
+
+    ALOGD("Listening on <" << path << "> socket");
+
+    return fd;
+}
+
+bool recv(int fd, void *buf, size_t size, int flags) {
+    int result = 0;
+    size_t bytesRead = 0;
+
+    while (bytesRead < size) {
+        result = TEMP_FAILURE_RETRY(::recv(fd, buf, size, flags));
+
+        if (result < 0 && errno != ECONNRESET)
+            throw ErrnoException("Error receiving data from socket");
+        else if (result <= 0)
+            return false;
+
+        bytesRead += result;
+
+        ALOGD("Recieved " << bytesRead << "/" << size << " byte(s)");
+    }
+
+    return true;
+}
+
+bool send(int fd, const void *buf, size_t size, int flags) {
+    int result = 0;
+    size_t bytesSend = 0;
+
+    while (bytesSend < size) {
+
+        result = TEMP_FAILURE_RETRY(::send(fd, buf, size, flags | MSG_NOSIGNAL));
+
+        if (result < 0) {
+            if (errno == EPIPE)
+                return false;
+            else
+                throw ErrnoException("Error sending data to socket");
+        }
+
+        bytesSend += result;
+
+        ALOGD("Send " << result << "/" << size << " byte(s)");
+    }
+
+    return true;
+}
+
+} /* namespace Socket */
+
+} /* namespace AskUser */
diff --git a/src/common/socket/Socket.h b/src/common/socket/Socket.h
new file mode 100644 (file)
index 0000000..0f66d0d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co.
+ *
+ *  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
+ */
+/**
+ * @file        Socket.cpp
+ * @author      Oskar Świtalski <o.switalski@samsung.com>
+ * @brief       Declaration of Socket methods
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <string>
+
+namespace AskUser {
+
+namespace Socket {
+
+int accept(int fd);
+void close(int fd);
+int connect(const std::string &path);
+int listen(const std::string &path);
+bool recv(int fd, void *buf, size_t size, int flags = 0);
+bool send(int fd, const void *buf, size_t size, int flags = 0);
+
+} /* namespace Socket */
+
+} /* namespace AskUser */