Clean up after SIGTERM.
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Wed, 17 Jul 2013 14:46:34 +0000 (16:46 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Thu, 6 Feb 2014 16:13:21 +0000 (17:13 +0100)
[Issue#]   N/A
[Bug]      N/A
[Cause]    Lack of SIGTERM support.
[Problem]  N/A
[Solution] Add support for SIGTERM signal.

[Verification] Use "systemctl restart security-server.service" command.
               Security server should be killed and restarted.

Change-Id: Ic41957bf3aaee60afb98cae6de841a057f3ad49a

src/server/security-server-main.c
src/server2/main/generic-socket-manager.h
src/server2/main/socket-manager.cpp
src/server2/main/socket-manager.h

index 81797a6..dcbf484 100644 (file)
@@ -1368,14 +1368,21 @@ int main(int argc, char *argv[])
     (void)argc;
     (void)argv;
 
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGTERM);
+    sigaddset(&mask, SIGPIPE);
+    if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL)) {
+        SEC_SVR_ERR("Error in pthread_sigmask");
+    }
+
     if (0 != (res = pthread_create(&main_thread, NULL, security_server_main_thread, NULL))) {
         SEC_SVR_ERR("Error: Server: Cannot create main security server thread: %s", strerror(res));
         return -1;
     }
 
     server2();
-
-    pthread_exit(NULL);
+    exit(0);
     return 0;
 }
 
index f9d11f4..a0244b4 100644 (file)
@@ -93,6 +93,8 @@ struct GenericSocketService {
     virtual void Event(const ReadEvent &event) = 0;
     virtual void Event(const CloseEvent &event) = 0;
     virtual void Event(const ErrorEvent &event) = 0;
+
+    GenericSocketService() : m_serviceManager(NULL) {}
     virtual ~GenericSocketService(){}
 protected:
     GenericSocketManager *m_serviceManager;
index 1f6c0d1..481f7ae 100644 (file)
  * @brief       Implementation of SocketManager.
  */
 
+#include <set>
+
+#include <signal.h>
 #include <sys/select.h>
+#include <sys/signalfd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/smack.h>
@@ -61,6 +65,48 @@ struct DummyService : public GenericSocketService {
     void Event(const ErrorEvent &event) { (void)event; }
 };
 
+struct SignalService : public GenericSocketService {
+    int GetDescriptor() {
+        LogInfo("set up");
+        sigset_t mask;
+        sigemptyset(&mask);
+        sigaddset(&mask, SIGTERM);
+        if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL))
+            return -1;
+        return signalfd(-1, &mask, 0);
+    }
+
+    ServiceDescriptionVector GetServiceDescription() {
+        return ServiceDescriptionVector();
+    }
+
+    void Event(const AcceptEvent &event) { (void)event; } // not supported
+    void Event(const WriteEvent &event) { (void)event; }  // not supported
+    void Event(const CloseEvent &event) { (void)event; }  // not supported
+    void Event(const ErrorEvent &event) { (void)event; }  // not supported
+
+    void Event(const ReadEvent &event) {
+        LogDebug("Get signal information");
+
+        if(sizeof(struct signalfd_siginfo) != event.rawBuffer.size()) {
+            LogError("Wrong size of signalfd_siginfo struct. Expected: "
+                << sizeof(signalfd_siginfo) << " Get: "
+                << event.rawBuffer.size());
+            return;
+        }
+
+        signalfd_siginfo *siginfo = (signalfd_siginfo*)(&(event.rawBuffer[0]));
+
+        if (siginfo->ssi_signo == SIGTERM) {
+            LogInfo("Got signal: SIGTERM");
+            static_cast<SocketManager*>(m_serviceManager)->MainLoopStop();
+            return;
+        }
+
+        LogInfo("This should not happend. Got signal: " << siginfo->ssi_signo);
+    }
+};
+
 SocketManager::SocketDescription&
 SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout)
 {
@@ -110,10 +156,41 @@ SocketManager::SocketManager()
     sigemptyset(&set);
     sigaddset(&set, SIGPIPE);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    // add support for TERM signal (passed from systemd)
+    auto *signalService = new SignalService;
+    int filefd = signalService->GetDescriptor();
+    if (-1 == filefd) {
+        LogError("Error in SignalService.GetDescriptor()");
+        delete signalService;
+    } else {
+        auto &desc2 = CreateDefaultReadSocketDescription(filefd, false);
+        desc2.service = signalService;
+        LogInfo("SignalService mounted on " << filefd << " descriptor");
+    }
 }
 
 SocketManager::~SocketManager() {
-    // TODO clean up all services!
+    std::set<GenericSocketService*> serviceMap;
+
+    // Find all services. Set is used to remove duplicates.
+    // In this implementation, services are not able to react in any way.
+    for (size_t i=0; i < m_socketDescriptionVector.size(); ++i)
+        if (m_socketDescriptionVector[i].isOpen)
+            serviceMap.insert(m_socketDescriptionVector[i].service);
+
+    // Time to destroy all services.
+    for(auto it = serviceMap.begin(); it != serviceMap.end(); ++it) {
+        LogDebug("delete " << (void*)(*it));
+        delete *it;
+    }
+
+    for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i)
+        if (m_socketDescriptionVector[i].isOpen)
+            close(i);
+
+    // All socket except one were closed. Now pipe input must be closed.
+    close(m_notifyMe[1]);
 }
 
 void SocketManager::ReadyForAccept(int sock) {
@@ -320,6 +397,12 @@ void SocketManager::MainLoop() {
     }
 }
 
+void SocketManager::MainLoopStop()
+{
+    m_working = false;
+    NotifyMe();
+}
+
 int SocketManager::GetSocketFromSystemD(
     const GenericSocketService::ServiceDescription &desc)
 {
@@ -341,7 +424,7 @@ int SocketManager::GetSocketFromSystemD(
                                   desc.serviceHandlerPath.c_str(), 0))
         {
             LogInfo("Useable socket " << desc.serviceHandlerPath <<
-                " was passed by SystemD");
+                " was passed by SystemD under descriptor " << fd);
             return fd;
         }
     }
index 12203fe..0983a3f 100644 (file)
@@ -48,6 +48,7 @@ public:
     SocketManager();
     virtual ~SocketManager();
     virtual void MainLoop();
+    virtual void MainLoopStop();
 
     virtual void RegisterSocketService(GenericSocketService *service);
     virtual void Close(ConnectionID connectionID);