2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Jan Olszak <j.olszak@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Jan Olszak (j.olszak@samsung.com)
22 * @brief Linux socket wrapper
27 #include "ipc/exception.hpp"
28 #include "ipc/internals/socket.hpp"
29 #include "utils/fd-utils.hpp"
30 #include "utils/exception.hpp"
31 #include "logger/logger.hpp"
34 #include <systemd/sd-daemon.h>
35 #endif // HAVE_SYSTEMD
36 #include <sys/socket.h>
44 using namespace utils;
49 const int MAX_QUEUE_LENGTH = 1000;
51 void setFdOptions(int fd)
53 // Prevent from inheriting fd by zones
54 if (-1 == ::fcntl(fd, F_SETFD, FD_CLOEXEC)) {
55 const std::string msg = "Error in fcntl: " + getSystemErrorMessage();
57 throw IPCException(msg);
63 Socket::Socket(int socketFD)
68 Socket::Socket(Socket&& socket) noexcept
74 Socket::~Socket() noexcept
78 } catch (std::exception& e) {
79 LOGE("Error in Socket's destructor: " << e.what());
83 Socket::Guard Socket::getGuard() const
85 return Guard(mCommunicationMutex);
88 int Socket::getFD() const
93 std::shared_ptr<Socket> Socket::accept()
95 int sockfd = ::accept(mFD, nullptr, nullptr);
97 const std::string msg = "Error in accept: " + getSystemErrorMessage();
99 throw IPCException(msg);
101 setFdOptions(sockfd);
102 return std::make_shared<Socket>(sockfd);
105 void Socket::write(const void* bufferPtr, const size_t size) const
107 Guard guard(mCommunicationMutex);
108 utils::write(mFD, bufferPtr, size);
111 void Socket::read(void* bufferPtr, const size_t size) const
113 Guard guard(mCommunicationMutex);
114 utils::read(mFD, bufferPtr, size);
118 int Socket::getSystemdSocketInternal(const std::string& path)
120 int n = ::sd_listen_fds(-1 /*Block further calls to sd_listen_fds*/);
122 const std::string msg = "sd_listen_fds failed: " + getSystemErrorMessage(-n);
124 throw IPCException(msg);
127 for (int fd = SD_LISTEN_FDS_START;
128 fd < SD_LISTEN_FDS_START + n;
130 if (0 < ::sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0)) {
135 LOGW("No usable sockets were passed by systemd.");
138 #endif // HAVE_SYSTEMD
140 int Socket::createSocketInternal(const std::string& path)
142 // Isn't the path too long?
143 if (path.size() >= sizeof(sockaddr_un::sun_path)) {
144 const std::string msg = "Socket's path too long";
146 throw IPCException(msg);
149 int sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
151 const std::string msg = "Error in socket: " + getSystemErrorMessage();
153 throw IPCSocketException(errno, msg);
155 setFdOptions(sockfd);
157 ::sockaddr_un serverAddress;
158 serverAddress.sun_family = AF_UNIX;
159 ::strncpy(serverAddress.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
160 unlink(serverAddress.sun_path);
162 // Everybody can access the socket
163 // TODO: Use SMACK to guard the socket
164 if (-1 == ::bind(sockfd,
165 reinterpret_cast<struct sockaddr*>(&serverAddress),
166 sizeof(struct sockaddr_un))) {
167 utils::close(sockfd);
168 const std::string msg = "Error in bind: " + getSystemErrorMessage();
170 throw IPCException(msg);
173 if (-1 == ::listen(sockfd,
175 utils::close(sockfd);
176 const std::string msg = "Error in listen: " + getSystemErrorMessage();
178 throw IPCException(msg);
184 Socket Socket::createSocket(const std::string& path)
186 // Initialize a socket
189 fd = getSystemdSocketInternal(path);
191 fd = createSocketInternal(path);
194 fd = createSocketInternal(path);
195 #endif // HAVE_SYSTEMD
200 Socket Socket::connectSocket(const std::string& path)
202 // Isn't the path too long?
203 if (path.size() >= sizeof(sockaddr_un::sun_path)) {
204 const std::string msg = "Socket's path too long";
206 throw IPCException(msg);
209 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
211 const std::string msg = "Error in socket: " + getSystemErrorMessage();
213 throw IPCSocketException(errno, msg);
217 sockaddr_un serverAddress;
218 serverAddress.sun_family = AF_UNIX;
219 strncpy(serverAddress.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
221 if (-1 == connect(fd,
222 reinterpret_cast<struct sockaddr*>(&serverAddress),
223 sizeof(struct sockaddr_un))) {
225 const std::string msg = "Error in connect: " + getSystemErrorMessage();
227 throw IPCException(msg);
231 int flags = fcntl(fd, F_GETFL, 0);
232 if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
234 const std::string msg = "Error in fcntl: " + getSystemErrorMessage();
236 throw IPCException(msg);