2 * Copyright (c) 2014 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 SocketManager.cpp
18 * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
20 * @brief This file implements socket layer manager for cynara
25 #include <sys/select.h>
26 #include <sys/socket.h>
28 #include <sys/types.h>
32 #include <systemd/sd-daemon.h>
36 #include <exceptions/InitException.h>
37 #include <exceptions/UnexpectedErrorException.h>
39 #include <logic/Logic.h>
40 #include <main/Cynara.h>
41 #include <protocol/ProtocolAdmin.h>
42 #include <protocol/ProtocolClient.h>
43 #include <protocol/ProtocolSignal.h>
45 #include "SocketManager.h"
49 SocketManager::SocketManager() : m_working(false), m_maxDesc(-1) {
54 SocketManager::~SocketManager() {
57 void SocketManager::run(void) {
62 void SocketManager::init(void) {
63 LOGI("SocketManger init start");
64 const std::string clientSocketPath("/run/cynara/cynara.socket");
65 const std::string adminSocketPath("/run/cynara/cynara-admin.socket");
66 const mode_t clientSocketUMask(0);
67 const mode_t adminSocketUMask(0077);
69 createDomainSocket(new ProtocolClient, clientSocketPath, clientSocketUMask);
70 createDomainSocket(new ProtocolAdmin, adminSocketPath, adminSocketUMask);
71 // todo create signal descriptor
72 LOGI("SocketManger init done");
75 void SocketManager::mainLoop(void) {
76 LOGI("SocketManger mainLoop start");
79 fd_set readSet = m_readSet;
80 fd_set writeSet = m_writeSet;
82 int ret = select(m_maxDesc + 1, &readSet, &writeSet, nullptr, nullptr);
90 throw UnexpectedErrorException(err, strerror(err));
93 for (int i = 0; i < m_maxDesc + 1 && ret; ++i) {
94 if (FD_ISSET(i, &readSet)) {
98 if (FD_ISSET(i, &writeSet)) {
105 LOGI("SocketManger mainLoop done");
108 void SocketManager::mainLoopStop(void) {
112 void SocketManager::readyForRead(int fd) {
113 LOGD("SocketManger readyForRead on fd [%d] start", fd);
114 auto &desc = m_fds[fd];
115 if (desc.isListen()) {
120 RawBuffer readBuffer(DEFAULT_BUFFER_SIZE);
121 ssize_t size = read(fd, readBuffer.data(), DEFAULT_BUFFER_SIZE);
124 LOGD("read [%zd] bytes", size);
125 readBuffer.resize(size);
126 if (handleRead(fd, readBuffer)) {
127 LOGD("SocketManger readyForRead on fd [%d] successfully done", fd);
130 LOGI("interpreting buffer read from [%d] failed", fd);
131 } else if (size < 0) {
135 #if EWOULDBLOCK != EAGAIN
141 LOGW("While reading from [%d] socket, error [%d]:<%s>",
142 fd, err, strerror(err));
145 LOGN("Socket [%d] closed on other end", fd);
148 LOGD("SocketManger readyForRead on fd [%d] done", fd);
151 void SocketManager::readyForWrite(int fd) {
152 LOGD("SocketManger readyForWrite on fd [%d] start", fd);
153 auto &desc = m_fds[fd];
154 auto &buffer = desc.prepareWriteBuffer();
155 size_t size = buffer.size();
156 ssize_t result = write(fd, buffer.data(), size);
162 // select will trigger write once again, nothing to do
166 LOGD("Error during write to fd [%d]:<%s> ", fd, strerror(err));
170 return; // We do not want to propagate error to next layer
173 LOGD("written [%zd] bytes", result);
174 buffer.erase(buffer.begin(), buffer.begin() + result);
177 removeWriteSocket(fd);
178 LOGD("SocketManger readyForWrite on fd [%d] done", fd);
181 void SocketManager::readyForAccept(int fd) {
182 LOGD("SocketManger readyForAccept on fd [%d] start", fd);
183 struct sockaddr_un clientAddr;
184 unsigned int clientLen = sizeof(clientAddr);
185 int client = accept4(fd, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
188 LOGW("Error in accept on socket [%d]: <%s>", fd, strerror(err));
191 LOGD("Accept on sock [%d]. New client socket opened [%d]", fd, client);
193 auto &description = createDescriptor(client);
194 description.setListen(false);
195 description.setProtocol(m_fds[fd].protocol());
196 addReadSocket(client);
197 LOGD("SocketManger readyForAccept on fd [%d] done", fd);
200 void SocketManager::closeSocket(int fd) {
201 LOGD("SocketManger closeSocket fd [%d] start", fd);
202 removeReadSocket(fd);
203 removeWriteSocket(fd);
206 LOGD("SocketManger closeSocket fd [%d] done", fd);
209 bool SocketManager::handleRead(int fd, const RawBuffer &readbuffer) {
210 LOGD("SocketManger handleRead on fd [%d] start", fd);
211 auto &desc = m_fds[fd];
212 desc.pushReadBuffer(readbuffer);
215 Request *req = nullptr;
217 req = desc.extractRequest();
221 LOGD("request extracted");
222 req->execute(Cynara::getLogic(), {fd});
225 if (desc.isDataToWrite())
228 } catch (const Exception &ex) {
229 LOGE("Error handling request <%s>. Closing socket", ex.what());
232 LOGD("SocketManger handleRead on fd [%d] done", fd);
236 void SocketManager::createDomainSocket(Protocol *protocol, const std::string &path, mode_t mask) {
237 int fd = getSocketFromSystemD(path);
239 fd = createDomainSocketHelp(path, mask);
241 auto &desc = createDescriptor(fd);
242 desc.setListen(true);
243 desc.setProtocol(protocol);
246 LOGD("Domain socket: [%d] added.", fd);
249 int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask) {
252 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
254 LOGE("Error during UNIX socket creation: <%s>", strerror(err));
255 throw InitException();
259 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
261 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
264 LOGE("Error setting \"O_NONBLOCK\" on descriptor [%d] with fcntl: <%s>",
266 throw InitException();
269 sockaddr_un serverAddress;
270 memset(&serverAddress, 0, sizeof(serverAddress));
271 serverAddress.sun_family = AF_UNIX;
272 if (path.length() > sizeof(serverAddress.sun_path)) {
273 LOGE("Path for unix domain socket <%s> is [%zu] bytes long, while it should be maximum "
274 "[%zu] bytes long", path.c_str(), path.length(), sizeof(serverAddress));
275 throw InitException();
277 strcpy(serverAddress.sun_path, path.c_str());
278 unlink(serverAddress.sun_path);
280 mode_t originalUmask;
281 originalUmask = umask(mask);
283 if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
286 LOGE("Error in bind socket descriptor [%d] to path <%s>: <%s>",
287 fd, path.c_str(), strerror(err));
288 throw InitException();
291 umask(originalUmask);
293 if (listen(fd, 5) == -1) {
296 LOGE("Error setting listen on file descriptor [%d], path <%s>: <%s>",
297 fd, path.c_str(), strerror(err));
298 throw InitException();
304 int SocketManager::getSocketFromSystemD(const std::string &path) {
305 int n = sd_listen_fds(0);
306 LOGI("sd_listen_fds returns: [%d]", n);
308 LOGE("Error in sd_listend_fds");
309 throw InitException();
312 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
313 if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0) > 0) {
314 LOGI("Useable socket <%s> was passed by SystemD under descriptor [%d]",
319 LOGI("No useable sockets were passed by systemd.");
323 Descriptor &SocketManager::createDescriptor(int fd) {
324 if (fd > m_maxDesc) {
326 if (fd >= static_cast<int>(m_fds.size()))
327 m_fds.resize(fd + 20);
332 void SocketManager::addReadSocket(int fd) {
333 FD_SET(fd, &m_readSet);
336 void SocketManager::removeReadSocket(int fd) {
337 FD_CLR(fd, &m_readSet);
340 void SocketManager::addWriteSocket(int fd) {
341 FD_SET(fd, &m_writeSet);
344 void SocketManager::removeWriteSocket(int fd) {
345 FD_CLR(fd, &m_writeSet);
348 } // namespace Cynara