X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=62561544866413f5abb1534da27caac1e2aa2218;hp=4ed586206f42107b0e32132530631545fede4ea4;hb=ffad2da835e26a1a457d4f4a16acf6797d4cc71e;hpb=b35f8916a5252182070d0e4502a540e81a3ced90 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 4ed58620..62561544 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -9,8 +9,6 @@ * Please read the file COPYING, README and AUTHORS for more information. */ -#undef DEBUG_BUFFER - #define CONN_MODULE #include "portab.h" @@ -20,6 +18,9 @@ * Connection management */ +/* Additionan debug messages related to buffer handling: 0=off / 1=on */ +#define DEBUG_BUFFER 0 + #include #ifdef PROTOTYPES # include @@ -73,6 +74,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 +91,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; @@ -664,7 +670,7 @@ GLOBAL void Conn_Handler(void) { int i; - size_t wdatalen, bytes_processed; + size_t wdatalen; struct timeval tv; time_t t; @@ -683,17 +689,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); } } @@ -1265,7 +1261,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); @@ -1572,8 +1568,8 @@ Read_Request( CONN_ID Idx ) { /* 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; } @@ -1625,6 +1621,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 +1648,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 +1693,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 +1795,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 +1817,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 */ @@ -1900,7 +1904,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 */ @@ -2407,6 +2411,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 Seconds 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