X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=01253a2a19dba746ead7a8edc8b1bca34985c263;hb=15dfdaac823c5927b096b2980753a6198a6a7741;hp=14d337b9408265b1213a157cd36cf66a8efc057e;hpb=f16d230530424f93541b4ca36e2686ddfb76834a;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 14d337b9..01253a2a 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -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, because 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; + int 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 = atoi(e); + unsetenv("LISTEN_FDS"); + + return count; +} + /** * IO callback for listening sockets: handle new connections. This callback @@ -329,13 +367,13 @@ cb_clientserver(int sock, short what) #ifdef SSL_SUPPORT /** - * IO callback for established SSL-enabled client and server connections. + * IO callback for new SSL-enabled client and server connections. * * @param sock Socket descriptor. * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...). */ static void -cb_clientserver_ssl(int sock, short what) +cb_clientserver_ssl(int sock, UNUSED short what) { CONN_ID idx = Socket2Index(sock); @@ -352,14 +390,11 @@ cb_clientserver_ssl(int sock, short what) case 0: return; /* EAGAIN: callback will be invoked again by IO layer */ default: - Conn_Close(idx, "SSL accept error, closing socket", "SSL accept error", false); + Conn_Close(idx, + "SSL accept error, closing socket", "SSL accept error", + false); return; } - if (what & IO_WANTREAD) - Read_Request(idx); - - if (what & IO_WANTWRITE) - Handle_Write(idx); io_event_setcb(sock, cb_clientserver); /* SSL handshake completed */ } @@ -367,14 +402,13 @@ cb_clientserver_ssl(int sock, short what) /** - * Initialize connecion module. + * Initialize connection module. */ GLOBAL void Conn_Init( void ) { CONN_ID i; - /* Speicher fuer Verbindungs-Pool anfordern */ Pool_Size = CONNECTION_POOL; if ((Conf_MaxConnections > 0) && (Pool_Size > Conf_MaxConnections)) @@ -494,10 +528,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 +636,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); @@ -752,8 +852,7 @@ Conn_Handler(void) /* Look for non-empty read buffers ... */ for (i = 0; i < Pool_Size; i++) { if ((My_Connections[i].sock > NONE) - && (array_bytes(&My_Connections[i].rbuf) > 0) - && (My_Connections[i].delaytime <= t)) { + && (array_bytes(&My_Connections[i].rbuf) > 0)) { /* ... and try to handle the received data */ bytes_processed = Handle_Buffer(i); /* if we processed data, and there might be @@ -823,7 +922,7 @@ Conn_Handler(void) * which is the granularity with witch we handle "penalty * times" for example. * Note: tv_sec/usec are undefined(!) after io_dispatch() - * returns, so we have to set it beforce each call to it! */ + * returns, so we have to set it before each call to it! */ tv.tv_usec = 0; tv.tv_sec = 1; @@ -836,6 +935,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) @@ -899,7 +1007,7 @@ va_dcl * * So we have a big problem here: we should send more bytes * to the network than we are allowed to and we don't know - * the originator (any more). The "old" behaviour of blaming + * the originator (any more). The "old" behavior of blaming * the receiver ("next hop") is a bad idea (it could be just * an other server only routing the message!), so the only * option left is to shorten the string and to hope that the @@ -1197,6 +1305,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 +1678,7 @@ static void Account_Connection(void) { NumConnections++; + idle_t = 0; if (NumConnections > NumConnectionsMax) NumConnectionsMax = NumConnections; LogDebug("Total number of connections now %lu (max %lu).", @@ -1597,7 +1708,7 @@ Socket2Index( int Sock ) /** - * Read data from the network to the read buffer. If an error occures, + * Read data from the network to the read buffer. If an error occurs, * the socket of this connection will be shut down. * * @param Idx Connection index. @@ -1746,7 +1857,7 @@ Handle_Buffer(CONN_ID Idx) maxcmd = (int)(Client_UserCount() / 5) + MAX_COMMANDS_SERVER_MIN; /* Allow servers to handle even more commands while peering - * to speed up server login and network synchronisation. */ + * to speed up server login and network synchronization. */ if (Conn_LastPing(Idx) == 0) maxcmd *= 5; break; @@ -2240,7 +2351,7 @@ cb_Connect_to_Server(int fd, UNUSED short events) /** * Read results of a resolver sub-process from the pipe and update the - * apropriate connection/client structure(s): hostname and/or IDENT user name. + * appropriate connection/client structure(s): hostname and/or IDENT user name. * * @param r_fd File descriptor of the pipe to the sub-process. * @param events (ignored IO specification) @@ -2467,7 +2578,7 @@ Conn_SetAuthPing(CONN_ID Idx, long ID) #ifdef SSL_SUPPORT /** - * Get information about used SSL chiper. + * Get information about used SSL cipher. * * @param Idx Connection index number. * @param buf Buffer for returned information text. @@ -2499,6 +2610,45 @@ Conn_UsesSSL(CONN_ID Idx) return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } + +GLOBAL char * +Conn_GetCertFp(CONN_ID Idx) +{ + if (Idx < 0) + return NULL; + assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); + return ConnSSL_GetCertFp(&My_Connections[Idx]); +} + + +GLOBAL bool +Conn_SetCertFp(CONN_ID Idx, const char *fingerprint) +{ + if (Idx < 0) + return false; + assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); + return ConnSSL_SetCertFp(&My_Connections[Idx], fingerprint); +} +#else +GLOBAL bool +Conn_UsesSSL(UNUSED CONN_ID Idx) +{ + return false; +} + + +GLOBAL char * +Conn_GetCertFp(UNUSED CONN_ID Idx) +{ + return NULL; +} + + +GLOBAL bool +Conn_SetCertFp(UNUSED CONN_ID Idx, UNUSED const char *fingerprint) +{ + return true; +} #endif