Commit Diff
Diff:
4c2acd55c6ecb8d9a6a1c6c5c86295fdd859820c
35f1db5f28245579efbbb06eed6eaf1a3d6d84bc
Commit:
35f1db5f28245579efbbb06eed6eaf1a3d6d84bc
Tree:
1f43bd429df0f93b945cd0db52f9883c8996f6e6
Author:
Alexander Barton <alex@barton.de>
Committer:
Alexander Barton <alex@barton.de>
Date:
Tue Mar 18 13:53:29 2014 UTC
Message:
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.
blob - 4dfe62fbdb85935030dc3112032baee6668ba9ff
blob + 77c8cd8a04ae7c6dca8958663326b52a34053180
--- src/ngircd/conn.c
+++ src/ngircd/conn.c
@@ -74,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 ));
@@ -88,6 +91,8 @@ static void New_Server PARAMS(( int Server, ng_ipaddr_
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;
@@ -665,7 +670,7 @@ GLOBAL void
Conn_Handler(void)
{
int i;
- size_t wdatalen, bytes_processed;
+ size_t wdatalen;
struct timeval tv;
time_t t;
@@ -684,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);
}
}
@@ -1573,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;
}
@@ -1626,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 */
@@ -1651,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 */
/**
@@ -1827,6 +1818,11 @@ Handle_Buffer(CONN_ID Idx)
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 */
@@ -2410,7 +2406,32 @@ 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;
+
+ LogDebug("Throttling connection %d: code %d, value %d!", Idx,
+ Reason, Value);
+ Conn_SetPenalty(Idx, 1);
+}
+
#ifndef STRICT_RFC
GLOBAL long
IRCNow