ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 3107
Committed: Thu Mar 6 12:09:42 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 10587 byte(s)
Log Message:
- Applied dbuf changes as provided by Adam:
  Refcount dbufs instead of copying the same message to many
  different buffers.

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 2916 * Copyright (c) 1997-2014 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19     * USA
20     */
21 michael 2916
22     /*! \file packet.c
23     * \brief Packet handlers.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "s_bsd.h"
30 michael 1309 #include "conf.h"
31 adx 30 #include "s_serv.h"
32     #include "client.h"
33     #include "ircd.h"
34     #include "parse.h"
35     #include "fdlist.h"
36     #include "packet.h"
37     #include "irc_string.h"
38     #include "memory.h"
39     #include "hook.h"
40     #include "send.h"
41 michael 1243 #include "s_misc.h"
42 adx 30
43     #define READBUF_SIZE 16384
44    
45     static char readBuf[READBUF_SIZE];
46     static void client_dopacket(struct Client *, char *, size_t);
47    
48     /* extract_one_line()
49     *
50     * inputs - pointer to a dbuf queue
51     * - pointer to buffer to copy data to
52     * output - length of <buffer>
53     * side effects - one line is copied and removed from the dbuf
54     */
55     static int
56     extract_one_line(struct dbuf_queue *qptr, char *buffer)
57     {
58     int line_bytes = 0, empty_bytes = 0, phase = 0;
59 michael 3107 unsigned int idx = 0;
60     dlink_node *ptr = NULL;
61 adx 30
62     /*
63     * Phase 0: "empty" characters before the line
64     * Phase 1: copying the line
65     * Phase 2: "empty" characters after the line
66     * (delete them as well and free some space in the dbuf)
67     *
68     * Empty characters are CR, LF and space (but, of course, not
69     * in the middle of a line). We try to remove as much of them as we can,
70     * since they simply eat server memory.
71     *
72     * --adx
73     */
74     DLINK_FOREACH(ptr, qptr->blocks.head)
75     {
76 michael 3107 struct dbuf_block *block = ptr->data;
77 adx 30
78 michael 3107 if (ptr == qptr->blocks.head)
79     idx = qptr->pos;
80     else
81     idx = 0;
82    
83     for (; idx < block->size; ++idx)
84 adx 30 {
85 michael 3107 char c = block->data[idx];
86    
87 adx 30 if (IsEol(c) || (c == ' ' && phase != 1))
88     {
89 michael 3107 ++empty_bytes;
90 adx 30 if (phase == 1)
91     phase = 2;
92     }
93     else switch (phase)
94     {
95     case 0: phase = 1;
96     case 1: if (line_bytes++ < IRCD_BUFSIZE - 2)
97     *buffer++ = c;
98     break;
99     case 2: *buffer = '\0';
100     dbuf_delete(qptr, line_bytes + empty_bytes);
101     return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
102     }
103     }
104     }
105    
106     /*
107     * Now, if we haven't reached phase 2, ignore all line bytes
108     * that we have read, since this is a partial line case.
109     */
110     if (phase != 2)
111     line_bytes = 0;
112     else
113     *buffer = '\0';
114    
115     /* Remove what is now unnecessary */
116     dbuf_delete(qptr, line_bytes + empty_bytes);
117     return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
118     }
119     /*
120     * parse_client_queued - parse client queued messages
121     */
122     static void
123     parse_client_queued(struct Client *client_p)
124 michael 2916 {
125 adx 30 int dolen = 0;
126     int checkflood = 1;
127     struct LocalUser *lclient_p = client_p->localClient;
128    
129     if (IsUnknown(client_p))
130     {
131     int i = 0;
132    
133 michael 2916 for (; ;)
134 adx 30 {
135     if (IsDefunct(client_p))
136 michael 2916 return;
137 adx 30
138     /* rate unknown clients at MAX_FLOOD per loop */
139     if (i >= MAX_FLOOD)
140     break;
141    
142     dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
143     if (dolen == 0)
144 michael 2916 break;
145 adx 30
146     client_dopacket(client_p, readBuf, dolen);
147     i++;
148    
149     /* if they've dropped out of the unknown state, break and move
150     * to the parsing for their appropriate status. --fl
151     */
152     if(!IsUnknown(client_p))
153     break;
154     }
155     }
156    
157     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
158     {
159     while (1)
160     {
161     if (IsDefunct(client_p))
162     return;
163     if ((dolen = extract_one_line(&lclient_p->buf_recvq,
164     readBuf)) == 0)
165     break;
166     client_dopacket(client_p, readBuf, dolen);
167     }
168     }
169 adx 163 else if (IsClient(client_p))
170 adx 30 {
171 michael 1219 if (ConfigFileEntry.no_oper_flood && (HasUMode(client_p, UMODE_OPER) || IsCanFlood(client_p)))
172 adx 30 {
173     if (ConfigFileEntry.true_no_oper_flood)
174     checkflood = -1;
175     else
176     checkflood = 0;
177     }
178    
179     /*
180     * Handle flood protection here - if we exceed our flood limit on
181     * messages in this loop, we simply drop out of the loop prematurely.
182     * -- adrian
183     */
184 michael 2916 for (; ;)
185 adx 30 {
186     if (IsDefunct(client_p))
187 michael 2916 break;
188 adx 30
189     /* This flood protection works as follows:
190     *
191     * A client is given allow_read lines to send to the server. Every
192     * time a line is parsed, sent_parsed is increased. sent_parsed
193     * is decreased by 1 every time flood_recalc is called.
194     *
195     * Thus a client can 'burst' allow_read lines to the server, any
196     * excess lines will be parsed one per flood_recalc() call.
197     *
198     * Therefore a client will be penalised more if they keep flooding,
199     * as sent_parsed will always hover around the allow_read limit
200     * and no 'bursts' will be permitted.
201     */
202     if (checkflood > 0)
203     {
204     if(lclient_p->sent_parsed >= lclient_p->allow_read)
205     break;
206     }
207 michael 2916
208 adx 30 /* allow opers 4 times the amount of messages as users. why 4?
209     * why not. :) --fl_
210     */
211     else if (lclient_p->sent_parsed >= (4 * lclient_p->allow_read) &&
212     checkflood != -1)
213     break;
214    
215     dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
216     if (dolen == 0)
217     break;
218    
219     client_dopacket(client_p, readBuf, dolen);
220     lclient_p->sent_parsed++;
221     }
222     }
223     }
224    
225     /* flood_endgrace()
226     *
227     * marks the end of the clients grace period
228     */
229     void
230     flood_endgrace(struct Client *client_p)
231     {
232     SetFloodDone(client_p);
233    
234     /* Drop their flood limit back down */
235     client_p->localClient->allow_read = MAX_FLOOD;
236    
237     /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
238     * so reset it.
239     */
240     client_p->localClient->sent_parsed = 0;
241     }
242    
243     /*
244     * flood_recalc
245     *
246     * recalculate the number of allowed flood lines. this should be called
247     * once a second on any given client. We then attempt to flush some data.
248     */
249     void
250     flood_recalc(fde_t *fd, void *data)
251     {
252     struct Client *client_p = data;
253     struct LocalUser *lclient_p = client_p->localClient;
254 michael 2916
255 adx 30 /* allow a bursting client their allocation per second, allow
256     * a client whos flooding an extra 2 per second
257     */
258     if (IsFloodDone(client_p))
259     lclient_p->sent_parsed -= 2;
260     else
261     lclient_p->sent_parsed = 0;
262 michael 2916
263 adx 30 if (lclient_p->sent_parsed < 0)
264     lclient_p->sent_parsed = 0;
265 michael 2916
266 adx 30 parse_client_queued(client_p);
267 michael 2916
268 adx 30 /* And now, try flushing .. */
269     if (!IsDead(client_p))
270     {
271     /* and finally, reset the flood check */
272     comm_setflush(fd, 1000, flood_recalc, client_p);
273     }
274     }
275    
276     /*
277     * read_packet - Read a 'packet' of data from a connection and process it.
278     */
279     void
280     read_packet(fde_t *fd, void *data)
281     {
282     struct Client *client_p = data;
283     int length = 0;
284    
285     if (IsDefunct(client_p))
286     return;
287    
288     /*
289     * Read some data. We *used to* do anti-flood protection here, but
290     * I personally think it makes the code too hairy to make sane.
291     * -- adrian
292     */
293 michael 2916 do
294     {
295 adx 30 #ifdef HAVE_LIBCRYPTO
296     if (fd->ssl)
297     {
298     length = SSL_read(fd->ssl, readBuf, READBUF_SIZE);
299    
300     /* translate openssl error codes, sigh */
301     if (length < 0)
302     switch (SSL_get_error(fd->ssl, length))
303 michael 2881 {
304 adx 30 case SSL_ERROR_WANT_WRITE:
305 michael 2881 comm_setselect(fd, COMM_SELECT_WRITE, (PF *)sendq_unblocked, client_p, 0);
306     return;
307     case SSL_ERROR_WANT_READ:
308     errno = EWOULDBLOCK;
309 adx 30 case SSL_ERROR_SYSCALL:
310 michael 2881 break;
311 michael 428 case SSL_ERROR_SSL:
312     if (errno == EAGAIN)
313     break;
314 adx 30 default:
315 michael 2881 length = errno = 0;
316     }
317 adx 30 }
318     else
319     #endif
320     {
321     length = recv(fd->fd, readBuf, READBUF_SIZE, 0);
322     }
323    
324     if (length <= 0)
325     {
326     /*
327     * If true, then we can recover from this error. Just jump out of
328     * the loop and re-register a new io-request.
329     */
330     if (length < 0 && ignoreErrno(errno))
331     break;
332    
333     dead_link_on_read(client_p, length);
334     return;
335     }
336    
337 michael 3107 dbuf_put_raw(&client_p->localClient->buf_recvq, readBuf, length);
338 adx 30
339 michael 1241 if (client_p->localClient->lasttime < CurrentTime)
340     client_p->localClient->lasttime = CurrentTime;
341     if (client_p->localClient->lasttime > client_p->localClient->since)
342     client_p->localClient->since = CurrentTime;
343 adx 30 ClearPingSent(client_p);
344    
345     /* Attempt to parse what we have */
346     parse_client_queued(client_p);
347    
348     if (IsDefunct(client_p))
349     return;
350    
351     /* Check to make sure we're not flooding */
352     if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p))
353     && (dbuf_length(&client_p->localClient->buf_recvq) >
354 michael 1632 get_recvq(&client_p->localClient->confs)))
355 adx 30 {
356 michael 1219 if (!(ConfigFileEntry.no_oper_flood && HasUMode(client_p, UMODE_OPER)))
357 adx 30 {
358     exit_client(client_p, client_p, "Excess Flood");
359     return;
360     }
361     }
362     }
363     #ifdef HAVE_LIBCRYPTO
364     while (length == sizeof(readBuf) || fd->ssl);
365     #else
366     while (length == sizeof(readBuf));
367     #endif
368    
369     /* If we get here, we need to register for another COMM_SELECT_READ */
370     comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
371     }
372    
373     /*
374     * client_dopacket - copy packet to client buf and parse it
375     * client_p - pointer to client structure for which the buffer data
376     * applies.
377     * buffer - pointr to the buffer containing the newly read data
378     * length - number of valid bytes of data in the buffer
379     *
380     * Note:
381     * It is implicitly assumed that dopacket is called only
382     * with client_p of "local" variation, which contains all the
383     * necessary fields (buffer etc..)
384     */
385     static void
386     client_dopacket(struct Client *client_p, char *buffer, size_t length)
387     {
388 michael 2916 /*
389 adx 30 * Update messages received
390     */
391     ++me.localClient->recv.messages;
392     ++client_p->localClient->recv.messages;
393    
394 michael 2916 /*
395 adx 30 * Update bytes received
396     */
397     client_p->localClient->recv.bytes += length;
398     me.localClient->recv.bytes += length;
399    
400     parse(client_p, buffer, buffer + length);
401     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision