X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=5dd581b70e6de47975c7db83c0f5061c79909afd;hb=c7de505c919c5f550d848f9cafae99532bc1f789;hp=4ed586206f42107b0e32132530631545fede4ea4;hpb=b35f8916a5252182070d0e4502a540e81a3ced90;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 4ed58620..5dd581b7 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2019 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 @@ -9,9 +9,8 @@ * Please read the file COPYING, README and AUTHORS for more information. */ -#undef DEBUG_BUFFER - #define CONN_MODULE +#define CONN_MODULE_GLOBAL_INIT #include "portab.h" @@ -20,6 +19,9 @@ * Connection management */ +/* Additionan debug messages related to buffer handling: 0=off / 1=on */ +#define DEBUG_BUFFER 0 + #include #ifdef PROTOTYPES # include @@ -73,6 +75,9 @@ #define SD_LISTEN_FDS_START 3 /** systemd(8) socket activation offset */ +#define THROTTLE_CMDS 1 /** Throttling: max commands reached */ +#define THROTTLE_BPS 2 /** Throttling: max bps reached */ + 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 )); @@ -87,6 +92,8 @@ static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest )); static void Simple_Message PARAMS(( int Sock, const char *Msg )); static int NewListener PARAMS(( const char *listen_addr, UINT16 Port )); static void Account_Connection PARAMS((void)); +static void Throttle_Connection PARAMS((const CONN_ID Idx, CLIENT *Client, + const int Reason, unsigned int Value)); static array My_Listeners; static array My_ConnArray; @@ -176,7 +183,6 @@ cb_connserver(int sock, UNUSED short what) CONN_ID idx = Socket2Index( sock ); if (idx <= NONE) { - LogDebug("cb_connserver wants to write on unknown socket?!"); io_close(sock); return; } @@ -274,12 +280,11 @@ cb_clientserver(int sock, short what) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - - if (idx < 0) { + if (idx <= NONE) { io_close(sock); return; } + #ifdef SSL_SUPPORT if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) { @@ -301,32 +306,20 @@ cb_clientserver(int sock, short what) GLOBAL void Conn_Init( void ) { - CONN_ID i; + int size; - Pool_Size = CONNECTION_POOL; - if ((Conf_MaxConnections > 0) && - (Pool_Size > Conf_MaxConnections)) - Pool_Size = Conf_MaxConnections; - - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) { - Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]"); + /* Initialize the "connection pool". + * FIXME: My_Connetions/Pool_Size is needed by other parts of the + * code; remove them! */ + Pool_Size = 0; + size = Conf_MaxConnections > 0 ? Conf_MaxConnections : CONNECTION_POOL; + if (Socket2Index(size) <= NONE) { + Log(LOG_EMERG, "Failed to initialize connection pool!"); exit(1); } - /* FIXME: My_Connetions/Pool_Size is needed by other parts of the - * code; remove them! */ - My_Connections = (CONNECTION*) array_start(&My_ConnArray); - - LogDebug("Allocated connection pool for %d items (%ld bytes).", - array_length(&My_ConnArray, sizeof(CONNECTION)), - array_bytes(&My_ConnArray)); - - assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size); - + /* Initialize "listener" array. */ array_free( &My_Listeners ); - - for (i = 0; i < Pool_Size; i++) - Init_Conn_Struct(i); } /* Conn_Init */ /** @@ -564,8 +557,8 @@ InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port if (!ret) { assert(listen_addrstr); Log(LOG_CRIT, - "Can't bind to [%s]:%u: can't convert ip address \"%s\"!", - listen_addrstr, Port, listen_addrstr); + "Can't listen on [%s]:%u: Failed to parse IP address!", + listen_addrstr, Port); } return ret; } @@ -598,7 +591,7 @@ set_v6_only(int af, int sock) /** * Initialize new listening port. * - * @param listen_addr Local address to bind the socet to (can be 0.0.0.0). + * @param listen_addr Local address to bind the socket to (can be 0.0.0.0). * @param Port Port number on which the new socket should be listening. * @returns file descriptor of the socket or -1 on failure. */ @@ -664,12 +657,17 @@ GLOBAL void Conn_Handler(void) { int i; - size_t wdatalen, bytes_processed; + size_t wdatalen; struct timeval tv; time_t t; + bool command_available; + + Log(LOG_NOTICE, "Server \"%s\" (on \"%s\") ready.", + Client_ID(Client_ThisServer()), Client_Hostname(Client_ThisServer())); while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) { t = time(NULL); + command_available = false; /* Check configured servers and established links */ Check_Servers(); @@ -683,17 +681,7 @@ Conn_Handler(void) if ((My_Connections[i].sock > NONE) && (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 - * more commands in the input buffer, do not - * try to read any more data now */ - if (bytes_processed && - array_bytes(&My_Connections[i].rbuf) > 2) { - LogDebug - ("Throttling connection %d: command limit reached!", - i); - Conn_SetPenalty(i, 1); - } + Handle_Buffer(i); } } @@ -748,16 +736,31 @@ Conn_Handler(void) continue; } + if (array_bytes(&My_Connections[i].rbuf) >= COMMAND_LEN) { + /* There is still more data in the read buffer + * than a single valid command can get long: + * so either there is a complete command, or + * invalid data. Therefore don't try to read in + * even more data from the network but wait for + * this command(s) to be handled first! */ + io_event_del(My_Connections[i].sock, + IO_WANTREAD); + command_available = true; + continue; + } + io_event_add(My_Connections[i].sock, IO_WANTREAD); } - /* Set the timeout for reading from the network to 1 second, - * which is the granularity with witch we handle "penalty - * times" for example. + /* Don't wait for data when there is still at least one command + * available in a read buffer which can be handled immediately; + * set the timeout for reading from the network to 1 second + * otherwise, 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 before each call to it! */ tv.tv_usec = 0; - tv.tv_sec = 1; + tv.tv_sec = command_available ? 0 : 1; /* Wait for activity ... */ i = io_dispatch(&tv); @@ -800,7 +803,7 @@ Conn_Handler(void) GLOBAL bool Conn_WriteStr(CONN_ID Idx, const char *Format, ...) #else -GLOBAL bool +GLOBAL bool Conn_WriteStr(Idx, Format, va_alist) CONN_ID Idx; const char *Format; @@ -833,7 +836,7 @@ va_dcl * IRC_WriteXXX() functions when the prefix of this server had * to be added to an already "quite long" command line which * has been received from a regular IRC client, for example. - * + * * We are not allowed to send such "oversized" messages to * other servers and clients, see RFC 2812 2.3 and 2813 3.3 * ("these messages SHALL NOT exceed 512 characters in length, @@ -872,7 +875,7 @@ va_dcl #ifdef SNIFFER if (NGIRCd_Sniffer) - Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer); + LogDebug("-> connection %d: '%s'.", Idx, buffer); #endif len = strlcat( buffer, "\r\n", sizeof( buffer )); @@ -1099,9 +1102,9 @@ Conn_Close(CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClien * the calculation of in_p and out_p: in_z_k and out_z_k * are non-zero, that's guaranteed by the protocol until * compression can be enabled. */ - if (! in_z_k) + if (in_z_k <= 0) in_z_k = in_k; - if (! out_z_k) + if (out_z_k <= 0) out_z_k = out_k; in_p = (int)(( in_k * 100 ) / in_z_k ); out_p = (int)(( out_k * 100 ) / out_z_k ); @@ -1265,7 +1268,7 @@ Handle_Write( CONN_ID Idx ) return true; } -#ifdef DEBUG_BUFFER +#if DEBUG_BUFFER LogDebug ("Handle_Write() called for connection %d, %ld bytes pending ...", Idx, wdatalen); @@ -1286,6 +1289,9 @@ Handle_Write( CONN_ID Idx ) if (errno == EAGAIN || errno == EINTR) return true; + /* Log write errors but do not close the connection yet. + * Calling Conn_Close() now could result in too many recursive calls. + */ if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING)) Log(LOG_ERR, "Write error on connection %d (socket %d): %s!", @@ -1293,7 +1299,7 @@ Handle_Write( CONN_ID Idx ) else LogDebug("Recursive write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); - Conn_Close(Idx, "Write error", NULL, false); + return false; } @@ -1382,8 +1388,8 @@ New_Connection(int Sock, UNUSED bool IsSSL) /* Check global connection limit */ if ((Conf_MaxConnections > 0) && (NumConnections >= (size_t) Conf_MaxConnections)) { - Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!", - Conf_MaxConnections); + Log(LOG_ALERT, "Can't accept new connection on socket %d: Limit (%d) reached!", + Sock, Conf_MaxConnections); Simple_Message(new_sock, "ERROR :Connection limit reached"); close(new_sock); return -1; @@ -1402,23 +1408,10 @@ New_Connection(int Sock, UNUSED bool IsSSL) return -1; } - if (new_sock >= Pool_Size) { - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), - (size_t) new_sock)) { - Log(LOG_EMERG, - "Can't allocate memory! [New_Connection]"); - Simple_Message(new_sock, "ERROR: Internal error"); - close(new_sock); - return -1; - } - LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)", - new_sock, array_length(&My_ConnArray, - sizeof(CONNECTION)), array_bytes(&My_ConnArray)); - - /* Adjust pointer to new block */ - My_Connections = array_start(&My_ConnArray); - while (Pool_Size <= new_sock) - Init_Conn_Struct(Pool_Size++); + if (Socket2Index(new_sock) <= NONE) { + Simple_Message(new_sock, "ERROR: Internal error"); + close(new_sock); + return -1; } /* register callback */ @@ -1461,7 +1454,7 @@ New_Connection(int Sock, UNUSED bool IsSSL) Account_Connection(); #ifdef SSL_SUPPORT - /* Delay connection initalization until SSL handshake is finished */ + /* Delay connection initialization until SSL handshake is finished */ if (!IsSSL) #endif Conn_StartLogin(new_sock); @@ -1491,16 +1484,16 @@ Conn_StartLogin(CONN_ID Idx) ident_sock = My_Connections[Idx].sock; #endif - if (Conf_NoticeAuth) { - /* Send "NOTICE AUTH" messages to the client */ + if (Conf_NoticeBeforeRegistration) { + /* Send "NOTICE *" messages to the client */ #ifdef IDENTAUTH if (Conf_Ident) (void)Conn_WriteStr(Idx, - "NOTICE AUTH :*** Looking up your hostname and checking ident"); + "NOTICE * :*** Looking up your hostname and checking ident"); else #endif (void)Conn_WriteStr(Idx, - "NOTICE AUTH :*** Looking up your hostname"); + "NOTICE * :*** Looking up your hostname"); /* Send buffered data to the client, but break on errors * because Handle_Write() would have closed the connection * again in this case! */ @@ -1527,24 +1520,38 @@ Account_Connection(void) } /* Account_Connection */ /** - * Translate socket handle into connection index. + * Translate socket handle into connection index (for historical reasons, it is + * a 1:1 mapping today) and enlarge the "connection pool" accordingly. * * @param Sock Socket handle. - * @returns Connecion index or NONE, if no connection could be found. + * @returns Connecion index or NONE when the pool is too small. */ static CONN_ID Socket2Index( int Sock ) { - assert( Sock >= 0 ); + assert(Sock > 0); + assert(Pool_Size >= 0); + + if (Sock < Pool_Size) + return Sock; - if( Sock >= Pool_Size || My_Connections[Sock].sock != Sock ) { - /* the Connection was already closed again, likely due to - * an error. */ - LogDebug("Socket2Index: can't get connection for socket %d!", Sock); + /* Try to allocate more memory ... */ + if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Sock)) { + Log(LOG_EMERG, + "Can't allocate memory to enlarge connection pool!"); return NONE; } + LogDebug("Enlarged connection pool for %ld sockets (%ld items, %ld bytes)", + Sock, array_length(&My_ConnArray, sizeof(CONNECTION)), + array_bytes(&My_ConnArray)); + + /* Adjust pointer to new block, update size and initialize new items. */ + My_Connections = array_start(&My_ConnArray); + while (Pool_Size <= Sock) + Init_Conn_Struct(Pool_Size++); + return Sock; -} /* Socket2Index */ +} /** * Read data from the network to the read buffer. If an error occurs, @@ -1553,16 +1560,21 @@ Socket2Index( int Sock ) * @param Idx Connection index. */ static void -Read_Request( CONN_ID Idx ) +Read_Request(CONN_ID Idx) { ssize_t len; static const unsigned int maxbps = COMMAND_LEN / 2; char readbuf[READBUFFER_LEN]; time_t t; CLIENT *c; - assert( Idx > NONE ); - assert( My_Connections[Idx].sock > NONE ); + assert(Idx > NONE); + assert(My_Connections[Idx].sock > NONE); + + /* Check if the read buffer is "full". Basically this shouldn't happen + * here, because as long as there possibly are commands in the read + * buffer (buffer usage > COMMAND_LEN), the socket shouldn't be + * scheduled for reading in Conn_Handler() at all ... */ #ifdef ZLIB if ((array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) || (array_bytes(&My_Connections[Idx].zip.rbuf) >= READBUFFER_LEN)) @@ -1570,36 +1582,44 @@ Read_Request( CONN_ID Idx ) if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) #endif { - /* Read buffer is full */ Log(LOG_ERR, - "Receive buffer space exhausted (connection %d): %d bytes", - Idx, array_bytes(&My_Connections[Idx].rbuf)); + "Receive buffer space exhausted (connection %d): %d/%d bytes", + Idx, array_bytes(&My_Connections[Idx].rbuf), READBUFFER_LEN); Conn_Close(Idx, "Receive buffer space exhausted", NULL, false); return; } + /* Now read new data from the network, up to READBUFFER_LEN bytes ... */ #ifdef SSL_SUPPORT if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL)) - len = ConnSSL_Read( &My_Connections[Idx], readbuf, sizeof(readbuf)); + len = ConnSSL_Read(&My_Connections[Idx], readbuf, sizeof(readbuf)); else #endif - len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); + len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); + if (len == 0) { LogDebug("Client \"%s:%u\" is closing connection %d ...", My_Connections[Idx].host, - ng_ipaddr_tostr(&My_Connections[Idx].addr), Idx); + ng_ipaddr_getport(&My_Connections[Idx].addr), Idx); Conn_Close(Idx, NULL, "Client closed connection", false); return; } if (len < 0) { - if( errno == EAGAIN ) return; + if (errno == EAGAIN) + return; + Log(LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); Conn_Close(Idx, "Read error", "Client closed connection", false); return; } + + /* Now append the newly received data to the connection buffer. + * NOTE: This can lead to connection read buffers being bigger(!) than + * READBUFFER_LEN bytes, as we add up to READBUFFER_LEN new bytes to a + * buffer possibly being "almost" READBUFFER_LEN bytes already! */ #ifdef ZLIB if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) { if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf, @@ -1625,6 +1645,8 @@ Read_Request( CONN_ID Idx ) /* Update connection statistics */ My_Connections[Idx].bytes_in += len; + + /* Handle read buffer */ My_Connections[Idx].bps += Handle_Buffer(Idx); /* Make sure that there is still a valid client registered */ @@ -1650,14 +1672,8 @@ Read_Request( CONN_ID Idx ) } /* Look at the data in the (read-) buffer of this connection */ - if (Client_Type(c) != CLIENT_SERVER - && Client_Type(c) != CLIENT_UNKNOWNSERVER - && Client_Type(c) != CLIENT_SERVICE - && My_Connections[Idx].bps >= maxbps) { - LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)", - Idx, My_Connections[Idx].bps, maxbps); - Conn_SetPenalty(Idx, 1); - } + if (My_Connections[Idx].bps >= maxbps) + Throttle_Connection(Idx, c, THROTTLE_BPS, maxbps); } /* Read_Request */ /** @@ -1701,7 +1717,12 @@ Handle_Buffer(CONN_ID Idx) maxcmd *= 5; break; case CLIENT_SERVICE: - maxcmd = MAX_COMMANDS_SERVICE; break; + maxcmd = MAX_COMMANDS_SERVICE; + break; + case CLIENT_USER: + if (Client_HasMode(c, 'F')) + maxcmd = MAX_COMMANDS_SERVICE; + break; } for (i=0; i < maxcmd; i++) { @@ -1798,10 +1819,6 @@ Handle_Buffer(CONN_ID Idx) return 0; /* error -> connection has been closed */ array_moveleft(&My_Connections[Idx].rbuf, 1, len); -#ifdef DEBUG_BUFFER - LogDebug("Connection %d: %d bytes left in read buffer.", - Idx, array_bytes(&My_Connections[Idx].rbuf)); -#endif #ifdef ZLIB if ((!old_z) && (My_Connections[Idx].options & CONN_ZIP) && (array_bytes(&My_Connections[Idx].rbuf) > 0)) { @@ -1824,6 +1841,17 @@ Handle_Buffer(CONN_ID Idx) } #endif } +#if DEBUG_BUFFER + LogDebug("Connection %d: Processed %ld commands (max=%ld), %ld bytes. %ld bytes left in read buffer.", + Idx, i, maxcmd, len_processed, + array_bytes(&My_Connections[Idx].rbuf)); +#endif + + /* If data has been processed but there is still data in the read + * buffer, the command limit triggered. Enforce the penalty time: */ + if (len_processed && array_bytes(&My_Connections[Idx].rbuf) > 2) + Throttle_Connection(Idx, c, THROTTLE_CMDS, maxcmd); + return len_processed; } /* Handle_Buffer */ @@ -1838,6 +1866,9 @@ Check_Connections(void) CLIENT *c; CONN_ID i; char msg[64]; + time_t time_now; + + time_now = time(NULL); for (i = 0; i < Pool_Size; i++) { if (My_Connections[i].sock < 0) @@ -1852,7 +1883,7 @@ Check_Connections(void) My_Connections[i].lastdata) { /* We already sent a ping */ if (My_Connections[i].lastping < - time(NULL) - Conf_PongTimeout) { + time_now - Conf_PongTimeout) { /* Timeout */ snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", @@ -1861,10 +1892,10 @@ Check_Connections(void) Conn_Close(i, NULL, msg, true); } } else if (My_Connections[i].lastdata < - time(NULL) - Conf_PingTimeout) { + time_now - Conf_PingTimeout) { /* We need to send a PING ... */ LogDebug("Connection %d: sending PING ...", i); - Conn_UpdatePing(i); + Conn_UpdatePing(i, time_now); Conn_WriteStr(i, "PING :%s", Client_ID(Client_ThisServer())); } @@ -1875,7 +1906,7 @@ Check_Connections(void) * still not registered. */ if (My_Connections[i].lastdata < - time(NULL) - Conf_PongTimeout) { + time_now - Conf_PongTimeout) { LogDebug ("Unregistered connection %d timed out ...", i); @@ -1900,7 +1931,7 @@ Check_Servers(void) for (i = 0; i < MAX_SERVERS; i++) { if (Conf_Server[i].conn_id != NONE) continue; /* Already establishing or connected */ - if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0) + if (!Conf_Server[i].host[0] || Conf_Server[i].port <= 0) continue; /* No host and/or port configured */ if (Conf_Server[i].flags & CONF_SFLAG_DISABLED) continue; /* Disabled configuration entry */ @@ -1927,8 +1958,11 @@ Check_Servers(void) Conf_Server[i].lasttry = time_now; Conf_Server[i].conn_id = SERVER_WAIT; assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0); - Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, - cb_Connect_to_Server); + + /* Start resolver subprocess ... */ + if (!Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, + cb_Connect_to_Server)) + Conf_Server[i].conn_id = NONE; } } /* Check_Servers */ @@ -2003,10 +2037,7 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } - if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) { - Log(LOG_ALERT, - "Cannot allocate memory for server connection (socket %d)", - new_sock); + if (Socket2Index(new_sock) <= NONE) { close( new_sock ); Conf_Server[Server].conn_id = NONE; return; @@ -2020,8 +2051,6 @@ New_Server( int Server , ng_ipaddr_t *dest) return; } - My_Connections = array_start(&My_ConnArray); - assert(My_Connections[new_sock].sock <= 0); Init_Conn_Struct(new_sock); @@ -2261,9 +2290,9 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) strlcpy(My_Connections[i].host, readbuf, sizeof(My_Connections[i].host)); Client_SetHostname(c, readbuf); - if (Conf_NoticeAuth) + if (Conf_NoticeBeforeRegistration) (void)Conn_WriteStr(i, - "NOTICE AUTH :*** Found your hostname: %s", + "NOTICE * :*** Found your hostname: %s", My_Connections[i].host); #ifdef IDENTAUTH ++identptr; @@ -2287,22 +2316,22 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) i, identptr); Client_SetUser(c, identptr, true); } - if (Conf_NoticeAuth) { + if (Conf_NoticeBeforeRegistration) { (void)Conn_WriteStr(i, - "NOTICE AUTH :*** Got %sident response%s%s", + "NOTICE * :*** Got %sident response%s%s", *ptr ? "invalid " : "", *ptr ? "" : ": ", *ptr ? "" : identptr); } } else if(Conf_Ident) { Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i); - if (Conf_NoticeAuth) + if (Conf_NoticeBeforeRegistration) (void)Conn_WriteStr(i, - "NOTICE AUTH :*** No ident response"); + "NOTICE * :*** No ident response"); } #endif - if (Conf_NoticeAuth) { + if (Conf_NoticeBeforeRegistration) { /* Send buffered data to the client, but break on * errors because Handle_Write() would have closed * the connection again in this case! */ @@ -2312,10 +2341,8 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) Class_HandleServerBans(c); } -#ifdef DEBUG else LogDebug("Resolver: discarding result for already registered connection %d.", i); -#endif } /* cb_Read_Resolver_Result */ /** @@ -2360,7 +2387,7 @@ Simple_Message(int Sock, const char *Msg) * @returns Pointer to CLIENT structure. */ GLOBAL CLIENT * -Conn_GetClient( CONN_ID Idx ) +Conn_GetClient( CONN_ID Idx ) { CONNECTION *c; @@ -2407,6 +2434,35 @@ Conn_GetFromProc(int fd) return NONE; } /* Conn_GetFromProc */ +/** + * Throttle a connection because of excessive usage. + * + * @param Reason The reason, see THROTTLE_xxx constants. + * @param Idx The connection index. + * @param Client The client of this connection. + * @param Value The time to delay this connection. + */ +static void +Throttle_Connection(const CONN_ID Idx, CLIENT *Client, const int Reason, + unsigned int Value) +{ + assert(Idx > NONE); + assert(Client != NULL); + + /* Never throttle servers or services, only interrupt processing */ + if (Client_Type(Client) == CLIENT_SERVER + || Client_Type(Client) == CLIENT_UNKNOWNSERVER + || Client_Type(Client) == CLIENT_SERVICE) + return; + + /* Don't throttle clients with user mode 'F' set */ + if (Client_HasMode(Client, 'F')) + return; + + LogDebug("Throttling connection %d: code %d, value %d!", Idx, + Reason, Value); + Conn_SetPenalty(Idx, 1); +} #ifndef STRICT_RFC @@ -2439,9 +2495,7 @@ cb_clientserver_ssl(int sock, UNUSED short what) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - - if (idx < 0) { + if (idx <= NONE) { io_close(sock); return; } @@ -2491,12 +2545,13 @@ cb_connserver_login_ssl(int sock, short unused) { CONN_ID idx = Socket2Index(sock); - assert(idx >= 0); - if (idx < 0) { + (void) unused; + + if (idx <= NONE) { io_close(sock); return; } - (void) unused; + switch (ConnSSL_Connect( &My_Connections[idx])) { case 1: break; case 0: LogDebug("ConnSSL_Connect: not ready"); @@ -2631,7 +2686,6 @@ Conn_SetCertFp(UNUSED CONN_ID Idx, UNUSED const char *fingerprint) #endif /* SSL_SUPPORT */ -#ifdef DEBUG /** * Dump internal state of the "connection module". @@ -2641,11 +2695,11 @@ Conn_DebugDump(void) { int i; - Log(LOG_DEBUG, "Connection status:"); + LogDebug("Connection status:"); for (i = 0; i < Pool_Size; i++) { if (My_Connections[i].sock == NONE) continue; - Log(LOG_DEBUG, + LogDebug( " - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s", My_Connections[i].sock, My_Connections[i].host, My_Connections[i].lastdata, My_Connections[i].lastping, @@ -2655,6 +2709,5 @@ Conn_DebugDump(void) } } /* Conn_DumpClients */ -#endif /* DEBUG */ /* -eof- */