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>
32 #include <sys/smack.h>
41 #include <systemd/sd-daemon.h>
43 #include <dpl/errno_string.h>
44 #include <dpl/log/log.h>
45 #include <dpl/assert.h>
47 #include <smack-check.h>
48 #include <socket-manager.h>
52 const time_t SOCKET_TIMEOUT = 1000;
54 int getCredentialsFromSocket(int sock, CKM::Credentials &cred) {
55 std::vector<char> result(1);
59 if ((0 > getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length))
62 LogError("getsockopt failed");
66 result.resize(length);
68 if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length)) {
69 LogError("getsockopt failed");
73 length = sizeof(ucred);
75 if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peerCred, &length)) {
76 LogError("getsockopt failed");
80 result.push_back('\0');
81 cred = CKM::Credentials(peerCred.uid, result.data());
85 } // namespace anonymous
89 struct DummyService : public GenericSocketService {
90 ServiceDescriptionVector GetServiceDescription() {
91 return ServiceDescriptionVector();
97 void Event(const AcceptEvent &) {}
98 void Event(const WriteEvent &) {}
99 void Event(const ReadEvent &) {}
100 void Event(const CloseEvent &) {}
103 struct SignalService : public GenericSocketService {
104 int GetDescriptor() {
108 sigaddset(&mask, SIGTERM);
109 if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL))
111 return signalfd(-1, &mask, 0);
114 ServiceDescriptionVector GetServiceDescription() {
115 return ServiceDescriptionVector();
121 void Event(const AcceptEvent &) {} // not supported
122 void Event(const WriteEvent &) {} // not supported
123 void Event(const CloseEvent &) {} // not supported
125 void Event(const ReadEvent &event) {
126 LogDebug("Get signal information");
128 if(sizeof(struct signalfd_siginfo) != event.rawBuffer.size()) {
129 LogError("Wrong size of signalfd_siginfo struct. Expected: "
130 << sizeof(signalfd_siginfo) << " Get: "
131 << event.rawBuffer.size());
135 signalfd_siginfo *siginfo = (signalfd_siginfo*)(&(event.rawBuffer[0]));
137 if (siginfo->ssi_signo == SIGTERM) {
138 LogInfo("Got signal: SIGTERM");
139 static_cast<SocketManager*>(m_serviceManager)->MainLoopStop();
143 LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo);
147 SocketManager::SocketDescription&
148 SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout)
150 if ((int)m_socketDescriptionVector.size() <= sock)
151 m_socketDescriptionVector.resize(sock+20);
153 auto &desc = m_socketDescriptionVector[sock];
154 desc.isListen = false;
156 desc.interfaceID = 0;
158 desc.counter = ++m_counter;
161 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
162 if (false == desc.isTimeout) {
164 tm.time = desc.timeout;
166 m_timeoutQueue.push(tm);
170 desc.isTimeout = timeout;
172 FD_SET(sock, &m_readSet);
173 m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc;
177 SocketManager::SocketManager()
182 FD_ZERO(&m_writeSet);
183 if (-1 == pipe(m_notifyMe)) {
185 ThrowMsg(Exception::InitFailed, "Error in pipe: " << GetErrnoString(err));
187 LogInfo("Pipe: Read desc: " << m_notifyMe[0] << " Write desc: " << m_notifyMe[1]);
189 auto &desc = CreateDefaultReadSocketDescription(m_notifyMe[0], false);
190 desc.service = new DummyService;
192 // std::thread bases on pthread so this should work fine
195 sigaddset(&set, SIGPIPE);
196 pthread_sigmask(SIG_BLOCK, &set, NULL);
198 // add support for TERM signal (passed from systemd)
199 auto *signalService = new SignalService;
200 signalService->SetSocketManager(this);
201 int filefd = signalService->GetDescriptor();
203 LogError("Error in SignalService.GetDescriptor()");
204 delete signalService;
206 auto &desc2 = CreateDefaultReadSocketDescription(filefd, false);
207 desc2.service = signalService;
208 LogInfo("SignalService mounted on " << filefd << " descriptor");
212 SocketManager::~SocketManager() {
213 std::set<GenericSocketService*> serviceMap;
215 // Find all services. Set is used to remove duplicates.
216 // In this implementation, services are not able to react in any way.
217 for (size_t i=0; i < m_socketDescriptionVector.size(); ++i)
218 if (m_socketDescriptionVector[i].isOpen)
219 serviceMap.insert(m_socketDescriptionVector[i].service);
221 // Time to destroy all services.
222 for (auto service : serviceMap) {
223 LogDebug("delete " << (void*)(service));
228 for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i)
229 if (m_socketDescriptionVector[i].isOpen)
232 // All socket except one were closed. Now pipe input must be closed.
233 close(m_notifyMe[1]);
236 void SocketManager::ReadyForAccept(int sock) {
237 struct sockaddr_un clientAddr;
238 unsigned int clientLen = sizeof(clientAddr);
239 int client = accept4(sock, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
240 // LogInfo("Accept on sock: " << sock << " Socket opended: " << client);
243 LogDebug("Error in accept: " << GetErrnoString(err));
247 Credentials peerCred;
248 if (0 > getCredentialsFromSocket(client, peerCred)) {
249 LogDebug("Error in getCredentialsFromSocket. Socket closed.");
250 TEMP_FAILURE_RETRY(close(client));
254 auto &desc = CreateDefaultReadSocketDescription(client, true);
255 desc.interfaceID = m_socketDescriptionVector[sock].interfaceID;
256 desc.service = m_socketDescriptionVector[sock].service;
258 GenericSocketService::AcceptEvent event;
259 event.connectionID.sock = client;
260 event.connectionID.counter = desc.counter;
261 event.interfaceID = desc.interfaceID;
262 event.credentials = peerCred;
263 desc.service->Event(event);
266 void SocketManager::ReadyForRead(int sock) {
267 if (m_socketDescriptionVector[sock].isListen) {
268 ReadyForAccept(sock);
272 GenericSocketService::ReadEvent event;
273 event.connectionID.sock = sock;
274 event.connectionID.counter = m_socketDescriptionVector[sock].counter;
275 event.rawBuffer.resize(4096);
277 auto &desc = m_socketDescriptionVector[sock];
278 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
280 ssize_t size = read(sock, &event.rawBuffer[0], 4096);
284 } else if (size >= 0) {
285 event.rawBuffer.resize(size);
286 desc.service->Event(event);
287 } else if (size == -1) {
294 LogDebug("Reading sock error: " << GetErrnoString(err));
300 void SocketManager::ReadyForWriteBuffer(int sock) {
301 auto &desc = m_socketDescriptionVector[sock];
302 size_t size = desc.rawBuffer.size();
303 ssize_t result = write(sock, &desc.rawBuffer[0], size);
309 // select will trigger write once again, nothing to do
313 LogDebug("Error during write: " << GetErrnoString(err));
317 return; // We do not want to propagate error to next layer
320 desc.rawBuffer.erase(desc.rawBuffer.begin(), desc.rawBuffer.begin()+result);
322 desc.timeout = time(NULL) + SOCKET_TIMEOUT;
324 if (desc.rawBuffer.empty())
325 FD_CLR(sock, &m_writeSet);
327 GenericSocketService::WriteEvent event;
328 event.connectionID.sock = sock;
329 event.connectionID.counter = desc.counter;
331 event.left = desc.rawBuffer.size();
333 desc.service->Event(event);
336 void SocketManager::ReadyForWrite(int sock) {
337 ReadyForWriteBuffer(sock);
340 void SocketManager::MainLoop() {
341 // remove evironment values passed by systemd
342 // uncomment it after removing old security-server code
345 // Daemon is ready to work.
346 sd_notify(0, "READY=1");
350 fd_set readSet = m_readSet;
351 fd_set writeSet = m_writeSet;
353 timeval localTempTimeout;
354 timeval *ptrTimeout = &localTempTimeout;
356 // I need to extract timeout from priority_queue.
357 // Timeout in priority_queue may be deprecated.
358 // I need to find some actual one.
359 while(!m_timeoutQueue.empty()) {
360 auto &top = m_timeoutQueue.top();
361 auto &desc = m_socketDescriptionVector[top.sock];
363 if (top.time == desc.timeout) {
364 // This timeout matches timeout from socket.
368 // This socket was used after timeout in priority queue was set up.
369 // We need to update timeout and find some useable one.
370 Timeout tm = { desc.timeout , top.sock};
371 m_timeoutQueue.pop();
372 m_timeoutQueue.push(tm);
376 if (m_timeoutQueue.empty()) {
377 LogDebug("No usaable timeout found.");
378 ptrTimeout = NULL; // select will wait without timeout
380 time_t currentTime = time(NULL);
381 auto &pqTimeout = m_timeoutQueue.top();
383 // 0 means that select won't block and socket will be closed ;-)
385 currentTime < pqTimeout.time ? pqTimeout.time - currentTime : 0;
386 ptrTimeout->tv_usec = 0;
387 // LogDebug("Set up timeout: " << (int)ptrTimeout->tv_sec
388 // << " seconds. Socket: " << pqTimeout.sock);
391 int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout);
393 if (0 == ret) { // timeout
394 Assert(!m_timeoutQueue.empty());
396 Timeout pqTimeout = m_timeoutQueue.top();
397 m_timeoutQueue.pop();
399 auto &desc = m_socketDescriptionVector[pqTimeout.sock];
401 if (!desc.isTimeout || !desc.isOpen) {
402 // Connection was closed. Timeout is useless...
403 desc.isTimeout = false;
407 if (pqTimeout.time < desc.timeout) {
409 // This socket was used after timeout. We need to update timeout.
410 pqTimeout.time = desc.timeout;
411 m_timeoutQueue.push(pqTimeout);
415 // timeout from m_timeoutQueue matches with socket.timeout
416 // and connection is open. Time to close it!
417 // Putting new timeout in queue here is pointless.
418 desc.isTimeout = false;
419 CloseSocket(pqTimeout.sock);
421 // All done. Now we should process next select ;-)
428 LogDebug("EINTR in select");
432 LogError("Error in select: " << GetErrnoString(err));
437 for(int i = 0; i<m_maxDesc+1 && ret; ++i) {
438 if (FD_ISSET(i, &readSet)) {
442 if (FD_ISSET(i, &writeSet)) {
451 void SocketManager::MainLoopStop()
457 int SocketManager::GetSocketFromSystemD(
458 const GenericSocketService::ServiceDescription &desc)
462 // TODO optimalization - do it once in object constructor
463 // and remember all information path->sockfd
464 int n = sd_listen_fds(0);
466 LogInfo("sd_listen_fds returns: " << n);
469 LogError("Error in sd_listend_fds");
470 ThrowMsg(Exception::InitFailed, "Error in sd_listend_fds");
473 for(fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd) {
474 if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1,
475 desc.serviceHandlerPath.c_str(), 0))
477 LogInfo("Useable socket " << desc.serviceHandlerPath <<
478 " was passed by SystemD under descriptor " << fd);
482 LogError("No useable sockets were passed by systemd.");
486 int SocketManager::CreateDomainSocketHelp(
487 const GenericSocketService::ServiceDescription &desc)
491 if(desc.serviceHandlerPath.size()*sizeof(decltype(desc.serviceHandlerPath)::value_type) >=
492 sizeof(static_cast<sockaddr_un*>(0)->sun_path))
494 LogError("Service handler path too long: " << desc.serviceHandlerPath.size());
495 ThrowMsg(Exception::InitFailed,
496 "Service handler path too long: " << desc.serviceHandlerPath.size());
499 if (-1 == (sockfd = socket(AF_UNIX, SOCK_STREAM, 0))) {
501 LogError("Error in socket: " << GetErrnoString(err));
502 ThrowMsg(Exception::InitFailed, "Error in socket: " << GetErrnoString(err));
506 LogInfo("Set up smack label: " << desc.smackLabel);
508 if (0 != smack_fsetlabel(sockfd, desc.smackLabel.c_str(), SMACK_LABEL_IPIN)) {
509 LogError("Error in smack_fsetlabel");
510 ThrowMsg(Exception::InitFailed, "Error in smack_fsetlabel");
513 LogInfo("No smack on platform. Socket won't be securied with smack label!");
517 if (-1 == (flags = fcntl(sockfd, F_GETFL, 0)))
520 if (-1 == fcntl(sockfd, F_SETFL, flags | O_NONBLOCK)) {
523 LogError("Error in fcntl: " << GetErrnoString(err));
524 ThrowMsg(Exception::InitFailed, "Error in fcntl: " << GetErrnoString(err));
527 sockaddr_un serverAddress;
528 memset(&serverAddress, 0, sizeof(serverAddress));
529 serverAddress.sun_family = AF_UNIX;
530 strcpy(serverAddress.sun_path, desc.serviceHandlerPath.c_str());
531 unlink(serverAddress.sun_path);
533 mode_t originalUmask;
534 originalUmask = umask(0);
536 if (-1 == bind(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress))) {
539 LogError("Error in bind: " << GetErrnoString(err));
540 ThrowMsg(Exception::InitFailed, "Error in bind: " << GetErrnoString(err));
543 umask(originalUmask);
545 if (-1 == listen(sockfd, 5)) {
548 LogError("Error in listen: " << GetErrnoString(err));
549 ThrowMsg(Exception::InitFailed, "Error in listen: " << GetErrnoString(err));
555 void SocketManager::CreateDomainSocket(
556 GenericSocketService *service,
557 const GenericSocketService::ServiceDescription &desc)
559 int sockfd = GetSocketFromSystemD(desc);
561 sockfd = CreateDomainSocketHelp(desc);
563 auto &description = CreateDefaultReadSocketDescription(sockfd, false);
565 description.isListen = true;
566 description.interfaceID = desc.interfaceID;
567 description.service = service;
569 LogDebug("Listen on socket: " << sockfd <<
570 " Handler: " << desc.serviceHandlerPath.c_str());
573 void SocketManager::RegisterSocketService(GenericSocketService *service) {
574 service->SetSocketManager(this);
575 service->SetCommManager(&m_commMgr);
576 auto serviceVector = service->GetServiceDescription();
578 for (auto iter = serviceVector.begin(); iter != serviceVector.end(); ++iter)
579 CreateDomainSocket(service, *iter);
580 } Catch (Exception::Base) {
581 for (int i =0; i < (int)m_socketDescriptionVector.size(); ++i)
583 auto &desc = m_socketDescriptionVector[i];
584 if (desc.service == service && desc.isOpen) {
589 ReThrow(Exception::Base);
593 void SocketManager::Close(ConnectionID connectionID) {
595 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
596 m_closeQueue.push(connectionID);
601 void SocketManager::Write(ConnectionID connectionID, const RawBuffer &rawBuffer) {
603 buffer.connectionID = connectionID;
604 buffer.rawBuffer = rawBuffer;
606 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
607 m_writeBufferQueue.push(buffer);
612 void SocketManager::NotifyMe() {
613 TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1));
616 void SocketManager::ProcessQueue() {
619 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
620 while (!m_writeBufferQueue.empty()) {
621 buffer = m_writeBufferQueue.front();
622 m_writeBufferQueue.pop();
624 auto &desc = m_socketDescriptionVector[buffer.connectionID.sock];
627 LogDebug("Received packet for write but connection is closed. Packet ignored!");
631 if (desc.counter != buffer.connectionID.counter)
633 LogDebug("Received packet for write but counter is broken. Packet ignored!");
638 buffer.rawBuffer.begin(),
639 buffer.rawBuffer.end(),
640 std::back_inserter(desc.rawBuffer));
642 FD_SET(buffer.connectionID.sock, &m_writeSet);
648 ConnectionID connection;
650 std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
651 if (m_closeQueue.empty())
653 connection = m_closeQueue.front();
657 if (!m_socketDescriptionVector[connection.sock].isOpen)
660 if (connection.counter != m_socketDescriptionVector[connection.sock].counter)
663 CloseSocket(connection.sock);
667 void SocketManager::CloseSocket(int sock) {
668 // LogInfo("Closing socket: " << sock);
669 auto &desc = m_socketDescriptionVector[sock];
671 if (!(desc.isOpen)) {
672 // This may happend when some information was waiting for write to the
673 // socket and in the same time socket was closed by the client.
674 LogError("Socket " << sock << " is not open. Nothing to do!");
678 GenericSocketService::CloseEvent event;
679 event.connectionID.sock = sock;
680 event.connectionID.counter = desc.counter;
681 auto service = desc.service;
685 desc.interfaceID = -1;
686 desc.rawBuffer.clear();
689 service->Event(event);
691 LogError("Critical! Service is NULL! This should never happend!");
693 TEMP_FAILURE_RETRY(close(sock));
694 FD_CLR(sock, &m_readSet);
695 FD_CLR(sock, &m_writeSet);