From e4873b4d63d0bcd4914a1cee82599a13cfd77e47 Mon Sep 17 00:00:00 2001 From: Alexander Barton Date: Fri, 5 Apr 2024 22:38:22 +0200 Subject: [PATCH] Add support for the "sd_notify" protocol 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 | 1 + contrib/ngircd.service | 4 +- src/ngircd/conn.c | 9 +++- src/ngircd/sighandlers.c | 100 +++++++++++++++++++++++++++++++++++++-- src/ngircd/sighandlers.h | 3 ++ 5 files changed, 110 insertions(+), 7 deletions(-) diff --git a/configure.ng b/configure.ng index ec7b6c35..0dccfbc5 100644 --- a/configure.ng +++ b/configure.ng @@ -193,6 +193,7 @@ AC_CHECK_HEADERS_ONCE([ \ stddef.h \ stdint.h \ sys/resource.h \ + sys/un.h \ varargs.h \ ]) diff --git a/contrib/ngircd.service b/contrib/ngircd.service index fb3cf8a1..215f5052 100644 --- a/contrib/ngircd.service +++ b/contrib/ngircd.service @@ -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 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 10042943..61f296ab 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -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 */ /** diff --git a/src/ngircd/sighandlers.c b/src/ngircd/sighandlers.c index 4ed1a125..56fd8aea 100644 --- a/src/ngircd/sighandlers.c +++ b/src/ngircd/sighandlers.c @@ -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 @@ -26,6 +26,11 @@ #include #include +#ifdef HAVE_SYS_UN_H +# include +# include +#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 +} diff --git a/src/ngircd/sighandlers.h b/src/ngircd/sighandlers.h index 68491d94..e03864a3 100644 --- a/src/ngircd/sighandlers.h +++ b/src/ngircd/sighandlers.h @@ -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- */ -- 2.39.2