mirror of
https://github.com/osmarks/ngircd.git
synced 2024-12-12 09:50:29 +00:00
Handle "throttling" in a single function
ngIRCd uses "command throttling" and "bps throttling" (bytes per second). The states are detected in different functions, Conn_Handler() and Read_Request(), but handle the actual "throttling" in a common function: this enables us to guarantee consistent behavior and to disable throttling for special connections in only one place, eventually.
This commit is contained in:
parent
4c2acd55c6
commit
35f1db5f28
@ -74,6 +74,9 @@
|
|||||||
|
|
||||||
#define SD_LISTEN_FDS_START 3 /** systemd(8) socket activation offset */
|
#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 Handle_Write PARAMS(( CONN_ID Idx ));
|
||||||
static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
|
static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
|
||||||
static int New_Connection PARAMS(( int Sock, bool IsSSL ));
|
static int New_Connection PARAMS(( int Sock, bool IsSSL ));
|
||||||
@ -88,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 void Simple_Message PARAMS(( int Sock, const char *Msg ));
|
||||||
static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
|
static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
|
||||||
static void Account_Connection PARAMS((void));
|
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_Listeners;
|
||||||
static array My_ConnArray;
|
static array My_ConnArray;
|
||||||
@ -665,7 +670,7 @@ GLOBAL void
|
|||||||
Conn_Handler(void)
|
Conn_Handler(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
size_t wdatalen, bytes_processed;
|
size_t wdatalen;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
time_t t;
|
time_t t;
|
||||||
|
|
||||||
@ -684,17 +689,7 @@ Conn_Handler(void)
|
|||||||
if ((My_Connections[i].sock > NONE)
|
if ((My_Connections[i].sock > NONE)
|
||||||
&& (array_bytes(&My_Connections[i].rbuf) > 0)) {
|
&& (array_bytes(&My_Connections[i].rbuf) > 0)) {
|
||||||
/* ... and try to handle the received data */
|
/* ... and try to handle the received data */
|
||||||
bytes_processed = Handle_Buffer(i);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1573,8 +1568,8 @@ Read_Request( CONN_ID Idx )
|
|||||||
{
|
{
|
||||||
/* Read buffer is full */
|
/* Read buffer is full */
|
||||||
Log(LOG_ERR,
|
Log(LOG_ERR,
|
||||||
"Receive buffer space exhausted (connection %d): %d bytes",
|
"Receive buffer space exhausted (connection %d): %d/%d bytes",
|
||||||
Idx, array_bytes(&My_Connections[Idx].rbuf));
|
Idx, array_bytes(&My_Connections[Idx].rbuf), READBUFFER_LEN);
|
||||||
Conn_Close(Idx, "Receive buffer space exhausted", NULL, false);
|
Conn_Close(Idx, "Receive buffer space exhausted", NULL, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1626,6 +1621,8 @@ Read_Request( CONN_ID Idx )
|
|||||||
|
|
||||||
/* Update connection statistics */
|
/* Update connection statistics */
|
||||||
My_Connections[Idx].bytes_in += len;
|
My_Connections[Idx].bytes_in += len;
|
||||||
|
|
||||||
|
/* Handle read buffer */
|
||||||
My_Connections[Idx].bps += Handle_Buffer(Idx);
|
My_Connections[Idx].bps += Handle_Buffer(Idx);
|
||||||
|
|
||||||
/* Make sure that there is still a valid client registered */
|
/* Make sure that there is still a valid client registered */
|
||||||
@ -1651,14 +1648,8 @@ Read_Request( CONN_ID Idx )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Look at the data in the (read-) buffer of this connection */
|
/* Look at the data in the (read-) buffer of this connection */
|
||||||
if (Client_Type(c) != CLIENT_SERVER
|
if (My_Connections[Idx].bps >= maxbps)
|
||||||
&& Client_Type(c) != CLIENT_UNKNOWNSERVER
|
Throttle_Connection(Idx, c, THROTTLE_BPS, maxbps);
|
||||||
&& 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);
|
|
||||||
}
|
|
||||||
} /* Read_Request */
|
} /* Read_Request */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1827,6 +1818,11 @@ Handle_Buffer(CONN_ID Idx)
|
|||||||
array_bytes(&My_Connections[Idx].rbuf));
|
array_bytes(&My_Connections[Idx].rbuf));
|
||||||
#endif
|
#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;
|
return len_processed;
|
||||||
} /* Handle_Buffer */
|
} /* Handle_Buffer */
|
||||||
|
|
||||||
@ -2410,6 +2406,31 @@ Conn_GetFromProc(int fd)
|
|||||||
return NONE;
|
return NONE;
|
||||||
} /* Conn_GetFromProc */
|
} /* 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;
|
||||||
|
|
||||||
|
LogDebug("Throttling connection %d: code %d, value %d!", Idx,
|
||||||
|
Reason, Value);
|
||||||
|
Conn_SetPenalty(Idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef STRICT_RFC
|
#ifndef STRICT_RFC
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user