Add early cynara service implementation
[platform/core/security/cynara.git] / src / service / sockets / SocketManager.cpp
1 /*
2  * Copyright (c) 2014 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        SocketManager.cpp
18  * @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
19  * @version     1.0
20  * @brief       This file implements socket layer manager for cynara
21  */
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/select.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30 #include <unistd.h>
31
32 #include <systemd/sd-daemon.h>
33
34 #include <log/log.h>
35 #include <common.h>
36 #include <exceptions/InitException.h>
37 #include <exceptions/UnexpectedErrorException.h>
38
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>
44
45 #include "SocketManager.h"
46
47 namespace Cynara {
48
49 SocketManager::SocketManager() : m_working(false), m_maxDesc(-1) {
50     FD_ZERO(&m_readSet);
51     FD_ZERO(&m_writeSet);
52 }
53
54 SocketManager::~SocketManager() {
55 }
56
57 void SocketManager::run(void) {
58     init();
59     mainLoop();
60 }
61
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);
68
69     createDomainSocket(new ProtocolClient, clientSocketPath, clientSocketUMask);
70     createDomainSocket(new ProtocolAdmin, adminSocketPath, adminSocketUMask);
71     // todo create signal descriptor
72     LOGI("SocketManger init done");
73 }
74
75 void SocketManager::mainLoop(void) {
76     LOGI("SocketManger mainLoop start");
77     m_working  = true;
78     while (m_working) {
79         fd_set readSet = m_readSet;
80         fd_set writeSet = m_writeSet;
81
82         int ret = select(m_maxDesc + 1, &readSet, &writeSet, nullptr, nullptr);
83
84         if (ret < 0) {
85             switch (errno) {
86             case EINTR:
87                 continue;
88             default:
89                 int err = errno;
90                 throw UnexpectedErrorException(err, strerror(err));
91             }
92         } else if (ret > 0) {
93             for (int i = 0; i < m_maxDesc + 1 && ret; ++i) {
94                 if (FD_ISSET(i, &readSet)) {
95                     readyForRead(i);
96                     --ret;
97                 }
98                 if (FD_ISSET(i, &writeSet)) {
99                     readyForWrite(i);
100                     --ret;
101                 }
102             }
103         }
104     }
105     LOGI("SocketManger mainLoop done");
106 }
107
108 void SocketManager::mainLoopStop(void) {
109     m_working = false;
110 }
111
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()) {
116         readyForAccept(fd);
117         return;
118     }
119
120     RawBuffer readBuffer(DEFAULT_BUFFER_SIZE);
121     ssize_t size = read(fd, readBuffer.data(), DEFAULT_BUFFER_SIZE);
122
123     if (size > 0) {
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);
128             return;
129         }
130         LOGI("interpreting buffer read from [%d] failed", fd);
131     } else if (size < 0) {
132         int err = errno;
133         switch (err) {
134             case EAGAIN:
135 #if EWOULDBLOCK != EAGAIN
136             case EWOULDBLOCK:
137 #endif
138             case EINTR:
139                 return;
140             default:
141                 LOGW("While reading from [%d] socket, error [%d]:<%s>",
142                      fd, err, strerror(err));
143         }
144     } else {
145         LOGN("Socket [%d] closed on other end", fd);
146     }
147     closeSocket(fd);
148     LOGD("SocketManger readyForRead on fd [%d] done", fd);
149 }
150
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);
157     if (result == -1) {
158         int err = errno;
159         switch (err) {
160         case EAGAIN:
161         case EINTR:
162             // select will trigger write once again, nothing to do
163             break;
164         case EPIPE:
165         default:
166             LOGD("Error during write to fd [%d]:<%s> ", fd, strerror(err));
167             closeSocket(fd);
168             break;
169         }
170         return; // We do not want to propagate error to next layer
171     }
172
173     LOGD("written [%zd] bytes", result);
174     buffer.erase(buffer.begin(), buffer.begin() + result);
175
176     if (buffer.empty())
177         removeWriteSocket(fd);
178     LOGD("SocketManger readyForWrite on fd [%d] done", fd);
179 }
180
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);
186     if (client == -1) {
187         int err = errno;
188         LOGW("Error in accept on socket [%d]: <%s>", fd, strerror(err));
189         return;
190     }
191     LOGD("Accept on sock [%d]. New client socket opened [%d]", fd, client);
192
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);
198 }
199
200 void SocketManager::closeSocket(int fd) {
201     LOGD("SocketManger closeSocket fd [%d] start", fd);
202     removeReadSocket(fd);
203     removeWriteSocket(fd);
204     m_fds[fd].clear();
205     close(fd);
206     LOGD("SocketManger closeSocket fd [%d] done", fd);
207 }
208
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);
213
214     try {
215         Request *req = nullptr;
216         for (;;) {
217             req = desc.extractRequest();
218             if (!req)
219                 break;
220
221             LOGD("request extracted");
222             req->execute(Cynara::getLogic(), {fd});
223             delete req;
224
225             if (desc.isDataToWrite())
226                     addWriteSocket(fd);
227         }
228     } catch (const Exception &ex) {
229         LOGE("Error handling request <%s>. Closing socket", ex.what());
230         return false;
231     }
232     LOGD("SocketManger handleRead on fd [%d] done", fd);
233     return true;
234 }
235
236 void SocketManager::createDomainSocket(Protocol *protocol, const std::string &path, mode_t mask) {
237     int fd = getSocketFromSystemD(path);
238     if (fd == -1)
239         fd = createDomainSocketHelp(path, mask);
240
241     auto &desc = createDescriptor(fd);
242     desc.setListen(true);
243     desc.setProtocol(protocol);
244     addReadSocket(fd);
245
246     LOGD("Domain socket: [%d] added.", fd);
247 }
248
249 int SocketManager::createDomainSocketHelp(const std::string &path, mode_t mask) {
250     int fd;
251
252     if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
253         int err = errno;
254         LOGE("Error during UNIX socket creation: <%s>",  strerror(err));
255         throw InitException();
256     }
257
258     int flags;
259     if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
260         flags = 0;
261     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
262         int err = errno;
263         close(fd);
264         LOGE("Error setting \"O_NONBLOCK\" on descriptor [%d] with fcntl: <%s>",
265              fd, strerror(err));
266         throw InitException();
267     }
268
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();
276     }
277     strcpy(serverAddress.sun_path, path.c_str());
278     unlink(serverAddress.sun_path);
279
280     mode_t originalUmask;
281     originalUmask = umask(mask);
282
283     if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
284         int err = errno;
285         close(fd);
286         LOGE("Error in bind socket descriptor [%d] to path <%s>: <%s>",
287              fd, path.c_str(), strerror(err));
288         throw InitException();
289     }
290
291     umask(originalUmask);
292
293     if (listen(fd, 5) == -1) {
294         int err = errno;
295         close(fd);
296         LOGE("Error setting listen on file descriptor [%d], path <%s>: <%s>",
297              fd, path.c_str(), strerror(err));
298         throw InitException();
299     }
300
301     return fd;
302 }
303
304 int SocketManager::getSocketFromSystemD(const std::string &path) {
305     int n = sd_listen_fds(0);
306     LOGI("sd_listen_fds returns: [%d]", n);
307     if (n < 0) {
308         LOGE("Error in sd_listend_fds");
309         throw InitException();
310     }
311
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]",
315                     path.c_str(), fd);
316             return fd;
317         }
318     }
319     LOGI("No useable sockets were passed by systemd.");
320     return -1;
321 }
322
323 Descriptor &SocketManager::createDescriptor(int fd) {
324     if (fd > m_maxDesc) {
325         m_maxDesc = fd;
326         if (fd >= static_cast<int>(m_fds.size()))
327             m_fds.resize(fd + 20);
328     }
329     return m_fds[fd];
330 }
331
332 void SocketManager::addReadSocket(int fd) {
333     FD_SET(fd, &m_readSet);
334 }
335
336 void SocketManager::removeReadSocket(int fd) {
337     FD_CLR(fd, &m_readSet);
338 }
339
340 void SocketManager::addWriteSocket(int fd) {
341     FD_SET(fd, &m_writeSet);
342 }
343
344 void SocketManager::removeWriteSocket(int fd) {
345     FD_CLR(fd, &m_writeSet);
346 }
347
348 } // namespace Cynara