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

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2015 ircd-hybrid development team
5 *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file packet.c
23 * \brief Packet handlers.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "s_bsd.h"
30 #include "conf.h"
31 #include "server.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 "send.h"
40 #include "misc.h"
41
42 #define READBUF_SIZE 16384
43
44 static char readBuf[READBUF_SIZE];
45
46
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 * It is implicitly assumed that client_dopacket() is called only
56 * with client_p of "local" variation, which contains all the
57 * necessary fields (buffer etc..)
58 */
59 static void
60 client_dopacket(struct Client *client_p, char *buffer, unsigned int length)
61 {
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 /* 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 static unsigned int
81 extract_one_line(struct dbuf_queue *qptr, char *buffer)
82 {
83 unsigned int line_bytes = 0, eol_bytes = 0;
84 dlink_node *node;
85
86 DLINK_FOREACH(node, qptr->blocks.head)
87 {
88 const struct dbuf_block *block = node->data;
89 unsigned int idx;
90
91 if (node == qptr->blocks.head)
92 idx = qptr->pos;
93 else
94 idx = 0;
95
96 for (; idx < block->size; ++idx)
97 {
98 char c = block->data[idx];
99
100 if (IsEol(c))
101 {
102 ++eol_bytes;
103
104 /* Allow 2 eol bytes per message */
105 if (eol_bytes == 2)
106 goto out;
107 }
108 else if (eol_bytes)
109 goto out;
110 else if (line_bytes++ < IRCD_BUFSIZE - 2)
111 *buffer++ = c;
112 }
113 }
114
115 out:
116
117 /*
118 * Now, if we haven't found an EOL, ignore all line bytes
119 * that we have read, since this is a partial line case.
120 */
121 if (eol_bytes)
122 *buffer = '\0';
123 else
124 line_bytes = 0;
125
126 /* Remove what is now unnecessary */
127 dbuf_delete(qptr, line_bytes + eol_bytes);
128
129 return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
130 }
131
132 /*
133 * parse_client_queued - parse client queued messages
134 */
135 static void
136 parse_client_queued(struct Client *client_p)
137 {
138 unsigned int dolen = 0;
139
140 if (IsUnknown(client_p))
141 {
142 unsigned int i = 0;
143
144 while (1)
145 {
146 if (IsDefunct(client_p))
147 return;
148
149 /* Rate unknown clients at MAX_FLOOD per loop */
150 if (i >= MAX_FLOOD)
151 break;
152
153 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
154
155 if (dolen == 0)
156 break;
157
158 client_dopacket(client_p, readBuf, dolen);
159 ++i;
160
161 /*
162 * If they've dropped out of the unknown state, break and move
163 * to the parsing for their appropriate status. --fl
164 */
165 if (!IsUnknown(client_p))
166 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
177 if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
178 break;
179
180 client_dopacket(client_p, readBuf, dolen);
181 }
182 }
183 else if (IsClient(client_p))
184 {
185 unsigned int checkflood = 1;
186
187 if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
188 checkflood = 0;
189 else if (IsCanFlood(client_p))
190 checkflood = 0;
191
192 /*
193 * 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 * -- adrian
196 */
197 while (1)
198 {
199 if (IsDefunct(client_p))
200 break;
201
202 /*
203 * This flood protection works as follows:
204 *
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 if (checkflood)
217 if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
218 break;
219
220 dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
221
222 if (dolen == 0)
223 break;
224
225 client_dopacket(client_p, readBuf, dolen);
226 ++client_p->connection->sent_parsed;
227 }
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 client_p->connection->allow_read = MAX_FLOOD;
242
243 /*
244 * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
245 * so reset it.
246 */
247 client_p->connection->sent_parsed = 0;
248 }
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 struct Client *const client_p = data;
260
261 /*
262 * Allow a bursting client their allocation per second, allow
263 * a client whos flooding an extra 2 per second
264 */
265 if (IsFloodDone(client_p))
266 client_p->connection->sent_parsed -= 2;
267 else
268 client_p->connection->sent_parsed = 0;
269
270 if (client_p->connection->sent_parsed < 0)
271 client_p->connection->sent_parsed = 0;
272
273 parse_client_queued(client_p);
274
275 /* 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 struct Client *const client_p = data;
290 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 do
301 {
302 #ifdef HAVE_LIBCRYPTO
303 if (fd->ssl)
304 {
305 length = SSL_read(fd->ssl, readBuf, sizeof(readBuf));
306
307 /* translate openssl error codes, sigh */
308 if (length < 0)
309 switch (SSL_get_error(fd->ssl, length))
310 {
311 case SSL_ERROR_WANT_WRITE:
312 comm_setselect(fd, COMM_SELECT_WRITE, sendq_unblocked, client_p, 0);
313 return;
314 case SSL_ERROR_WANT_READ:
315 errno = EWOULDBLOCK;
316 case SSL_ERROR_SYSCALL:
317 break;
318 case SSL_ERROR_SSL:
319 if (errno == EAGAIN)
320 break;
321 default:
322 length = errno = 0;
323 }
324 }
325 else
326 #endif
327 {
328 length = recv(fd->fd, readBuf, sizeof(readBuf), 0);
329 }
330
331 if (length <= 0)
332 {
333 /*
334 * If true, then we can recover from this error. Just jump out of
335 * 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 dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
345
346 if (client_p->connection->lasttime < CurrentTime)
347 client_p->connection->lasttime = CurrentTime;
348
349 if (client_p->connection->lasttime > client_p->connection->since)
350 client_p->connection->since = CurrentTime;
351
352 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 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 {
365 exit_client(client_p, "Excess Flood");
366 return;
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 }

Properties

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