mirror of
				https://github.com/osmarks/ngircd.git
				synced 2025-10-31 22:13:00 +00:00 
			
		
		
		
	Merge branch 'systemd'
* systemd: ngircd.sock: explicitely bind to IPv4 and IPv6 addresses Show address and port of sockets passed-in by systemd(8) Check type of sockets passed-in by systemd(8) Adjust severity levels of some log messages New configuration option "IdleTimeout": exit daemon when idle Implement support for systemd(8) "socket activation" contrib/README: add more files
This commit is contained in:
		| @@ -370,6 +370,7 @@ Conf_Test( void ) | ||||
|  | ||||
| 	puts("[LIMITS]"); | ||||
| 	printf("  ConnectRetry = %d\n", Conf_ConnectRetry); | ||||
| 	printf("  IdleTimeout = %d\n", Conf_IdleTimeout); | ||||
| 	printf("  MaxConnections = %d\n", Conf_MaxConnections); | ||||
| 	printf("  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP); | ||||
| 	printf("  MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1); | ||||
| @@ -736,6 +737,7 @@ Set_Defaults(bool InitServers) | ||||
|  | ||||
| 	/* Limits */ | ||||
| 	Conf_ConnectRetry = 60; | ||||
| 	Conf_IdleTimeout = 0; | ||||
| 	Conf_MaxConnections = 0; | ||||
| 	Conf_MaxConnectionsIP = 5; | ||||
| 	Conf_MaxJoins = 10; | ||||
| @@ -830,8 +832,8 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination) | ||||
|  | ||||
| 	fp = fopen(Filename, "r"); | ||||
| 	if (!fp) { | ||||
| 		Config_Error(LOG_WARNING, "Can't read %s file \"%s\": %s", | ||||
| 					Name, Filename, strerror(errno)); | ||||
| 		Config_Error(LOG_ERR, "Can't read %s file \"%s\": %s", | ||||
| 			     Name, Filename, strerror(errno)); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| @@ -841,7 +843,7 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination) | ||||
|  | ||||
| 		/* add text including \0 */ | ||||
| 		if (!array_catb(Destination, line, strlen(line) + 1)) { | ||||
| 			Log(LOG_WARNING, "Cannot read/add \"%s\", line %d: %s", | ||||
| 			Log(LOG_ERR, "Cannot read/add \"%s\", line %d: %s", | ||||
| 			    Filename, line_no, strerror(errno)); | ||||
| 			break; | ||||
| 		} | ||||
| @@ -1241,6 +1243,7 @@ CheckLegacyGlobalOption(int Line, char *Var, char *Arg) | ||||
| 		return "[Options]"; | ||||
| 	} | ||||
| 	if (strcasecmp(Var, "ConnectRetry") == 0 | ||||
| 	    || strcasecmp(Var, "IdleTimeout") == 0 | ||||
| 	    || strcasecmp(Var, "MaxConnections") == 0 | ||||
| 	    || strcasecmp(Var, "MaxConnectionsIP") == 0 | ||||
| 	    || strcasecmp(Var, "MaxJoins") == 0 | ||||
| @@ -1490,6 +1493,12 @@ Handle_LIMITS(int Line, char *Var, char *Arg) | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 	if (strcasecmp(Var, "IdleTimeout") == 0) { | ||||
| 		Conf_IdleTimeout = atoi(Arg); | ||||
| 		if (!Conf_IdleTimeout && strcmp(Arg, "0")) | ||||
| 			Config_Error_NaN(Line, Var); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (strcasecmp(Var, "MaxConnections") == 0) { | ||||
| 		Conf_MaxConnections = atoi(Arg); | ||||
| 		if (!Conf_MaxConnections && strcmp(Arg, "0")) | ||||
|   | ||||
| @@ -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 | ||||
| @@ -211,6 +211,9 @@ GLOBAL bool Conf_ConnectIPv6; | ||||
| /** Try to connect to remote systems using the IPv4 protocol (true) */ | ||||
| GLOBAL bool Conf_ConnectIPv4; | ||||
|  | ||||
| /** Idle timout (seconds), after which the daemon should exit */ | ||||
| GLOBAL int Conf_IdleTimeout; | ||||
|  | ||||
| /** Maximum number of simultaneous connections to this server */ | ||||
| GLOBAL int Conf_MaxConnections; | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| @@ -82,6 +82,8 @@ | ||||
| #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 )); | ||||
| @@ -119,6 +121,42 @@ 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)); | ||||
|  | ||||
| time_t idle_t = 0; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 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; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * IO callback for listening sockets: handle new connections. This callback | ||||
| @@ -494,10 +532,71 @@ Conn_InitListeners( void ) | ||||
| { | ||||
| 	/* Initialize ports on which the server should accept connections */ | ||||
| 	unsigned int created = 0; | ||||
| 	char *copy, *listen_addr; | ||||
| 	char *af_str, *copy, *listen_addr; | ||||
| 	int count, fd, i, addr_len; | ||||
| 	ng_ipaddr_t addr; | ||||
|  | ||||
| 	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; | ||||
| 			addr_len = (int)sizeof(addr); | ||||
| 			getsockname(fd, (struct sockaddr *)&addr, (socklen_t*)&addr_len); | ||||
| #ifdef WANT_IPV6 | ||||
| 			if (addr.sin4.sin_family != AF_INET && addr.sin4.sin_family != AF_INET6) | ||||
| #else | ||||
| 			if (addr.sin4.sin_family != AF_INET) | ||||
| #endif | ||||
| 			{ | ||||
| 				/* Socket is of unsupported type! For example, systemd passed in | ||||
| 				 * an IPv6 socket but ngIRCd isn't compiled with IPv6 support. */ | ||||
| 				switch (addr.sin4.sin_family) | ||||
| 				{ | ||||
| 					case AF_UNSPEC: af_str = "AF_UNSPEC"; break; | ||||
| 					case AF_UNIX: af_str = "AF_UNIX"; break; | ||||
| 					case AF_INET: af_str = "AF_INET"; break; | ||||
| #ifdef AF_INET6 | ||||
| 					case AF_INET6: af_str = "AF_INET6"; break; | ||||
| #endif | ||||
| #ifdef AF_NETLINK | ||||
| 					case AF_NETLINK: af_str = "AF_NETLINK"; break; | ||||
| #endif | ||||
| 					default: af_str = "unknown"; break; | ||||
| 				} | ||||
| 				Log(LOG_CRIT, | ||||
| 				    "Socket %d is of unsupported type \"%s\" (%d), have to ignore it!", | ||||
| 				    fd, af_str, addr.sin4.sin_family); | ||||
| 				close(fd); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			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(8): %s:%d.", fd, | ||||
| 			    ng_ipaddr_tostr(&addr), ng_ipaddr_getport(&addr)); | ||||
| 			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 +640,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); | ||||
| @@ -836,6 +940,15 @@ Conn_Handler(void) | ||||
| 			    PACKAGE_NAME); | ||||
| 			exit(1); | ||||
| 		} | ||||
|  | ||||
| 		/* Should ngIRCd timeout when idle? */ | ||||
| 		if (Conf_IdleTimeout > 0 && NumConnectionsAccepted > 0 | ||||
| 		    && idle_t > 0 && time(NULL) - idle_t >= Conf_IdleTimeout) { | ||||
| 			LogDebug("Server idle timeout reached: %d second%s. Initiating shutdown ...", | ||||
| 				 Conf_IdleTimeout, | ||||
| 				 Conf_IdleTimeout == 1 ? "" : "s"); | ||||
| 			NGIRCd_SignalQuit = true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (NGIRCd_SignalQuit) | ||||
| @@ -1197,6 +1310,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie | ||||
| 		NumConnections--; | ||||
| 	LogDebug("Shutdown of connection %d completed, %ld connection%s left.", | ||||
| 		 Idx, NumConnections, NumConnections != 1 ? "s" : ""); | ||||
|  | ||||
| 	idle_t = NumConnections > 0 ? 0 : time(NULL); | ||||
| } /* Conn_Close */ | ||||
|  | ||||
|  | ||||
| @@ -1568,6 +1683,7 @@ static void | ||||
| Account_Connection(void) | ||||
| { | ||||
| 	NumConnections++; | ||||
| 	idle_t = 0; | ||||
| 	if (NumConnections > NumConnectionsMax) | ||||
| 		NumConnectionsMax = NumConnections; | ||||
| 	LogDebug("Total number of connections now %lu (max %lu).", | ||||
|   | ||||
| @@ -109,7 +109,7 @@ Log_ReInit(void) | ||||
| GLOBAL void | ||||
| Log_Exit( void ) | ||||
| { | ||||
| 	Log(LOG_NOTICE, "%s done%s, served %lu connection%s.", PACKAGE_NAME, | ||||
| 	Log(LOG_INFO, "%s done%s, served %lu connection%s.", PACKAGE_NAME, | ||||
| 	    NGIRCd_SignalRestart ? " (restarting)" : "", Conn_CountAccepted(), | ||||
| 	    Conn_CountAccepted() == 1 ? "" : "s"); | ||||
| #ifdef SYSLOG | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Alexander Barton
					Alexander Barton