I have written this document in June 2002 after having been asked questions about a piece of knowledge that I acquired a long time ago: flood control in ircds.
From 1996 until 1998, I developed with Etienne Bernard an IRC bot, the bobot.
At the end of 1996, I had the idea of managing the output of the bot with a queue, ordering the commands by priorities (at the time, IRC was a jungle, and keeping the op on a channel was a priority) and making the bot talk at the maximum speed the IRC server would process them.
I asked on the ircd development list if queuing in the server was documented anywhere, and having received a negative answer, I read the code of the ircd for a good while since the information was scattered all over the place to get an algorithm which seemed to work.
I am documenting some work I did more than 5 years ago. The ircd code might have changed, especially with all the different flavors. However, the algorithm did work at the time, so it probably is a good start for some IRC flood control work. The IRCNet network should have a behavior pretty close to what is described here.
I will use from now on the present tense assuming that things are unchanged (there is no such guarantee), and details are excerpted from the bobot source code.
I have divided this section into two subsections: the general overview and the specifics with some figures.
The ircd has for each connection a buffer for commands sent by the client and waiting to be processed. In order to make IRC friendlier (avoid channel hijacking, flooding, etc), commands are processed one by one, not too many at a time.
If the buffer is filled, the client will be disconnected for excess flood. The trick is therefore to keep the buffer on the server to the minimum, i.e. have the buffering done on the client side. The question is thus to know what the delays for command processing are.
For each client connection, there is a penalty count. As long as it is positive, commands are processed. When it is negative, commands are kept until it is positive again.
Each second, the penalty count is increased, but cannot go over a maximum.
Thinking about this again, I am not sure about the numbers at all.
Different commands have different cost: WHO is more expensive
than a simple PRIVMSG for example. Also, the longer the line
sent the higher the penalty.
Here is the get_penalty() function from bobot:
int get_penalty(struct line *l) {
int answer;
answer=1+(strlen(l->command)+strlen(l->params)+1)/100;
if (!strcmp(l->command,"NICK"))
return(answer+1);
if (!strcmp(l->command,"JOIN"))
return(answer+1);
if (!strcmp(l->command,"PART"))
return(answer+1);
if (!strcmp(l->command,"TOPIC"))
return(answer+2);
if (!strcmp(l->command,"NOTICE"))
return(answer);
if (!strcmp(l->command,"PING"))
return(answer+1);
if (!strcmp(l->command,"WHO"))
return(answer+3);
if (!strcmp(l->command,"USERHOST"))
return(answer+1);
if (!strcmp(l->command,"KICK"))
return(answer+2);
if (!strcmp(l->command,"MODE"))
return(answer+2);
return(answer);
}
If I remember correctly (I couldn't find that from the code... I guess it
would be possible, but ), the maximum for the penalty counter is
10, which is the beginning value, and is increased by
1 every second until it reaches that value.
Every time a line is processed by the server, its penalty is decreased to that counter.
Since the queue is managed on the client side, there are some optimizations possible instead of using a FIFO.
For example, some commands might be more important than others:
MODE is more important than NICK for a bot keeping
the op on a channel. bobot was using the following values for the queue
scheduling:
/* Priorities */ #define SERVER_MODE_PRIORITY 0 #define OP_MODE_PRIORITY 1 #define BAN_MODE_PRIORITY 2 #define CHANNEL_MODE_PRIORITY 5 #define KICK_PRIORITY 10 #define PONG_PRIORITY 20 #define TOPIC_PRIORITY 30 #define PART_PRIORITY 40 #define JOIN_PRIORITY 50 #define USERHOST_PRIORITY 60 #define WHO_PRIORITY 70 #define WHOIS_PRIORITY 80 #define NICK_PRIORITY 90 #define PING_PRIORITY 100 #define URGENT_NOTICE_PRIORITY 120 #define MSG_PRIORITY 121 #define DEFAULT_NOTICE_PRIORITY 122 #define QUIT_PRIORITY 0 #define IMPORTANT_PRIORITY 19
Also, it may be cost-effective to group commands. For example, it costs
more to send to MODE commands to give operator privileges to
two different people rather than sending only one with two arguments. bobot
merges MODE and KICK commands.
Please send comments about this document to hugo@larve.net. I am unlikely to keep this document up-to-date, but I will document errors; I am sure that there are some.