2 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Bumjin Im <bj.im@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
19 * @file socket-manager.cpp
20 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
22 * @brief Implementation of SocketManager.
28 #include <sys/select.h>
29 #include <sys/signalfd.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
39 #include <systemd/sd-daemon.h>
41 #include <dpl/errno_string.h>
42 #include <dpl/log/log.h>
43 #include <dpl/assert.h>
45 #include <ckm/ckm-client-info.h>
46 #include <socket-manager.h>
49 const time_t SOCKET_TIMEOUT = 1000;
51 int getCredentialsFromSocket(int sock, CKM::Credentials &cred, vsm_context_h &vsmCtx)
53 std::vector<char> result(1);
57 if ((0 > getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length))
60 LogError("getsockopt failed");
64 result.resize(length);
66 if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length)) {
67 LogError("getsockopt failed");
71 length = sizeof(ucred);
73 if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peerCred, &length)) {
74 LogError("getsockopt failed");
78 result.push_back('\0');
79 cred.smackLabel = result.data();
81 CKM::ClientInfo clientInfo(peerCred.uid);
82 cred.clientID = clientInfo.getClientID();
83 LogError("vsmCtx == NULL. ClientID[" << cred.clientID << "]");
85 vsm_zone_h _vsm_zone = vsm_lookup_zone_by_pid(vsmCtx, peerCred.pid);
87 if (0 > vsm_cleanup_context(vsmCtx)) {
88 LogError("Failed to vsm_cleanup_context.");
89 } else if (!(vsmCtx = vsm_create_context())) {
90 LogError("Failed to vsm_create_context.");
93 LogDebug("Recreate vsm context Success. vsm_lookup_zone_by_pid:[" << peerCred.pid << "] returned NULL");
94 _vsm_zone = vsm_lookup_zone_by_pid(vsmCtx, peerCred.pid);
97 LogError("Failed. vsm_zone lookedup by pid:[" << peerCred.pid << "]");
98 vsm_cleanup_context(vsmCtx);
102 LogDebug("Success. vsm_lookup_zone_by_pid:[" << peerCred.pid << "]");
105 // construct clientInfo with default zone
106 CKM::ClientInfo clientInfo(peerCred.uid);
108 if (!vsm_is_host_zone(_vsm_zone))
109 clientInfo = CKM::ClientInfo(std::string(vsm_get_zone_name(_vsm_zone)), peerCred.uid);
111 cred.clientID = clientInfo.getClientID();
112 LogDebug("sock[" << sock << "] clientID[" << cred.clientID << "]");
116 } // namespace anonymous
120 struct DummyService : public GenericSocketService {
121 ServiceDescriptionVector GetServiceDescription() {
122 return ServiceDescriptionVector();
124 void Event(const AcceptEvent &event) { (void)event; }
125 void Event(const WriteEvent &event) { (void)event; }
126 void Event(const ReadEvent &event) { (void)event; }
127 void Event(const CloseEvent &event) { (void)event; }
130 struct SignalService : public GenericSocketService {
131 int GetDescriptor() {
135 sigaddset(&mask, SIGTERM);
136 if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL))
138 return signalfd(-1, &mask, 0);
141 ServiceDescriptionVector GetServiceDescription() {
142 return ServiceDescriptionVector();
145 void Event(const AcceptEvent &event) { (void)event; } // not supported
146 void Event(const WriteEvent &event) { (void)event; } // not supported
147 void Event(const CloseEvent &event) { (void)event; } // not supported
149 void Event(const ReadEvent &event) {
150 LogDebug("Get signal information");
152 if(sizeof(struct signalfd_siginfo) != event.rawBuffer.size()) {
153 LogError("Wrong size of signalfd_siginfo struct. Expected: "
154 << sizeof(signalfd_siginfo) << " Get: "
155 << event.rawBuffer.size());
159 signalfd_siginfo *siginfo = (signalfd_siginfo*)(&(event.rawBuffer[0]));
161 if (siginfo->ssi_signo == SIGTERM) {
162 LogInfo("Got signal: SIGTERM");
163 static_cast<SocketManager*>(m_serviceManager)->MainLoopStop();
167 LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo);
171 SocketManager::SocketDescription&
172 SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout)
174 if ((int)m_socketDescriptionVector.size() <= sock)
175 m_socketDescriptionVector.resize(sock+20);
177 auto &desc = m_socketDescriptionVector[sock];
178 desc.isListen = false;
180 desc.interfaceID = 0;
182 desc.counter = ++m_counter;
185 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
186 if (false == desc.isTimeout) {
188 tm.time = desc.timeout;
190 m_timeoutQueue.push(tm);
194 desc.isTimeout = timeout;
196 FD_SET(sock, &m_readSet);
197 m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc;
201 SocketManager::SocketManager()
207 FD_ZERO(&m_writeSet);
208 if (-1 == pipe(m_notifyMe)) {
210 ThrowMsg(Exception::InitFailed, "Error in pipe: " << GetErrnoString(err));
212 LogInfo("Pipe: Read desc: " << m_notifyMe[0] << " Write desc: " << m_notifyMe[1]);
214 auto &desc = CreateDefaultReadSocketDescription(m_notifyMe[0], false);
215 desc.service = new DummyService;
217 // std::thread bases on pthread so this should work fine
220 sigaddset(&set, SIGPIPE);
221 pthread_sigmask(SIG_BLOCK, &set, NULL);
223 // add support for TERM signal (passed from systemd)
224 auto *signalService = new SignalService;
225 signalService->SetSocketManager(this);
226 int filefd = signalService->GetDescriptor();
228 LogError("Error in SignalService.GetDescriptor()");
229 delete signalService;
231 auto &desc2 = CreateDefaultReadSocketDescription(filefd, false);
232 desc2.service = signalService;
233 LogInfo("SignalService mounted on " << filefd << " descriptor");
235 m_vsmCtx = vsm_create_context();
236 // TODO: handle error
239 SocketManager::~SocketManager() {
240 std::set<GenericSocketService*> serviceMap;
242 // Find all services. Set is used to remove duplicates.
243 // In this implementation, services are not able to react in any way.
244 for (size_t i=0; i < m_socketDescriptionVector.size(); ++i)
245 if (m_socketDescriptionVector[i].isOpen)
246 serviceMap.insert(m_socketDescriptionVector[i].service);
248 // Time to destroy all services.
249 for(auto it = serviceMap.begin(); it != serviceMap.end(); ++it) {
250 LogDebug("delete " << (void*)(*it));
254 for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i)
255 if (m_socketDescriptionVector[i].isOpen)
258 // All socket except one were closed. Now pipe input must be closed.
259 close(m_notifyMe[1]);
262 void SocketManager::ReadyForAccept(int sock) {
263 struct sockaddr_un clientAddr;
264 unsigned int clientLen = sizeof(clientAddr);
265 int client = accept4(sock, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
266 // LogInfo("Accept on sock: " << sock << " Socket opended: " << client);
269 LogDebug("Error in accept: " << GetErrnoString(err));
273 Credentials peerCred;
274 if (0 > getCredentialsFromSocket(client, peerCred, m_vsmCtx)) {
275 LogDebug("Error in getCredentialsFromSocket. Socket closed.");
276 TEMP_FAILURE_RETRY(close(client));
280 auto &desc = CreateDefaultReadSocketDescription(client, true);
281 desc.interfaceID = m_socketDescriptionVector[sock].interfaceID;
282 desc.service = m_socketDescriptionVector[sock].service;
284 GenericSocketService::AcceptEvent event;
285 event.connectionID.sock = client;
286 event.connectionID.counter = desc.counter;
287 event.interfaceID = desc.interfaceID;
288 event.credentials = peerCred;
289 desc.service->Event(event);
292 void SocketManager::ReadyForRead(int sock) {
293 if (m_socketDescriptionVector[sock].isListen) {
294 ReadyForAccept(sock);
298 GenericSocketService::ReadEvent event;
299 event.connectionID.sock = sock;
300 event.connectionID.counter = m_socketDescriptionVector[sock].counter;
301 event.rawBuffer.resize(4096);
303 auto &desc = m_socketDescriptionVector[sock];
304 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
306 ssize_t size = read(sock, &event.rawBuffer[0], 4096);
310 } else if (size >= 0) {
311 event.rawBuffer.resize(size);
312 desc.service->Event(event);
313 } else if (size == -1) {
320 LogDebug("Reading sock error: " << GetErrnoString(err));
326 void SocketManager::ReadyForWriteBuffer(int sock) {
327 auto &desc = m_socketDescriptionVector[sock];
328 size_t size = desc.rawBuffer.size();
329 ssize_t result = write(sock, &desc.rawBuffer[0], size);
335 // select will trigger write once again, nothing to do
339 LogDebug("Error during write: " << GetErrnoString(err));
343 return; // We do not want to propagate error to next layer
346 desc.rawBuffer.erase(desc.rawBuffer.begin(), desc.rawBuffer.begin()+result);
348 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
350 if (desc.rawBuffer.empty())
351 FD_CLR(sock, &m_writeSet);
353 GenericSocketService::WriteEvent event;
354 event.connectionID.sock = sock;
355 event.connectionID.counter = desc.counter;
357 event.left = desc.rawBuffer.size();
359 desc.service->Event(event);
362 void SocketManager::ReadyForWrite(int sock) {
363 ReadyForWriteBuffer(sock);
366 void SocketManager::MainLoop() {
367 // remove evironment values passed by systemd
368 // uncomment it after removing old security-server code
371 // Daemon is ready to work.
372 sd_notify(0, "READY=1");
376 fd_set readSet = m_readSet;
377 fd_set writeSet = m_writeSet;
379 timeval localTempTimeout;
380 timeval *ptrTimeout = &localTempTimeout;
382 // I need to extract timeout from priority_queue.
383 // Timeout in priority_queue may be deprecated.
384 // I need to find some actual one.
385 while(!m_timeoutQueue.empty()) {
386 auto &top = m_timeoutQueue.top();
387 auto &desc = m_socketDescriptionVector[top.sock];
389 if (top.time == desc.timeout) {
390 // This timeout matches timeout from socket.
394 // This socket was used after timeout in priority queue was set up.
395 // We need to update timeout and find some useable one.
396 Timeout tm = { desc.timeout , top.sock};
397 m_timeoutQueue.pop();
398 m_timeoutQueue.push(tm);
402 if (m_timeoutQueue.empty()) {
403 LogDebug("No usaable timeout found.");
404 ptrTimeout = NULL; // select will wait without timeout
406 time_t currentTime = time(NULL);
407 auto &pqTimeout = m_timeoutQueue.top();
409 // 0 means that select won't block and socket will be closed ;-)
411 currentTime < pqTimeout.time ? pqTimeout.time - currentTime : 0;
412 ptrTimeout->tv_usec = 0;
413 // LogDebug("Set up timeout: " << (int)ptrTimeout->tv_sec
414 // << " seconds. Socket: " << pqTimeout.sock);
417 int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout);
419 if (0 == ret) { // timeout
420 Assert(!m_timeoutQueue.empty());
422 Timeout pqTimeout = m_timeoutQueue.top();
423 m_timeoutQueue.pop();
425 auto &desc = m_socketDescriptionVector[pqTimeout.sock];
427 if (!desc.isTimeout || !desc.isOpen) {
428 // Connection was closed. Timeout is useless...
429 desc.isTimeout = false;
433 if (pqTimeout.time < desc.timeout) {
435 // This socket was used after timeout. We need to update timeout.
436 pqTimeout.time = desc.timeout;
437 m_timeoutQueue.push(pqTimeout);
441 // timeout from m_timeoutQueue matches with socket.timeout
442 // and connection is open. Time to close it!
443 // Putting new timeout in queue here is pointless.
444 desc.isTimeout = false;
445 CloseSocket(pqTimeout.sock);
447 // All done. Now we should process next select ;-)
454 LogDebug("EINTR in select");
458 LogError("Error in select: " << GetErrnoString(err));
463 for(int i = 0; i<m_maxDesc+1 && ret; ++i) {
464 if (FD_ISSET(i, &readSet)) {
468 if (FD_ISSET(i, &writeSet)) {
477 void SocketManager::MainLoopStop()
483 int SocketManager::GetSocketFromSystemD(
484 const GenericSocketService::ServiceDescription &desc)
488 // TODO optimalization - do it once in object constructor
489 // and remember all information path->sockfd
490 int n = sd_listen_fds(0);
492 LogInfo("sd_listen_fds returns: " << n);
495 LogError("Error in sd_listend_fds");
496 ThrowMsg(Exception::InitFailed, "Error in sd_listend_fds");
499 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd) {
500 if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1, desc.serviceHandlerPath.c_str(), 0)) {
501 LogInfo("Useable socket " << desc.serviceHandlerPath <<
502 " was passed by SystemD under descriptor " << fd);
504 int ret = vsm_declare_link(m_vsmCtx, desc.serviceHandlerPath.c_str(), desc.serviceHandlerPath.c_str());
506 LogError("Failed to socket declare link: " << desc.serviceHandlerPath.c_str());
512 ThrowMsg(Exception::GetSystemdSocketFailed, "No useable sockets were passed by systemd.");
515 void SocketManager::CreateDomainSocket(
516 GenericSocketService *service,
517 const GenericSocketService::ServiceDescription &desc)
519 int sockfd = GetSocketFromSystemD(desc);
521 auto &description = CreateDefaultReadSocketDescription(sockfd, false);
523 description.isListen = true;
524 description.interfaceID = desc.interfaceID;
525 description.service = service;
527 LogDebug("Listen on socket: " << sockfd <<
528 " Handler: " << desc.serviceHandlerPath.c_str());
531 void SocketManager::RegisterSocketService(
532 GenericSocketService *service)
534 service->SetSocketManager(this);
535 auto serviceVector = service->GetServiceDescription();
537 for (auto iter = serviceVector.begin(); iter != serviceVector.end(); ++iter)
538 CreateDomainSocket(service, *iter);
539 } Catch (Exception::Base) {
540 for (int i =0; i < (int)m_socketDescriptionVector.size(); ++i)
542 auto &desc = m_socketDescriptionVector[i];
543 if (desc.service == service && desc.isOpen) {
548 ReThrow(Exception::Base);
552 void SocketManager::Close(ConnectionID connectionID) {
554 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
555 m_closeQueue.push(connectionID);
560 void SocketManager::Write(ConnectionID connectionID, const RawBuffer &rawBuffer) {
562 buffer.connectionID = connectionID;
563 buffer.rawBuffer = rawBuffer;
565 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
566 m_writeBufferQueue.push(buffer);
571 void SocketManager::NotifyMe() {
572 TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1));
575 void SocketManager::ProcessQueue() {
578 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
579 while (!m_writeBufferQueue.empty()) {
580 buffer = m_writeBufferQueue.front();
581 m_writeBufferQueue.pop();
583 auto &desc = m_socketDescriptionVector[buffer.connectionID.sock];
586 LogDebug("Received packet for write but connection is closed. Packet ignored!");
590 if (desc.counter != buffer.connectionID.counter)
592 LogDebug("Received packet for write but counter is broken. Packet ignored!");
597 buffer.rawBuffer.begin(),
598 buffer.rawBuffer.end(),
599 std::back_inserter(desc.rawBuffer));
601 FD_SET(buffer.connectionID.sock, &m_writeSet);
607 ConnectionID connection;
609 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
610 if (m_closeQueue.empty())
612 connection = m_closeQueue.front();
616 if (!m_socketDescriptionVector[connection.sock].isOpen)
619 if (connection.counter != m_socketDescriptionVector[connection.sock].counter)
622 CloseSocket(connection.sock);
626 void SocketManager::CloseSocket(int sock) {
627 // LogInfo("Closing socket: " << sock);
628 auto &desc = m_socketDescriptionVector[sock];
630 if (!(desc.isOpen)) {
631 // This may happend when some information was waiting for write to the
632 // socket and in the same time socket was closed by the client.
633 LogError("Socket " << sock << " is not open. Nothing to do!");
637 GenericSocketService::CloseEvent event;
638 event.connectionID.sock = sock;
639 event.connectionID.counter = desc.counter;
640 auto service = desc.service;
644 desc.interfaceID = -1;
645 desc.rawBuffer.clear();
648 service->Event(event);
650 LogError("Critical! Service is NULL! This should never happend!");
652 TEMP_FAILURE_RETRY(close(sock));
653 FD_CLR(sock, &m_readSet);
654 FD_CLR(sock, &m_writeSet);