]> arthur.barton.de Git - ngircd.git/commitdiff
Add support for the "sd_notify" protocol
authorAlexander Barton <alex@barton.de>
Fri, 5 Apr 2024 20:38:22 +0000 (22:38 +0200)
committerAlexander Barton <alex@barton.de>
Fri, 5 Apr 2024 22:12:58 +0000 (00:12 +0200)
This allows the "ngircd.service" systemd(8) unit to use the "notify"
service type, which allows for better status tracking by the service
manager.

configure.ng
contrib/ngircd.service
src/ngircd/conn.c
src/ngircd/sighandlers.c
src/ngircd/sighandlers.h

index ec7b6c356032bf321059fc65d198fb79d0b0675c..0dccfbc5d466ad0f908909ab4b9a4c2ee7cb8ce7 100644 (file)
@@ -193,6 +193,7 @@ AC_CHECK_HEADERS_ONCE([ \
        stddef.h \
        stdint.h \
        sys/resource.h \
+       sys/un.h \
        varargs.h \
 ])
 
index fb3cf8a1935681a997d7438b21cf7bd0419f2263..215f5052714806693d37fec4e32aefdcd70e7df1 100644 (file)
@@ -11,7 +11,7 @@ Before=anope.service atheme.service irc-services.service
 Before=bopm.service hopm.service
 
 [Service]
-Type=forking
+Type=notify
 User=irc
 Group=irc
 # Settings & limits:
@@ -35,7 +35,7 @@ EnvironmentFile=-/etc/default/ngircd
 EnvironmentFile=-/etc/default/ngircd-full
 EnvironmentFile=-/etc/default/ngircd-full-dbg
 # Start ngIRCd. Note: systemd doesn't allow to use $DAEMON here!
-ExecStart=/usr/sbin/ngircd $PARAMS
+ExecStart=/usr/sbin/ngircd --nodaemon --syslog $PARAMS
 ExecReload=/bin/kill -HUP $MAINPID
 Restart=on-failure
 
index 100429435eeb6dcae4ed59c76db558a322e43262..61f296ab5d1e6c4359a302f744f9cbae88ce8568 100644 (file)
@@ -66,6 +66,7 @@
 #include "ng_ipaddr.h"
 #include "parse.h"
 #include "resolve.h"
+#include "sighandlers.h"
 
 #define SERVER_WAIT (NONE - 1)         /** "Wait for outgoing connection" flag */
 
@@ -673,6 +674,7 @@ Conn_Handler(void)
 
        Log(LOG_NOTICE, "Server \"%s\" (on \"%s\") ready.",
            Client_ID(Client_ThisServer()), Client_Hostname(Client_ThisServer()));
+       Signal_NotifySvcMgr("READY=1\n");
 
        while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) {
                t = time(NULL);
@@ -791,10 +793,13 @@ Conn_Handler(void)
                }
        }
 
-       if (NGIRCd_SignalQuit)
+       if (NGIRCd_SignalQuit) {
                Log(LOG_NOTICE | LOG_snotice, "Server going down NOW!");
-       else if (NGIRCd_SignalRestart)
+               Signal_NotifySvcMgr("STOPPING=1\n");
+       } else if (NGIRCd_SignalRestart) {
                Log(LOG_NOTICE | LOG_snotice, "Server restarting NOW!");
+               Signal_NotifySvcMgr("RELOADING=1\n");
+       }
 } /* Conn_Handler */
 
 /**
index 4ed1a1255f4498b3820856dd8736d2a86cf0d33c..56fd8aea2382a6d588220eb3a7ba1a241384d989 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <sys/wait.h>
 #include <time.h>
 
+#ifdef HAVE_SYS_UN_H
+# include <sys/socket.h>
+# include <sys/un.h>
+#endif
+
 #include "conn.h"
 #include "channel.h"
 #include "conf.h"
@@ -100,14 +105,17 @@ Rehash(void)
        unsigned old_nicklen;
 
        Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
+       Signal_NotifySvcMgr("RELOADING=1\n");
 
        /* Remember old server name and nickname length */
        strlcpy( old_name, Conf_ServerName, sizeof old_name );
        old_nicklen = Conf_MaxNickLength;
 
        /* Re-read configuration ... */
-       if (!Conf_Rehash( ))
+       if (!Conf_Rehash()) {
+               Signal_NotifySvcMgr("READY=1\n");
                return;
+       }
 
        /* Close down all listening sockets */
        Conn_ExitListeners( );
@@ -139,6 +147,7 @@ Rehash(void)
        Conn_SyncServerStruct( );
 
        Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
+       Signal_NotifySvcMgr("READY=1\n");
 } /* Rehash */
 
 /**
@@ -339,4 +348,89 @@ Signals_Exit(void)
        signalpipe[0] = signalpipe[1] = 0;
 }
 
-/* -eof- */
+/**
+ * Notify the service manager using the "sd_notify" protocol.
+ *
+ * This function is based on the example notify() function shown in the
+ * sd_notify(3) manual page, with one significant difference: we keep the file
+ * descriptor open to reduce overhead when called multiple times.
+ *
+ * @param message: The message to pass to the service manager including "\n".
+ */
+GLOBAL void
+#if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
+Signal_NotifySvcMgr(UNUSED const char *message)
+{
+       return;
+#else
+Signal_NotifySvcMgr(const char *message)
+{
+       struct sockaddr_un socket_addr;
+       const char *socket_path;
+       size_t path_length, message_length;
+       static int fd = NONE;
+
+       assert(message != NULL);
+       assert(message[0] != '\0');
+
+       if (fd == NONE) {
+               /* No socket to the service manager open: Check if a path name
+                * is given in the environment and try to open it! */
+               socket_path = getenv("NOTIFY_SOCKET");
+               if (!socket_path)
+                       return; /* No socket specified, nothing to do. */
+
+               /* Only AF_UNIX is supported, with path or abstract sockets */
+               if (socket_path[0] != '/' && socket_path[0] != '@') {
+                       Log(LOG_CRIT,
+                       "Failed to notify service manager: Unsupported socket path!");
+                       return;
+               }
+
+               path_length = strlen(socket_path);
+
+               /* Ensure there is room for NUL byte */
+               if (path_length >= sizeof(socket_addr.sun_path)) {
+                       Log(LOG_CRIT,
+                       "Failed to notify service manager: Socket path too long!");
+                       return;
+               }
+
+               memset(&socket_addr, 0, sizeof(struct sockaddr_un));
+               socket_addr.sun_family = AF_UNIX;
+               memcpy(socket_addr.sun_path, socket_path, path_length);
+
+               /* Support for abstract socket */
+               if (socket_addr.sun_path[0] == '@')
+                       socket_addr.sun_path[0] = 0;
+
+               fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+               if (fd < 0) {
+                       Log(LOG_CRIT,
+                           "Failed to notify service manager: %s [socket()]",
+                           strerror(errno));
+                       return;
+               }
+
+               if (connect(fd, (struct sockaddr *)&socket_addr,
+                           sizeof(struct sockaddr_un)) != 0) {
+                       Log(LOG_CRIT,
+                           "Failed to notify service manager: %s [connect()]",
+                           strerror(errno));
+                       close(fd);
+                       fd = NONE;
+                       return;
+               }
+       }
+
+       message_length = strlen(message);
+       ssize_t written = write(fd, message, message_length);
+       if (written != (ssize_t)message_length) {
+               Log(LOG_CRIT,
+                       "Failed to notify service manager: %s [write()]",
+                       strerror(errno));
+               close(fd);
+               fd = NONE;
+       }
+#endif
+}
index 68491d949365827f4f8a66b7382e9dc2e10c3524..e03864a3d26bd9160f4cf5667c6282bb258c8f08 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +22,8 @@
 bool Signals_Init PARAMS((void));
 void Signals_Exit PARAMS((void));
 
+GLOBAL void Signal_NotifySvcMgr PARAMS((const char *message));
+
 #endif
 
 /* -eof- */