Commit Diff


commit - 84e24afd2f6607a2345c4df2b2f9ad81e9dd4bbc
commit + 8ab097afb743061c6c9b865bdb401ba51285c347
blob - 09b43a68a8bb71ef5ba2fb3dd02f9cee1f04bf14
blob + 6d16f7cac50f8b177fb4d336201906733b0a3607
--- contrib/Makefile.am
+++ contrib/Makefile.am
@@ -1,6 +1,6 @@
 #
 # ngIRCd -- The Next Generation IRC Daemon
-# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors
+# Copyright (c)2001-2013 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
@@ -17,6 +17,7 @@ EXTRA_DIST = README \
 	ngIRCd-Logo.gif \
 	ngircd-redhat.init \
 	ngircd.service \
+	ngircd.socket \
 	ngircd.spec \
 	platformtest.sh \
 	systrace.policy
blob - f3730a4e969c69aed07bbfdfb737a7901b382fa8
blob + 2d639e664076d19c8b20a23e50a4d6426ddd6953
--- contrib/README
+++ contrib/README
@@ -30,6 +30,9 @@ ngircd-redhat.init
 ngircd.service
  - systemd(8) service unit configuration file.
 
+ngircd.socket
+ - systemd(8) socket unit configuration file for "socket activation".
+
 ngircd.spec
  - RPM "spec" file.
 
blob - /dev/null
blob + 3838efcc1c278e315693d307013c4e8b2be41b09 (mode 644)
--- /dev/null
+++ contrib/ngircd.socket
@@ -0,0 +1,10 @@
+[Unit]
+Description=Next Generation IRC Daemon (Socket)
+
+[Socket]
+ListenStream=6667
+#ListenStream=6668
+IPTOS=low-delay
+
+[Install]
+WantedBy=sockets.target
blob - 14d337b9408265b1213a157cd36cf66a8efc057e
blob + 378509f96f09bc35eb9e3ebc2eb12140c24509fb
--- src/ngircd/conn.c
+++ src/ngircd/conn.c
@@ -82,7 +82,9 @@
 #define MAX_COMMANDS_SERVER_MIN 10
 #define MAX_COMMANDS_SERVICE 10
 
+#define SD_LISTEN_FDS_START 3
 
+
 static bool Handle_Write PARAMS(( CONN_ID Idx ));
 static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
 static int New_Connection PARAMS(( int Sock, bool IsSSL ));
@@ -118,6 +120,40 @@ static void cb_clientserver_ssl PARAMS((int sock, shor
 static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what));
 static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
 static void cb_clientserver PARAMS((int sock, short what));
+
+
+/**
+ * Get number of sockets available from systemd(8).
+ *
+ * ngIRCd needs to implement its own sd_listen_fds(3) function and can't
+ * use the one provided by systemd itself, becaus the sockets will be
+ * used in a forked child process with a new PID, and this would trigger
+ * an error in the standard implementation.
+ *
+ * @return Number of sockets available, -1 if sockets have already been
+ *         initialized, or 0 when no sockets have been passed.
+ */
+static int
+my_sd_listen_fds(void)
+{
+	const char *e;
+	long count;
+
+	/* Check if LISTEN_PID exists; but we ignore the result, because
+	 * normally ngircd forks a child before checking this, and therefore
+	 * the PID set in the environment is always wrong ... */
+	e = getenv("LISTEN_PID");
+	if (!e || !*e)
+		return 0;
+
+	e = getenv("LISTEN_FDS");
+	if (!e || !*e)
+		return -1;
+	count = atol(e);
+	unsetenv("LISTEN_FDS");
+
+	return count;
+}
 
 
 /**
@@ -495,9 +531,38 @@ Conn_InitListeners( void )
 	/* Initialize ports on which the server should accept connections */
 	unsigned int created = 0;
 	char *copy, *listen_addr;
+	int count, fd, i;
 
 	assert(Conf_ListenAddress);
+
+	count = my_sd_listen_fds();
+	if (count < 0) {
+		Log(LOG_INFO,
+		    "Not re-initializing listening sockets of systemd(8) ...");
+		return 0;
+	}
+	if (count > 0) {
+		/* systemd(8) passed sockets to us, so don't try to initialize
+		 * listening sockets on our own but use the passed ones */
+		LogDebug("Initializing %d systemd sockets ...", count);
+		for (i = 0; i < count; i++) {
+			fd = SD_LISTEN_FDS_START + i;
+			Init_Socket(fd);
+			if (!io_event_create(fd, IO_WANTREAD, cb_listen)) {
+				Log(LOG_ERR,
+				    "io_event_create(): Can't add fd %d: %s!",
+				    fd, strerror(errno));
+				continue;
+			}
+			Log(LOG_INFO,
+			    "Initialized socket %d from systemd.", fd);
+			created++;
+		}
+		return created;
+	}
 
+	/* not using systemd socket activation, initialize listening sockets: */
+
 	/* can't use Conf_ListenAddress directly, see below */
 	copy = strdup(Conf_ListenAddress);
 	if (!copy) {
@@ -541,7 +606,12 @@ Conn_ExitListeners( void )
 	int *fd;
 	size_t arraylen;
 
+	/* Get number of listening sockets to shut down. There can be none
+	 * if ngIRCd has been "socket activated" by systemd. */
 	arraylen = array_length(&My_Listeners, sizeof (int));
+	if (arraylen < 1)
+		return;
+
 	Log(LOG_INFO,
 	    "Shutting down all listening sockets (%d total) ...", arraylen);
 	fd = array_start(&My_Listeners);