[RFC PATCH 2/6] Allow socket activation by systemd

Victor Westerhuis victor@westerhu.is
Sun Mar 7 12:49:54 GMT 2021


Signed-off-by: Victor Westerhuis <victor@westerhu.is>
---
 debuginfod/debuginfod.cxx | 161 ++++++++++++++++++++++++++++----------
 1 file changed, 121 insertions(+), 40 deletions(-)

diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 2aecc049..caced48c 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -93,6 +93,10 @@ using namespace std;
 
 #include <microhttpd.h>
 
+#ifdef ENABLE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
 #if MHD_VERSION >= 0x00097002
 // libmicrohttpd 0.9.71 broke API
 #define MHD_RESULT enum MHD_Result
@@ -367,6 +371,10 @@ static const struct argp_option options[] =
    { "fdcache-prefetch", ARGP_KEY_FDCACHE_PREFETCH, "NUM", 0, "Number of archive files to prefetch into fdcache.", 0 },
 #define ARGP_KEY_FDCACHE_MINTMP 0x1004
    { "fdcache-mintmp", ARGP_KEY_FDCACHE_MINTMP, "NUM", 0, "Minimum free space% on tmpdir.", 0 },
+#ifdef ENABLE_SYSTEMD
+#define ARGP_KEY_SYSTEMD 0x1005
+   { "systemd", ARGP_KEY_SYSTEMD, NULL, 0, "Use systemd socket activation and cache directory.", 0 },
+#endif
    { NULL, 0, NULL, 0, NULL, 0 }
   };
 
@@ -412,6 +420,9 @@ static long fdcache_mbs;
 static long fdcache_prefetch;
 static long fdcache_mintmp;
 static string tmpdir;
+#ifdef ENABLE_SYSTEMD
+static bool systemd;
+#endif
 
 static void set_metric(const string& key, double value);
 // static void inc_metric(const string& key);
@@ -541,6 +552,11 @@ parse_opt (int key, char *arg,
     case ARGP_KEY_ARG:
       source_paths.insert(string(arg));
       break;
+#ifdef ENABLE_SYSTEMD
+    case ARGP_KEY_SYSTEMD:
+      systemd = true;
+      break;
+#endif
       // case 'h': argp_state_help (state, stderr, ARGP_HELP_LONG|ARGP_HELP_EXIT_OK);
     default: return ARGP_ERR_UNKNOWN;
     }
@@ -3267,6 +3283,16 @@ static void sqlite3_sharedprefix_fn (sqlite3_context* c, int argc, sqlite3_value
 }
 
 
+static void close_databases ()
+{
+  sqlite3 *database = db;
+  sqlite3 *databaseq = dbq;
+  db = dbq = 0; // for signal_handler not to freak
+  (void) sqlite3_close (databaseq);
+  (void) sqlite3_close (database);
+}
+
+
 int
 main (int argc, char *argv[])
 {
@@ -3372,46 +3398,105 @@ main (int argc, char *argv[])
              "cannot run database schema ddl: %s", sqlite3_errmsg(db));
     }
 
-  // Start httpd server threads.  Separate pool for IPv4 and IPv6, in
-  // case the host only has one protocol stack.
-  MHD_Daemon *d4 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
+  vector<MHD_Daemon *> daemons;
+#ifdef ENABLE_SYSTEMD
+  if (systemd)
+    {
+      int fds = sd_listen_fds (true);
+      if (fds <= 0)
+        {
+          close_databases ();
+          error (EXIT_FAILURE, -fds, "cannot get fds from systemd");
+        }
+
+      for (int i = 0; i < fds; ++i)
+        {
+          int fd = SD_LISTEN_FDS_START + i;
+
+          rc = sd_is_socket_inet (fd, AF_UNSPEC, SOCK_STREAM, true, 0);
+          if (rc < 0)
+            {
+              close_databases ();
+              error (EXIT_FAILURE, -rc, "unable to determine fd type");
+            }
+          else if (rc == 0)
+            {
+              close_databases ();
+              error (EXIT_FAILURE, 0,
+                     "fd %d is not of the correct socket type", fd);
+            }
+
+          MHD_Daemon *d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
 #if MHD_VERSION >= 0x00095300
-                                     | MHD_USE_INTERNAL_POLLING_THREAD
+                                            | MHD_USE_INTERNAL_POLLING_THREAD
 #else
-                                     | MHD_USE_SELECT_INTERNALLY
+                                            | MHD_USE_SELECT_INTERNALLY
 #endif
-                                     | MHD_USE_DEBUG, /* report errors to stderr */
-                                     http_port,
-                                     NULL, NULL, /* default accept policy */
-                                     handler_cb, NULL, /* handler callback */
-                                     MHD_OPTION_END);
-  MHD_Daemon *d6 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
+                                            | MHD_USE_DEBUG /* report errors to stderr */
+                                            | MHD_USE_ITC, /* don't close socket on shutdown */
+                                            0,
+                                            NULL, NULL, /* default accept policy */
+                                            handler_cb, NULL, /* handler callback */
+                                            MHD_OPTION_LISTEN_SOCKET,
+                                            fd,
+                                            MHD_OPTION_END);
+          if (d == NULL)
+            {
+              close_databases ();
+              error (EXIT_FAILURE, 0,
+                    "cannot start http server on fd %d", fd);
+            }
+
+          obatched(clog) << "started http server on fd " << fd << endl;
+
+          daemons.push_back (d);
+        }
+    }
+  else
+#endif
+    {
+      // Start httpd server threads.  Separate pool for IPv4 and IPv6, in
+      // case the host only has one protocol stack.
+      MHD_Daemon *d4 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
 #if MHD_VERSION >= 0x00095300
-                                     | MHD_USE_INTERNAL_POLLING_THREAD
+                                         | MHD_USE_INTERNAL_POLLING_THREAD
 #else
-                                     | MHD_USE_SELECT_INTERNALLY
+                                         | MHD_USE_SELECT_INTERNALLY
 #endif
-                                     | MHD_USE_IPv6
-                                     | MHD_USE_DEBUG, /* report errors to stderr */
-                                     http_port,
-                                     NULL, NULL, /* default accept policy */
-                                     handler_cb, NULL, /* handler callback */
-                                     MHD_OPTION_END);
-
-  if (d4 == NULL && d6 == NULL) // neither ipv4 nor ipv6? boo
-    {
-      sqlite3 *database = db;
-      sqlite3 *databaseq = dbq;
-      db = dbq = 0; // for signal_handler not to freak
-      sqlite3_close (databaseq);
-      sqlite3_close (database);
-      error (EXIT_FAILURE, 0, "cannot start http server at port %d", http_port);
-    }
+                                         | MHD_USE_DEBUG, /* report errors to stderr */
+                                         http_port,
+                                         NULL, NULL, /* default accept policy */
+                                         handler_cb, NULL, /* handler callback */
+                                         MHD_OPTION_END);
+      MHD_Daemon *d6 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
+#if MHD_VERSION >= 0x00095300
+                                         | MHD_USE_INTERNAL_POLLING_THREAD
+#else
+                                         | MHD_USE_SELECT_INTERNALLY
+#endif
+                                         | MHD_USE_IPv6
+                                         | MHD_USE_DEBUG, /* report errors to stderr */
+                                         http_port,
+                                         NULL, NULL, /* default accept policy */
+                                         handler_cb, NULL, /* handler callback */
+                                         MHD_OPTION_END);
+
+      if (d4 == NULL && d6 == NULL) // neither ipv4 nor ipv6? boo
+        {
+          close_databases ();
+          error (EXIT_FAILURE, 0, "cannot start http server at port %d", http_port);
+        }
+
+      obatched(clog) << "started http server on "
+                     << (d4 != NULL ? "IPv4 " : "")
+                     << (d6 != NULL ? "IPv6 " : "")
+                     << "port=" << http_port << endl;
 
-  obatched(clog) << "started http server on "
-                 << (d4 != NULL ? "IPv4 " : "")
-                 << (d6 != NULL ? "IPv6 " : "")
-                 << "port=" << http_port << endl;
+      if (d4)
+        daemons.push_back(d4);
+      if (d6)
+        daemons.push_back(d6);
+    }
 
   // add maxigroom sql if -G given
   if (maxigroom)
@@ -3505,8 +3590,8 @@ main (int argc, char *argv[])
     pthread_join (it, NULL);
 
   /* Stop all the web service threads. */
-  if (d4) MHD_stop_daemon (d4);
-  if (d6) MHD_stop_daemon (d6);
+  for (auto&& i : daemons)
+    MHD_stop_daemon (i);
 
   /* With all threads known dead, we can clean up the global resources. */
   rc = sqlite3_exec (db, DEBUGINFOD_SQLITE_CLEANUP_DDL, NULL, NULL, NULL);
@@ -3520,11 +3605,7 @@ main (int argc, char *argv[])
   (void) regfree (& file_include_regex);
   (void) regfree (& file_exclude_regex);
 
-  sqlite3 *database = db;
-  sqlite3 *databaseq = dbq;
-  db = dbq = 0; // for signal_handler not to freak
-  (void) sqlite3_close (databaseq);
-  (void) sqlite3_close (database);
+  close_databases ();
 
   return 0;
 }
-- 
2.30.1


More information about the Elfutils-devel mailing list