Fix build with CYNARA_NO_LOGS
[platform/core/security/cynara.git] / src / service / sockets / SocketManager.cpp
1 /*
2  * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
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>
20  * @version     1.0
21  * @brief       This file implements socket layer manager for cynara
22  */
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <memory>
27 #include <signal.h>
28 #include <sys/select.h>
29 #include <sys/signalfd.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/un.h>
34 #include <unistd.h>
35
36 #ifdef BUILD_WITH_SYSTEMD
37 #include <systemd/sd-daemon.h>
38 #endif
39
40 #include <attributes/attributes.h>
41 #include <log/log.h>
42 #include <common.h>
43 #include <config/PathConfig.h>
44 #include <exceptions/DescriptorNotExistsException.h>
45 #include <exceptions/InitException.h>
46 #include <exceptions/UnexpectedErrorException.h>
47
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>
56 #include <stdexcept>
57
58 #include "SocketManager.h"
59
60 namespace Cynara {
61
62 SocketManager::SocketManager() : m_working(false), m_maxDesc(-1) {
63     FD_ZERO(&m_readSet);
64     FD_ZERO(&m_writeSet);
65 }
66
67 SocketManager::~SocketManager() {
68 }
69
70 void SocketManager::run(void) {
71     init();
72     mainLoop();
73 }
74
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);
80
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");
89 }
90
91 void SocketManager::mainLoop(void) {
92     LOGI("SocketManger mainLoop start");
93     m_working  = true;
94     while (m_working) {
95         fd_set readSet = m_readSet;
96         fd_set writeSet = m_writeSet;
97
98         int ret = select(m_maxDesc + 1, &readSet, &writeSet, nullptr, nullptr);
99
100         if (ret < 0) {
101             switch (errno) {
102             case EINTR:
103                 continue;
104             default:
105                 int err = errno;
106                 throw UnexpectedErrorException(err, strerror(err));
107             }
108         } else if (ret > 0) {
109             for (int i = 0; i < m_maxDesc + 1 && ret; ++i) {
110                 if (FD_ISSET(i, &readSet)) {
111                     readyForRead(i);
112                     --ret;
113                 }
114                 if (FD_ISSET(i, &writeSet)) {
115                     readyForWrite(i);
116                     --ret;
117                 }
118             }
119
120             for (int i = 0; i < m_maxDesc + 1; ++i) {
121                 if (m_fds[i].isUsed() && m_fds[i].hasDataToWrite())
122                     addWriteSocket(i);
123             }
124         }
125     }
126     LOGI("SocketManger mainLoop done");
127 }
128
129 void SocketManager::mainLoopStop(void) {
130     m_working = false;
131 }
132
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()) {
137         readyForAccept(fd);
138         return;
139     }
140
141     RawBuffer readBuffer(DEFAULT_BUFFER_SIZE);
142     ssize_t size = read(fd, readBuffer.data(), DEFAULT_BUFFER_SIZE);
143
144     if (size > 0) {
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);
149             return;
150         }
151         LOGI("interpreting buffer read from [%d] failed", fd);
152     } else if (size < 0) {
153         int err = errno;
154         switch (err) {
155             case EAGAIN:
156 #if EWOULDBLOCK != EAGAIN
157             case EWOULDBLOCK:
158 #endif
159             case EINTR:
160                 return;
161             default:
162                 LOGW("While reading from [%d] socket, error [%d]:<%s>",
163                      fd, err, strerror(err));
164         }
165     } else {
166         LOGN("Socket [%d] closed on other end", fd);
167     }
168     closeSocket(fd);
169     LOGD("SocketManger readyForRead on fd [%d] done", fd);
170 }
171
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);
178     if (result == -1) {
179         int err = errno;
180         switch (err) {
181         case EAGAIN:
182         case EINTR:
183             // select will trigger write once again, nothing to do
184             break;
185         case EPIPE:
186         default:
187             LOGD("Error during write to fd [%d]:<%s> ", fd, strerror(err));
188             closeSocket(fd);
189             break;
190         }
191         return; // We do not want to propagate error to next layer
192     }
193
194     LOGD("written [%zd] bytes", result);
195     buffer.erase(buffer.begin(), buffer.begin() + result);
196
197     if (buffer.empty())
198         removeWriteSocket(fd);
199     LOGD("SocketManger readyForWrite on fd [%d] done", fd);
200 }
201
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));
210         return;
211     }
212     LOGD("Accept on sock [%d]. New client socket opened [%d]", fd, clientFd);
213
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);
219 }
220
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);
227     desc.clear();
228     close(fd);
229     LOGD("SocketManger closeSocket fd [%d] done", fd);
230 }
231
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);
236
237     try {
238         while(true) {
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
242                 break;
243             LOGD("request extracted");
244
245             //build context
246             RequestContext context(desc.responseTaker(), desc.writeQueue());
247             //pass request to request taker
248             req->execute(*requestTaker(), context);
249         }
250     } catch (const Exception &ex) {
251         LOGE("Error handling request <%s>. Closing socket", ex.what());
252         return false;
253     }
254     LOGD("SocketManger handleRead on fd [%d] done", fd);
255     return true;
256 }
257
258 void SocketManager::createDomainSocket(ProtocolPtr protocol, const std::string &path, mode_t mask,
259                                        bool client) {
260     int fd;
261 #ifdef BUILD_WITH_SYSTEMD
262     fd = getSocketFromSystemD(path);
263     if (fd == -1)
264 #endif
265         fd = createDomainSocketHelp(path, mask);
266
267     auto &desc = createDescriptor(fd, client);
268     desc.setListen(true);
269     desc.setProtocol(protocol);
270     addReadSocket(fd);
271
272     LOGD("Domain socket: [%d] added.", fd);
273 }
274
275 int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask) {
276     int fd;
277
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();
282     }
283
284     int flags;
285     if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
286         flags = 0;
287     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
288         UNUSED int err = errno;
289         close(fd);
290         LOGE("Error setting \"O_NONBLOCK\" on descriptor [%d] with fcntl: <%s>",
291              fd, strerror(err));
292         throw InitException();
293     }
294
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();
302     }
303     strcpy(serverAddress.sun_path, path.c_str());
304     unlink(serverAddress.sun_path);
305
306     mode_t originalUmask;
307     originalUmask = umask(mask);
308
309     if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
310         UNUSED int err = errno;
311         close(fd);
312         LOGE("Error in bind socket descriptor [%d] to path <%s>: <%s>",
313              fd, path.c_str(), strerror(err));
314         throw InitException();
315     }
316
317     umask(originalUmask);
318
319     if (listen(fd, 5) == -1) {
320         UNUSED int err = errno;
321         close(fd);
322         LOGE("Error setting listen on file descriptor [%d], path <%s>: <%s>",
323              fd, path.c_str(), strerror(err));
324         throw InitException();
325     }
326
327     return fd;
328 }
329
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);
334     if (n < 0) {
335         LOGE("Error in sd_listend_fds");
336         throw InitException();
337     }
338
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]",
342                     path.c_str(), fd);
343             return fd;
344         }
345     }
346     LOGI("No useable sockets were passed by systemd.");
347     return -1;
348 }
349 #endif // BUILD_WITH_SYSTEMD
350
351 void SocketManager::createSignalSocket(ProtocolPtr protocol) {
352     sigset_t mask;
353
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.
356     sigemptyset(&mask);
357     sigaddset(&mask, SIGTERM); // systemd terminates service sending this signal
358
359     if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
360         LOGE("sigprocmask failed: <%s>", strerror(errno));
361         return;
362     }
363
364     int fd = signalfd(-1, &mask, SFD_NONBLOCK);
365     if (fd < 0) {
366         LOGE("Creating signal file descriptor failed: <%s>", strerror(errno));
367         return;
368     }
369
370     auto &desc = createDescriptor(fd, false);
371     desc.setListen(false);
372     desc.setProtocol(protocol);
373     addReadSocket(fd);
374
375     LOGD("Signal socket: [%d] added.", fd);
376 }
377
378 Descriptor &SocketManager::createDescriptor(int fd, bool client) {
379     if (fd > m_maxDesc) {
380         m_maxDesc = fd;
381         if (fd >= static_cast<int>(m_fds.size()))
382             m_fds.resize(fd + 20);
383     }
384     auto &desc = m_fds[fd];
385     desc.setUsed(true);
386     desc.setClient(client);
387     return desc;
388 }
389
390 void SocketManager::addReadSocket(int fd) {
391     FD_SET(fd, &m_readSet);
392 }
393
394 void SocketManager::removeReadSocket(int fd) {
395     FD_CLR(fd, &m_readSet);
396 }
397
398 void SocketManager::addWriteSocket(int fd) {
399     FD_SET(fd, &m_writeSet);
400 }
401
402 void SocketManager::removeWriteSocket(int fd) {
403     FD_CLR(fd, &m_writeSet);
404 }
405
406 RequestTakerPtr SocketManager::requestTaker(void) {
407     return std::static_pointer_cast<RequestTaker>(m_logic);
408 }
409
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())
414             closeSocket(i);
415     }
416 }
417
418 } // namespace Cynara