2 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file src/service/sockets/SocketManager.cpp
18 * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
19 * @author Adam Malinowski <a.malinowsk2@partner.samsung.com>
21 * @brief This file implements socket layer manager for cynara
28 #include <sys/select.h>
29 #include <sys/signalfd.h>
30 #include <sys/socket.h>
32 #include <sys/types.h>
36 #ifdef BUILD_WITH_SYSTEMD
37 #include <systemd/sd-daemon.h>
40 #include <attributes/attributes.h>
43 #include <config/PathConfig.h>
44 #include <exceptions/DescriptorNotExistsException.h>
45 #include <exceptions/InitException.h>
46 #include <exceptions/UnexpectedErrorException.h>
48 #include <logic/Logic.h>
49 #include <main/Cynara.h>
50 #include <protocol/ProtocolAdmin.h>
51 #include <protocol/ProtocolAgent.h>
52 #include <protocol/ProtocolClient.h>
53 #include <protocol/ProtocolSignal.h>
54 #include <request/pointers.h>
55 #include <request/RequestContext.h>
58 #include "SocketManager.h"
62 SocketManager::SocketManager() : m_working(false), m_maxDesc(-1) {
67 SocketManager::~SocketManager() {
70 void SocketManager::run(void) {
75 void SocketManager::init(void) {
76 LOGI("SocketManger init start");
77 const mode_t clientSocketUMask(0);
78 const mode_t adminSocketUMask(0077);
79 const mode_t agentSocketUMask(0);
81 createDomainSocket(std::make_shared<ProtocolClient>(), PathConfig::SocketPath::client,
82 clientSocketUMask, true);
83 createDomainSocket(std::make_shared<ProtocolAdmin>(), PathConfig::SocketPath::admin,
84 adminSocketUMask, false);
85 createDomainSocket(std::make_shared<ProtocolAgent>(), PathConfig::SocketPath::agent,
86 agentSocketUMask, false);
87 createSignalSocket(std::make_shared<ProtocolSignal>());
88 LOGI("SocketManger init done");
91 void SocketManager::mainLoop(void) {
92 LOGI("SocketManger mainLoop start");
95 fd_set readSet = m_readSet;
96 fd_set writeSet = m_writeSet;
98 int ret = select(m_maxDesc + 1, &readSet, &writeSet, nullptr, nullptr);
106 throw UnexpectedErrorException(err, strerror(err));
108 } else if (ret > 0) {
109 for (int i = 0; i < m_maxDesc + 1 && ret; ++i) {
110 if (FD_ISSET(i, &readSet)) {
114 if (FD_ISSET(i, &writeSet)) {
120 for (int i = 0; i < m_maxDesc + 1; ++i) {
121 if (m_fds[i].isUsed() && m_fds[i].hasDataToWrite())
126 LOGI("SocketManger mainLoop done");
129 void SocketManager::mainLoopStop(void) {
133 void SocketManager::readyForRead(int fd) {
134 LOGD("SocketManger readyForRead on fd [%d] start", fd);
135 auto &desc = m_fds[fd];
136 if (desc.isListen()) {
141 RawBuffer readBuffer(DEFAULT_BUFFER_SIZE);
142 ssize_t size = read(fd, readBuffer.data(), DEFAULT_BUFFER_SIZE);
145 LOGD("read [%zd] bytes", size);
146 readBuffer.resize(size);
147 if (handleRead(fd, readBuffer)) {
148 LOGD("SocketManger readyForRead on fd [%d] successfully done", fd);
151 LOGI("interpreting buffer read from [%d] failed", fd);
152 } else if (size < 0) {
156 #if EWOULDBLOCK != EAGAIN
162 LOGW("While reading from [%d] socket, error [%d]:<%s>",
163 fd, err, strerror(err));
166 LOGN("Socket [%d] closed on other end", fd);
169 LOGD("SocketManger readyForRead on fd [%d] done", fd);
172 void SocketManager::readyForWrite(int fd) {
173 LOGD("SocketManger readyForWrite on fd [%d] start", fd);
174 auto &desc = m_fds[fd];
175 auto &buffer = desc.prepareWriteBuffer();
176 size_t size = buffer.size();
177 ssize_t result = write(fd, buffer.data(), size);
183 // select will trigger write once again, nothing to do
187 LOGD("Error during write to fd [%d]:<%s> ", fd, strerror(err));
191 return; // We do not want to propagate error to next layer
194 LOGD("written [%zd] bytes", result);
195 buffer.erase(buffer.begin(), buffer.begin() + result);
198 removeWriteSocket(fd);
199 LOGD("SocketManger readyForWrite on fd [%d] done", fd);
202 void SocketManager::readyForAccept(int fd) {
203 LOGD("SocketManger readyForAccept on fd [%d] start", fd);
204 struct sockaddr_un clientAddr;
205 unsigned int clientLen = sizeof(clientAddr);
206 int clientFd = accept4(fd, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
207 if (clientFd == -1) {
208 UNUSED int err = errno;
209 LOGW("Error in accept on socket [%d]: <%s>", fd, strerror(err));
212 LOGD("Accept on sock [%d]. New client socket opened [%d]", fd, clientFd);
214 auto &desc = createDescriptor(clientFd, m_fds[fd].isClient());
215 desc.setListen(false);
216 desc.setProtocol(m_fds[fd].protocol()->clone());
217 addReadSocket(clientFd);
218 LOGD("SocketManger readyForAccept on fd [%d] done", fd);
221 void SocketManager::closeSocket(int fd) {
222 LOGD("SocketManger closeSocket fd [%d] start", fd);
223 Descriptor &desc = m_fds[fd];
224 requestTaker()->contextClosed(RequestContext(nullptr, desc.writeQueue()));
225 removeReadSocket(fd);
226 removeWriteSocket(fd);
229 LOGD("SocketManger closeSocket fd [%d] done", fd);
232 bool SocketManager::handleRead(int fd, const RawBuffer &readbuffer) {
233 LOGD("SocketManger handleRead on fd [%d] start", fd);
234 auto &desc = m_fds[fd];
235 desc.pushReadBuffer(readbuffer);
239 //try extract request from binary data received on socket
240 auto req = desc.extractRequest();
241 if (!req) // not enough data to build request yet
243 LOGD("request extracted");
246 RequestContext context(desc.responseTaker(), desc.writeQueue());
247 //pass request to request taker
248 req->execute(*requestTaker(), context);
250 } catch (const Exception &ex) {
251 LOGE("Error handling request <%s>. Closing socket", ex.what());
254 LOGD("SocketManger handleRead on fd [%d] done", fd);
258 void SocketManager::createDomainSocket(ProtocolPtr protocol, const std::string &path, mode_t mask,
261 #ifdef BUILD_WITH_SYSTEMD
262 fd = getSocketFromSystemD(path);
265 fd = createDomainSocketHelp(path, mask);
267 auto &desc = createDescriptor(fd, client);
268 desc.setListen(true);
269 desc.setProtocol(protocol);
272 LOGD("Domain socket: [%d] added.", fd);
275 int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask) {
278 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
279 UNUSED int err = errno;
280 LOGE("Error during UNIX socket creation: <%s>", strerror(err));
281 throw InitException();
285 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
287 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
288 UNUSED int err = errno;
290 LOGE("Error setting \"O_NONBLOCK\" on descriptor [%d] with fcntl: <%s>",
292 throw InitException();
295 sockaddr_un serverAddress;
296 memset(&serverAddress, 0, sizeof(serverAddress));
297 serverAddress.sun_family = AF_UNIX;
298 if (path.length() > sizeof(serverAddress.sun_path)) {
299 LOGE("Path for unix domain socket <%s> is [%zu] bytes long, while it should be maximum "
300 "[%zu] bytes long", path.c_str(), path.length(), sizeof(serverAddress));
301 throw InitException();
303 strcpy(serverAddress.sun_path, path.c_str());
304 unlink(serverAddress.sun_path);
306 mode_t originalUmask;
307 originalUmask = umask(mask);
309 if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
310 UNUSED int err = errno;
312 LOGE("Error in bind socket descriptor [%d] to path <%s>: <%s>",
313 fd, path.c_str(), strerror(err));
314 throw InitException();
317 umask(originalUmask);
319 if (listen(fd, 5) == -1) {
320 UNUSED int err = errno;
322 LOGE("Error setting listen on file descriptor [%d], path <%s>: <%s>",
323 fd, path.c_str(), strerror(err));
324 throw InitException();
330 #ifdef BUILD_WITH_SYSTEMD
331 int SocketManager::getSocketFromSystemD(const std::string &path) {
332 int n = sd_listen_fds(0);
333 LOGI("sd_listen_fds returns: [%d]", n);
335 LOGE("Error in sd_listend_fds");
336 throw InitException();
339 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
340 if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0) > 0) {
341 LOGI("Useable socket <%s> was passed by SystemD under descriptor [%d]",
346 LOGI("No useable sockets were passed by systemd.");
349 #endif // BUILD_WITH_SYSTEMD
351 void SocketManager::createSignalSocket(ProtocolPtr protocol) {
354 // Maybe someone will find useful some kind of registering signals with callbacks
355 // but for now I'm making it as simple as possible.
357 sigaddset(&mask, SIGTERM); // systemd terminates service sending this signal
359 if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
360 LOGE("sigprocmask failed: <%s>", strerror(errno));
364 int fd = signalfd(-1, &mask, SFD_NONBLOCK);
366 LOGE("Creating signal file descriptor failed: <%s>", strerror(errno));
370 auto &desc = createDescriptor(fd, false);
371 desc.setListen(false);
372 desc.setProtocol(protocol);
375 LOGD("Signal socket: [%d] added.", fd);
378 Descriptor &SocketManager::createDescriptor(int fd, bool client) {
379 if (fd > m_maxDesc) {
381 if (fd >= static_cast<int>(m_fds.size()))
382 m_fds.resize(fd + 20);
384 auto &desc = m_fds[fd];
386 desc.setClient(client);
390 void SocketManager::addReadSocket(int fd) {
391 FD_SET(fd, &m_readSet);
394 void SocketManager::removeReadSocket(int fd) {
395 FD_CLR(fd, &m_readSet);
398 void SocketManager::addWriteSocket(int fd) {
399 FD_SET(fd, &m_writeSet);
402 void SocketManager::removeWriteSocket(int fd) {
403 FD_CLR(fd, &m_writeSet);
406 RequestTakerPtr SocketManager::requestTaker(void) {
407 return std::static_pointer_cast<RequestTaker>(m_logic);
410 void SocketManager::disconnectAllClients(void) {
411 for(int i = 0; i <= m_maxDesc; ++i) {
412 auto &desc = m_fds[i];
413 if(desc.isUsed() && desc.isClient() && !desc.isListen())
418 } // namespace Cynara