ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 4894
Committed: Wed Nov 19 17:16:06 2014 UTC (10 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 10513 byte(s)
Log Message:
- Fixed compile warning

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 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * 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 michael 3347 #include "server.h"
32 adx 30 #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 "send.h"
40 michael 3347 #include "misc.h"
41 adx 30
42     #define READBUF_SIZE 16384
43    
44     static char readBuf[READBUF_SIZE];
45     static void client_dopacket(struct Client *, char *, size_t);
46    
47     /* extract_one_line()
48     *
49     * inputs - pointer to a dbuf queue
50     * - pointer to buffer to copy data to
51     * output - length of <buffer>
52     * side effects - one line is copied and removed from the dbuf
53     */
54     static int
55     extract_one_line(struct dbuf_queue *qptr, char *buffer)
56     {
57     int line_bytes = 0, empty_bytes = 0, phase = 0;
58 michael 3107 unsigned int idx = 0;
59 michael 4815 dlink_node *node = NULL;
60 adx 30
61     /*
62     * Phase 0: "empty" characters before the line
63     * Phase 1: copying the line
64     * Phase 2: "empty" characters after the line
65     * (delete them as well and free some space in the dbuf)
66     *
67     * Empty characters are CR, LF and space (but, of course, not
68     * in the middle of a line). We try to remove as much of them as we can,
69     * since they simply eat server memory.
70     *
71     * --adx
72     */
73 michael 4815 DLINK_FOREACH(node, qptr->blocks.head)
74 adx 30 {
75 michael 4815 struct dbuf_block *block = node->data;
76 adx 30
77 michael 4815 if (node == qptr->blocks.head)
78 michael 3107 idx = qptr->pos;
79     else
80     idx = 0;
81    
82     for (; idx < block->size; ++idx)
83 adx 30 {
84 michael 3107 char c = block->data[idx];
85    
86 adx 30 if (IsEol(c) || (c == ' ' && phase != 1))
87     {
88 michael 3107 ++empty_bytes;
89 michael 3453
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 michael 4588 struct Connection *lclient_p = client_p->connection;
128 adx 30
129     if (IsUnknown(client_p))
130     {
131     int i = 0;
132    
133 michael 3453 while (1)
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 michael 4890
144 adx 30 if (dolen == 0)
145 michael 2916 break;
146 adx 30
147     client_dopacket(client_p, readBuf, dolen);
148     i++;
149    
150     /* if they've dropped out of the unknown state, break and move
151     * to the parsing for their appropriate status. --fl
152     */
153 michael 3453 if (!IsUnknown(client_p))
154 adx 30 break;
155     }
156     }
157    
158     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
159     {
160     while (1)
161     {
162     if (IsDefunct(client_p))
163     return;
164 michael 4890
165 michael 3453 if ((dolen = extract_one_line(&lclient_p->buf_recvq, readBuf)) == 0)
166 adx 30 break;
167 michael 3453
168 adx 30 client_dopacket(client_p, readBuf, dolen);
169     }
170     }
171 adx 163 else if (IsClient(client_p))
172 adx 30 {
173 michael 4340 if (ConfigGeneral.no_oper_flood && (HasUMode(client_p, UMODE_OPER) || IsCanFlood(client_p)))
174 adx 30 {
175 michael 4340 if (ConfigGeneral.true_no_oper_flood)
176 adx 30 checkflood = -1;
177     else
178     checkflood = 0;
179     }
180    
181     /*
182     * Handle flood protection here - if we exceed our flood limit on
183     * messages in this loop, we simply drop out of the loop prematurely.
184     * -- adrian
185     */
186 michael 3453 while (1)
187 adx 30 {
188     if (IsDefunct(client_p))
189 michael 2916 break;
190 adx 30
191     /* This flood protection works as follows:
192     *
193     * A client is given allow_read lines to send to the server. Every
194     * time a line is parsed, sent_parsed is increased. sent_parsed
195     * is decreased by 1 every time flood_recalc is called.
196     *
197     * Thus a client can 'burst' allow_read lines to the server, any
198     * excess lines will be parsed one per flood_recalc() call.
199     *
200     * Therefore a client will be penalised more if they keep flooding,
201     * as sent_parsed will always hover around the allow_read limit
202     * and no 'bursts' will be permitted.
203     */
204     if (checkflood > 0)
205 michael 4894 {
206 michael 3453 if (lclient_p->sent_parsed >= lclient_p->allow_read)
207 adx 30 break;
208 michael 4894 }
209 michael 2916
210 michael 4890 /*
211     * Allow opers 4 times the amount of messages as users. why 4?
212 adx 30 * why not. :) --fl_
213     */
214 michael 3453 else if (lclient_p->sent_parsed >= (4 * lclient_p->allow_read) && checkflood != -1)
215 adx 30 break;
216    
217     dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
218 michael 4890
219 adx 30 if (dolen == 0)
220     break;
221    
222     client_dopacket(client_p, readBuf, dolen);
223     lclient_p->sent_parsed++;
224     }
225     }
226     }
227    
228     /* flood_endgrace()
229     *
230     * marks the end of the clients grace period
231     */
232     void
233     flood_endgrace(struct Client *client_p)
234     {
235     SetFloodDone(client_p);
236    
237     /* Drop their flood limit back down */
238 michael 4588 client_p->connection->allow_read = MAX_FLOOD;
239 adx 30
240     /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
241     * so reset it.
242     */
243 michael 4588 client_p->connection->sent_parsed = 0;
244 adx 30 }
245    
246     /*
247     * flood_recalc
248     *
249     * recalculate the number of allowed flood lines. this should be called
250     * once a second on any given client. We then attempt to flush some data.
251     */
252     void
253     flood_recalc(fde_t *fd, void *data)
254     {
255     struct Client *client_p = data;
256 michael 4588 struct Connection *lclient_p = client_p->connection;
257 michael 2916
258 michael 4890 /*
259     * Allow a bursting client their allocation per second, allow
260 adx 30 * a client whos flooding an extra 2 per second
261     */
262     if (IsFloodDone(client_p))
263     lclient_p->sent_parsed -= 2;
264     else
265     lclient_p->sent_parsed = 0;
266 michael 2916
267 adx 30 if (lclient_p->sent_parsed < 0)
268     lclient_p->sent_parsed = 0;
269 michael 2916
270 adx 30 parse_client_queued(client_p);
271 michael 2916
272 adx 30 /* And now, try flushing .. */
273     if (!IsDead(client_p))
274     {
275     /* and finally, reset the flood check */
276     comm_setflush(fd, 1000, flood_recalc, client_p);
277     }
278     }
279    
280     /*
281     * read_packet - Read a 'packet' of data from a connection and process it.
282     */
283     void
284     read_packet(fde_t *fd, void *data)
285     {
286     struct Client *client_p = data;
287     int length = 0;
288    
289     if (IsDefunct(client_p))
290     return;
291    
292     /*
293     * Read some data. We *used to* do anti-flood protection here, but
294     * I personally think it makes the code too hairy to make sane.
295     * -- adrian
296     */
297 michael 2916 do
298     {
299 adx 30 #ifdef HAVE_LIBCRYPTO
300     if (fd->ssl)
301     {
302 michael 3453 length = SSL_read(fd->ssl, readBuf, sizeof(readBuf));
303 adx 30
304     /* translate openssl error codes, sigh */
305     if (length < 0)
306     switch (SSL_get_error(fd->ssl, length))
307 michael 2881 {
308 adx 30 case SSL_ERROR_WANT_WRITE:
309 michael 4461 comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
310 michael 2881 return;
311     case SSL_ERROR_WANT_READ:
312     errno = EWOULDBLOCK;
313 adx 30 case SSL_ERROR_SYSCALL:
314 michael 2881 break;
315 michael 428 case SSL_ERROR_SSL:
316     if (errno == EAGAIN)
317     break;
318 adx 30 default:
319 michael 2881 length = errno = 0;
320     }
321 adx 30 }
322     else
323     #endif
324     {
325 michael 3453 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
326 adx 30 }
327    
328     if (length <= 0)
329     {
330     /*
331     * If true, then we can recover from this error. Just jump out of
332     * the loop and re-register a new io-request.
333     */
334     if (length < 0 && ignoreErrno(errno))
335     break;
336    
337     dead_link_on_read(client_p, length);
338     return;
339     }
340    
341 michael 4588 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
342 adx 30
343 michael 4588 if (client_p->connection->lasttime < CurrentTime)
344     client_p->connection->lasttime = CurrentTime;
345 michael 4890
346 michael 4588 if (client_p->connection->lasttime > client_p->connection->since)
347     client_p->connection->since = CurrentTime;
348 michael 3453
349 adx 30 ClearPingSent(client_p);
350    
351     /* Attempt to parse what we have */
352     parse_client_queued(client_p);
353    
354     if (IsDefunct(client_p))
355     return;
356    
357     /* Check to make sure we're not flooding */
358     if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p))
359 michael 4588 && (dbuf_length(&client_p->connection->buf_recvq) >
360     get_recvq(&client_p->connection->confs)))
361 adx 30 {
362 michael 4340 if (!(ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER)))
363 adx 30 {
364 michael 3171 exit_client(client_p, "Excess Flood");
365 adx 30 return;
366     }
367     }
368     }
369     #ifdef HAVE_LIBCRYPTO
370     while (length == sizeof(readBuf) || fd->ssl);
371     #else
372     while (length == sizeof(readBuf));
373     #endif
374    
375     /* If we get here, we need to register for another COMM_SELECT_READ */
376     comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
377     }
378    
379     /*
380     * client_dopacket - copy packet to client buf and parse it
381     * client_p - pointer to client structure for which the buffer data
382     * applies.
383     * buffer - pointr to the buffer containing the newly read data
384     * length - number of valid bytes of data in the buffer
385     *
386     * Note:
387     * It is implicitly assumed that dopacket is called only
388     * with client_p of "local" variation, which contains all the
389     * necessary fields (buffer etc..)
390     */
391     static void
392     client_dopacket(struct Client *client_p, char *buffer, size_t length)
393     {
394 michael 2916 /*
395 adx 30 * Update messages received
396     */
397 michael 4588 ++me.connection->recv.messages;
398     ++client_p->connection->recv.messages;
399 adx 30
400 michael 2916 /*
401 adx 30 * Update bytes received
402     */
403 michael 4588 client_p->connection->recv.bytes += length;
404     me.connection->recv.bytes += length;
405 adx 30
406     parse(client_p, buffer, buffer + length);
407     }

Properties

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