ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/packet.c
Revision: 5545
Committed: Thu Feb 12 14:13:34 2015 UTC (10 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 9505 byte(s)
Log Message:
- Fixed style in several places

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 5347 * Copyright (c) 1997-2015 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    
46 michael 4982
47     /*
48     * client_dopacket - copy packet to client buf and parse it
49     * client_p - pointer to client structure for which the buffer data
50     * applies.
51     * buffer - pointr to the buffer containing the newly read data
52     * length - number of valid bytes of data in the buffer
53     *
54     * Note:
55 michael 4989 * It is implicitly assumed that client_dopacket() is called only
56 michael 4982 * with client_p of "local" variation, which contains all the
57     * necessary fields (buffer etc..)
58     */
59     static void
60 michael 5422 client_dopacket(struct Client *client_p, char *buffer, unsigned int length)
61 michael 4982 {
62     /* Update messages received */
63     ++me.connection->recv.messages;
64     ++client_p->connection->recv.messages;
65    
66     /* Update bytes received */
67     client_p->connection->recv.bytes += length;
68     me.connection->recv.bytes += length;
69    
70     parse(client_p, buffer, buffer + length);
71     }
72    
73 adx 30 /* extract_one_line()
74     *
75     * inputs - pointer to a dbuf queue
76     * - pointer to buffer to copy data to
77     * output - length of <buffer>
78     * side effects - one line is copied and removed from the dbuf
79     */
80 michael 5422 static unsigned int
81 adx 30 extract_one_line(struct dbuf_queue *qptr, char *buffer)
82     {
83 michael 5422 unsigned int line_bytes = 0, eol_bytes = 0;
84 michael 5421 dlink_node *node;
85 adx 30
86 michael 5421 DLINK_FOREACH(node, qptr->blocks.head)
87 adx 30 {
88 michael 5421 const struct dbuf_block *block = node->data;
89 michael 5413 unsigned int idx;
90 adx 30
91 michael 5421 if (node == qptr->blocks.head)
92 michael 3107 idx = qptr->pos;
93     else
94     idx = 0;
95    
96     for (; idx < block->size; ++idx)
97 adx 30 {
98 michael 3107 char c = block->data[idx];
99    
100 michael 5413 if (IsEol(c))
101 adx 30 {
102 michael 5413 ++eol_bytes;
103 michael 3453
104 michael 5413 /* Allow 2 eol bytes per message */
105     if (eol_bytes == 2)
106     goto out;
107 adx 30 }
108 michael 5413 else if (eol_bytes)
109     goto out;
110     else if (line_bytes++ < IRCD_BUFSIZE - 2)
111     *buffer++ = c;
112 adx 30 }
113     }
114    
115 michael 5413 out:
116    
117 adx 30 /*
118 michael 5413 * Now, if we haven't found an EOL, ignore all line bytes
119 adx 30 * that we have read, since this is a partial line case.
120     */
121 michael 5413 if (eol_bytes)
122     *buffer = '\0';
123     else
124 adx 30 line_bytes = 0;
125    
126     /* Remove what is now unnecessary */
127 michael 5413 dbuf_delete(qptr, line_bytes + eol_bytes);
128    
129 adx 30 return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
130     }
131 michael 5413
132 adx 30 /*
133     * parse_client_queued - parse client queued messages
134     */
135     static void
136     parse_client_queued(struct Client *client_p)
137 michael 2916 {
138 michael 5422 unsigned int dolen = 0;
139 adx 30
140     if (IsUnknown(client_p))
141     {
142 michael 4982 unsigned int i = 0;
143 adx 30
144 michael 3453 while (1)
145 adx 30 {
146     if (IsDefunct(client_p))
147 michael 2916 return;
148 adx 30
149 michael 4982 /* Rate unknown clients at MAX_FLOOD per loop */
150 adx 30 if (i >= MAX_FLOOD)
151     break;
152    
153 michael 4982 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
154 michael 4890
155 adx 30 if (dolen == 0)
156 michael 2916 break;
157 adx 30
158     client_dopacket(client_p, readBuf, dolen);
159 michael 4982 ++i;
160 adx 30
161 michael 4982 /*
162     * If they've dropped out of the unknown state, break and move
163 adx 30 * to the parsing for their appropriate status. --fl
164     */
165 michael 3453 if (!IsUnknown(client_p))
166 adx 30 break;
167     }
168     }
169    
170     if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
171     {
172     while (1)
173     {
174     if (IsDefunct(client_p))
175     return;
176 michael 4890
177 michael 4982 if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
178 adx 30 break;
179 michael 3453
180 adx 30 client_dopacket(client_p, readBuf, dolen);
181     }
182     }
183 adx 163 else if (IsClient(client_p))
184 adx 30 {
185 michael 4989 unsigned int checkflood = 1;
186 adx 30
187 michael 4989 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
188     checkflood = 0;
189     else if (IsCanFlood(client_p))
190     checkflood = 0;
191    
192 adx 30 /*
193 michael 5545 * Handle flood protection here - if we exceed our flood limit on messages
194     * in this loop, we simply drop out of the loop prematurely.
195 adx 30 * -- adrian
196     */
197 michael 3453 while (1)
198 adx 30 {
199     if (IsDefunct(client_p))
200 michael 2916 break;
201 adx 30
202 michael 4982 /*
203     * This flood protection works as follows:
204 adx 30 *
205     * A client is given allow_read lines to send to the server. Every
206     * time a line is parsed, sent_parsed is increased. sent_parsed
207     * is decreased by 1 every time flood_recalc is called.
208     *
209     * Thus a client can 'burst' allow_read lines to the server, any
210     * excess lines will be parsed one per flood_recalc() call.
211     *
212     * Therefore a client will be penalised more if they keep flooding,
213     * as sent_parsed will always hover around the allow_read limit
214     * and no 'bursts' will be permitted.
215     */
216 michael 4989 if (checkflood)
217 michael 4982 if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
218 adx 30 break;
219 michael 2916
220 michael 4982 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
221 michael 4890
222 adx 30 if (dolen == 0)
223     break;
224    
225     client_dopacket(client_p, readBuf, dolen);
226 michael 4982 ++client_p->connection->sent_parsed;
227 adx 30 }
228     }
229     }
230    
231     /* flood_endgrace()
232     *
233     * marks the end of the clients grace period
234     */
235     void
236     flood_endgrace(struct Client *client_p)
237     {
238     SetFloodDone(client_p);
239    
240     /* Drop their flood limit back down */
241 michael 4588 client_p->connection->allow_read = MAX_FLOOD;
242 adx 30
243 michael 4982 /*
244     * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
245 adx 30 * so reset it.
246     */
247 michael 4588 client_p->connection->sent_parsed = 0;
248 adx 30 }
249    
250     /*
251     * flood_recalc
252     *
253     * recalculate the number of allowed flood lines. this should be called
254     * once a second on any given client. We then attempt to flush some data.
255     */
256     void
257     flood_recalc(fde_t *fd, void *data)
258     {
259 michael 4982 struct Client *const client_p = data;
260 michael 2916
261 michael 4890 /*
262     * Allow a bursting client their allocation per second, allow
263 adx 30 * a client whos flooding an extra 2 per second
264     */
265     if (IsFloodDone(client_p))
266 michael 4982 client_p->connection->sent_parsed -= 2;
267 adx 30 else
268 michael 4982 client_p->connection->sent_parsed = 0;
269 michael 2916
270 michael 4982 if (client_p->connection->sent_parsed < 0)
271     client_p->connection->sent_parsed = 0;
272 michael 2916
273 adx 30 parse_client_queued(client_p);
274 michael 2916
275 adx 30 /* And now, try flushing .. */
276     if (!IsDead(client_p))
277     {
278     /* and finally, reset the flood check */
279     comm_setflush(fd, 1000, flood_recalc, client_p);
280     }
281     }
282    
283     /*
284     * read_packet - Read a 'packet' of data from a connection and process it.
285     */
286     void
287     read_packet(fde_t *fd, void *data)
288     {
289 michael 4982 struct Client *const client_p = data;
290 adx 30 int length = 0;
291    
292     if (IsDefunct(client_p))
293     return;
294    
295     /*
296     * Read some data. We *used to* do anti-flood protection here, but
297     * I personally think it makes the code too hairy to make sane.
298     * -- adrian
299     */
300 michael 2916 do
301     {
302 adx 30 #ifdef HAVE_LIBCRYPTO
303     if (fd->ssl)
304     {
305 michael 3453 length = SSL_read(fd->ssl, readBuf, sizeof(readBuf));
306 adx 30
307     /* translate openssl error codes, sigh */
308     if (length < 0)
309     switch (SSL_get_error(fd->ssl, length))
310 michael 2881 {
311 adx 30 case SSL_ERROR_WANT_WRITE:
312 michael 4461 comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
313 michael 2881 return;
314     case SSL_ERROR_WANT_READ:
315     errno = EWOULDBLOCK;
316 adx 30 case SSL_ERROR_SYSCALL:
317 michael 2881 break;
318 michael 428 case SSL_ERROR_SSL:
319     if (errno == EAGAIN)
320     break;
321 adx 30 default:
322 michael 2881 length = errno = 0;
323     }
324 adx 30 }
325     else
326     #endif
327     {
328 michael 3453 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
329 adx 30 }
330    
331     if (length <= 0)
332     {
333     /*
334 michael 5545 * If true, then we can recover from this error. Just jump out of
335 adx 30 * the loop and re-register a new io-request.
336     */
337     if (length < 0 && ignoreErrno(errno))
338     break;
339    
340     dead_link_on_read(client_p, length);
341     return;
342     }
343    
344 michael 4588 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
345 adx 30
346 michael 4588 if (client_p->connection->lasttime < CurrentTime)
347     client_p->connection->lasttime = CurrentTime;
348 michael 4890
349 michael 4588 if (client_p->connection->lasttime > client_p->connection->since)
350     client_p->connection->since = CurrentTime;
351 michael 3453
352 adx 30 ClearPingSent(client_p);
353    
354     /* Attempt to parse what we have */
355     parse_client_queued(client_p);
356    
357     if (IsDefunct(client_p))
358     return;
359    
360     /* Check to make sure we're not flooding */
361 michael 4989 if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) &&
362     (dbuf_length(&client_p->connection->buf_recvq) >
363     get_recvq(&client_p->connection->confs)))
364 adx 30 {
365 michael 4989 exit_client(client_p, "Excess Flood");
366     return;
367 adx 30 }
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     }

Properties

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