Restore stats_spy hook that was removed in commit 401f2454671ca233e35b0e6e4f3fa4c43cd...
[seven-1.x.git] / src / packet.c
blob189557eff339b224998dbbba1e7c42c7a9ddfcda
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * packet.c: Packet handlers.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
24 #include "stdinc.h"
25 #include "tools.h"
26 #include "commio.h"
27 #include "s_conf.h"
28 #include "s_serv.h"
29 #include "client.h"
30 #include "common.h"
31 #include "ircd.h"
32 #include "parse.h"
33 #include "packet.h"
34 #include "irc_string.h"
35 #include "memory.h"
36 #include "hook.h"
37 #include "send.h"
39 static char readBuf[READBUF_SIZE];
40 static void client_dopacket(struct Client *client_p, char *buffer, size_t length);
44 * parse_client_queued - parse client queued messages
46 static void
47 parse_client_queued(struct Client *client_p)
49 int dolen = 0;
50 int checkflood = 1;
52 if(IsAnyDead(client_p))
53 return;
55 if(IsUnknown(client_p))
57 int i = 0;
59 for (;;)
61 /* rate unknown clients at MAX_FLOOD per loop */
62 if(i >= MAX_FLOOD)
63 break;
65 dolen = linebuf_get(&client_p->localClient->
66 buf_recvq, readBuf, READBUF_SIZE,
67 LINEBUF_COMPLETE, LINEBUF_PARSED);
69 if(dolen <= 0 || IsDead(client_p))
70 break;
72 client_dopacket(client_p, readBuf, dolen);
73 i++;
75 /* He's dead cap'n */
76 if(IsAnyDead(client_p))
77 return;
78 /* if theyve dropped out of the unknown state, break and move
79 * to the parsing for their appropriate status. --fl
81 if(!IsUnknown(client_p))
82 break;
87 if(IsAnyServer(client_p) || IsExemptFlood(client_p))
89 while (!IsAnyDead(client_p) && (dolen = linebuf_get(&client_p->localClient->buf_recvq,
90 readBuf, READBUF_SIZE, LINEBUF_COMPLETE,
91 LINEBUF_PARSED)) > 0)
93 client_dopacket(client_p, readBuf, dolen);
96 else if(IsClient(client_p))
99 if(IsOper(client_p) && ConfigFileEntry.no_oper_flood)
100 checkflood = 0;
102 * Handle flood protection here - if we exceed our flood limit on
103 * messages in this loop, we simply drop out of the loop prematurely.
104 * -- adrian
106 for (;;)
108 /* This flood protection works as follows:
110 * A client is given allow_read lines to send to the server. Every
111 * time a line is parsed, sent_parsed is increased. sent_parsed
112 * is decreased by 1 every time flood_recalc is called.
114 * Thus a client can 'burst' allow_read lines to the server, any
115 * excess lines will be parsed one per flood_recalc() call.
117 * Therefore a client will be penalised more if they keep flooding,
118 * as sent_parsed will always hover around the allow_read limit
119 * and no 'bursts' will be permitted.
121 if(checkflood)
123 if(client_p->localClient->sent_parsed >= client_p->localClient->allow_read)
124 break;
127 /* allow opers 4 times the amount of messages as users. why 4?
128 * why not. :) --fl_
130 else if(client_p->localClient->sent_parsed >= (4 * client_p->localClient->allow_read))
131 break;
133 dolen = linebuf_get(&client_p->localClient->
134 buf_recvq, readBuf, READBUF_SIZE,
135 LINEBUF_COMPLETE, LINEBUF_PARSED);
137 if(!dolen)
138 break;
140 client_dopacket(client_p, readBuf, dolen);
141 if(IsAnyDead(client_p))
142 return;
143 client_p->localClient->sent_parsed++;
148 /* flood_endgrace()
150 * marks the end of the clients grace period
152 void
153 flood_endgrace(struct Client *client_p)
155 SetFloodDone(client_p);
157 /* Drop their flood limit back down */
158 client_p->localClient->allow_read = MAX_FLOOD;
160 /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
161 * so reset it.
163 client_p->localClient->sent_parsed = 0;
167 * flood_recalc
169 * recalculate the number of allowed flood lines. this should be called
170 * once a second on any given client. We then attempt to flush some data.
172 void
173 flood_recalc(int fd, void *data)
175 struct Client *client_p = data;
176 struct LocalUser *lclient_p = client_p->localClient;
178 /* This can happen in the event that the client detached. */
179 if(!lclient_p)
180 return;
182 /* allow a bursting client their allocation per second, allow
183 * a client whos flooding an extra 2 per second
185 if(IsFloodDone(client_p))
186 lclient_p->sent_parsed -= 2;
187 else
188 lclient_p->sent_parsed = 0;
190 if(lclient_p->sent_parsed < 0)
191 lclient_p->sent_parsed = 0;
193 if(--lclient_p->actually_read < 0)
194 lclient_p->actually_read = 0;
196 parse_client_queued(client_p);
198 if(IsAnyDead(client_p))
199 return;
201 /* and finally, reset the flood check */
202 comm_setflush(fd, 1000, flood_recalc, client_p);
206 * read_ctrl_packet - Read a 'packet' of data from a servlink control
207 * link and process it.
209 void
210 read_ctrl_packet(int fd, void *data)
212 struct Client *server = data;
213 struct LocalUser *lserver = server->localClient;
214 struct SlinkRpl *reply;
215 int length = 0;
216 unsigned char tmp[2];
217 unsigned char *len = tmp;
218 struct SlinkRplDef *replydef;
219 #ifdef USE_IODEBUG_HOOKS
220 hook_data_int hdata;
221 #endif
223 s_assert(lserver != NULL);
224 if(IsAnyDead(server))
225 return;
227 reply = &lserver->slinkrpl;
230 if(!reply->command)
232 reply->gotdatalen = 0;
233 reply->readdata = 0;
234 reply->data = NULL;
236 length = read(fd, tmp, 1);
238 if(length <= 0)
240 if((length == -1) && ignoreErrno(errno))
241 goto nodata;
242 error_exit_client(server, length);
243 return;
246 reply->command = tmp[0];
249 for (replydef = slinkrpltab; replydef->handler; replydef++)
251 if((int)replydef->replyid == reply->command)
252 break;
255 /* we should be able to trust a local slink process...
256 * and if it sends an invalid command, that's a bug.. */
257 s_assert(replydef->handler);
259 if((replydef->flags & SLINKRPL_FLAG_DATA) && (reply->gotdatalen < 2))
261 /* we need a datalen u16 which we don't have yet... */
262 length = read(fd, len, (2 - reply->gotdatalen));
263 if(length <= 0)
265 if((length == -1) && ignoreErrno(errno))
266 goto nodata;
267 error_exit_client(server, length);
268 return;
271 if(reply->gotdatalen == 0)
273 reply->datalen = *len << 8;
274 reply->gotdatalen++;
275 length--;
276 len++;
278 if(length && (reply->gotdatalen == 1))
280 reply->datalen |= *len;
281 reply->gotdatalen++;
282 if(reply->datalen > 0)
283 reply->data = MyMalloc(reply->datalen);
286 if(reply->gotdatalen < 2)
287 return; /* wait for more data */
290 if(reply->readdata < reply->datalen) /* try to get any remaining data */
292 length = read(fd, (reply->data + reply->readdata),
293 (reply->datalen - reply->readdata));
294 if(length <= 0)
296 if((length == -1) && ignoreErrno(errno))
297 goto nodata;
298 error_exit_client(server, length);
299 return;
302 reply->readdata += length;
303 if(reply->readdata < reply->datalen)
304 return; /* wait for more data */
307 #ifdef USE_IODEBUG_HOOKS
308 hdata.client = server;
309 hdata.arg1 = NULL;
310 hdata.arg2 = reply->command;
311 hdata.data = NULL;
312 call_hook(h_iorecvctrl_id, &hdata);
313 #endif
315 /* we now have the command and any data, pass it off to the handler */
316 (*replydef->handler) (reply->command, reply->datalen, reply->data, server);
318 /* reset SlinkRpl */
319 if(reply->datalen > 0)
320 MyFree(reply->data);
321 reply->command = 0;
323 if(IsAnyDead(server))
324 return;
326 nodata:
327 /* If we get here, we need to register for another COMM_SELECT_READ */
328 comm_setselect(fd, FDLIST_SERVER, COMM_SELECT_READ, read_ctrl_packet, server, 0);
332 * read_packet - Read a 'packet' of data from a connection and process it.
334 void
335 read_packet(int fd, void *data)
337 struct Client *client_p = data;
338 struct LocalUser *lclient_p = client_p->localClient;
339 int length = 0;
340 int lbuf_len;
342 int binary = 0;
343 #ifdef USE_IODEBUG_HOOKS
344 hook_data_int hdata;
345 #endif
346 if(IsAnyDead(client_p))
347 return;
350 * Read some data. We *used to* do anti-flood protection here, but
351 * I personally think it makes the code too hairy to make sane.
352 * -- adrian
354 length = read(client_p->localClient->fd, readBuf, READBUF_SIZE);
356 if(length <= 0)
358 if((length == -1) && ignoreErrno(errno))
360 comm_setselect(client_p->localClient->fd, FDLIST_IDLECLIENT,
361 COMM_SELECT_READ, read_packet, client_p, 0);
362 return;
364 error_exit_client(client_p, length);
365 return;
368 #ifdef USE_IODEBUG_HOOKS
369 hdata.client = client_p;
370 hdata.arg1 = readBuf;
371 hdata.arg2 = length;
372 call_hook(h_iorecv_id, &hdata);
373 #endif
375 if(client_p->localClient->lasttime < CurrentTime)
376 client_p->localClient->lasttime = CurrentTime;
377 client_p->flags &= ~FLAGS_PINGSENT;
380 * Before we even think of parsing what we just read, stick
381 * it on the end of the receive queue and do it when its
382 * turn comes around.
384 if(IsHandshake(client_p) || IsUnknown(client_p))
385 binary = 1;
387 lbuf_len = linebuf_parse(&client_p->localClient->buf_recvq, readBuf, length, binary);
389 lclient_p->actually_read += lbuf_len;
391 if(IsAnyDead(client_p))
392 return;
394 /* Attempt to parse what we have */
395 parse_client_queued(client_p);
397 if(IsAnyDead(client_p))
398 return;
400 /* Check to make sure we're not flooding */
401 if(!IsAnyServer(client_p) &&
402 (linebuf_alloclen(&client_p->localClient->buf_recvq) > ConfigFileEntry.client_flood))
404 if(!(ConfigFileEntry.no_oper_flood && IsOper(client_p)))
406 exit_client(client_p, client_p, client_p, "Excess Flood");
407 return;
411 /* If we get here, we need to register for another COMM_SELECT_READ */
412 if(PARSE_AS_SERVER(client_p))
414 comm_setselect(client_p->localClient->fd, FDLIST_SERVER, COMM_SELECT_READ,
415 read_packet, client_p, 0);
417 else
419 comm_setselect(client_p->localClient->fd, FDLIST_IDLECLIENT,
420 COMM_SELECT_READ, read_packet, client_p, 0);
425 * client_dopacket - copy packet to client buf and parse it
426 * client_p - pointer to client structure for which the buffer data
427 * applies.
428 * buffer - pointr to the buffer containing the newly read data
429 * length - number of valid bytes of data in the buffer
431 * Note:
432 * It is implicitly assumed that dopacket is called only
433 * with client_p of "local" variation, which contains all the
434 * necessary fields (buffer etc..)
436 void
437 client_dopacket(struct Client *client_p, char *buffer, size_t length)
439 s_assert(client_p != NULL);
440 s_assert(buffer != NULL);
442 if(client_p == NULL || buffer == NULL)
443 return;
444 if(IsAnyDead(client_p))
445 return;
447 * Update messages received
449 ++me.localClient->receiveM;
450 ++client_p->localClient->receiveM;
453 * Update bytes received
455 client_p->localClient->receiveB += length;
457 if(client_p->localClient->receiveB > 1023)
459 client_p->localClient->receiveK += (client_p->localClient->receiveB >> 10);
460 client_p->localClient->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
463 me.localClient->receiveB += length;
465 if(me.localClient->receiveB > 1023)
467 me.localClient->receiveK += (me.localClient->receiveB >> 10);
468 me.localClient->receiveB &= 0x03ff;
471 parse(client_p, buffer, buffer + length);