ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/s_bsd.c
Revision: 2416
Committed: Sun Jul 21 15:07:43 2013 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 30006 byte(s)
Log Message:
- Add completed_connection()

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * s_bsd.c: Network functions.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 * Copyright (C) 1999 Thomas Helvey
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * $Id$
24 */
25
26 #include "stdinc.h"
27 #include <netinet/in_systm.h>
28 #include <netinet/ip.h>
29 #include <netinet/tcp.h>
30 #include <sys/uio.h>
31 #include "ircd_defs.h"
32 #include "list.h"
33 #include "s_bsd.h"
34 #include "parse.h"
35 #include "client.h"
36 #include "dbuf.h"
37 #include "irc_string.h"
38 #include "ircd.h"
39 #include "listener.h"
40 #include "numeric.h"
41 #include "packet.h"
42 #include "irc_res.h"
43 #include "restart.h"
44 #include "s_auth.h"
45 #include "conf.h"
46 #include "log.h"
47 #include "s_serv.h"
48 #include "send.h"
49 #include "memory.h"
50 #include "s_user.h"
51 #include "msgq.h"
52 #include "ioengine.h"
53 #include "dbuf.h"
54
55 #ifndef IOV_MAX
56 #define IOV_MAX 16 /**< Minimum required length of an iovec array */
57 #endif
58
59
60 dlink_list connection_list;
61
62 static void client_sock_callback(struct Event *);
63 static void client_timer_callback(struct Event *);
64
65 /** Temporary buffer for reading data from a peer. */
66 static char readbuf[SERVER_TCP_WINDOW];
67
68 /*
69 * report_error text constants
70 */
71 const char *const ACCEPT_ERROR_MSG = "error accepting connection for %s: %s";
72 const char *const BIND_ERROR_MSG = "bind error for %s: %s";
73 const char *const CONNECT_ERROR_MSG = "connect to host %s failed: %s";
74 const char *const CONNLIMIT_ERROR_MSG = "connect limit exceeded for %s: %s";
75 const char *const LISTEN_ERROR_MSG = "listen error for %s: %s";
76 const char *const NONB_ERROR_MSG = "error setting non-blocking for %s: %s";
77 const char *const PEERNAME_ERROR_MSG = "getpeername failed for %s: %s";
78 const char *const POLL_ERROR_MSG = "poll error for %s: %s";
79 const char *const REGISTER_ERROR_MSG = "registering %s: %s";
80 const char *const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
81 const char *const SELECT_ERROR_MSG = "select error for %s: %s";
82 const char *const SETBUFS_ERROR_MSG = "error setting buffer size for %s: %s";
83 const char *const SOCKET_ERROR_MSG = "error creating socket for %s: %s";
84 const char *const TOS_ERROR_MSG = "error setting TOS for %s: %s";
85
86
87 static int
88 is_blocked(int error)
89 {
90 return EWOULDBLOCK == error
91 #ifdef ENOMEM
92 || ENOMEM == error
93 #endif
94 #ifdef ENOBUFS
95 || ENOBUFS == error
96 #endif
97 || EAGAIN == error;
98 }
99
100 /* get_sockerr - get the error value from the socket or the current errno
101 *
102 * Get the *real* error from the socket (well try to anyway..).
103 * This may only work when SO_DEBUG is enabled but its worth the
104 * gamble anyway.
105 */
106 int
107 os_get_sockerr(int fd)
108 {
109 int errtmp = errno;
110 #ifdef SO_ERROR
111 int err = 0;
112 socklen_t len = sizeof(err);
113
114 if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len))
115 {
116 if (err)
117 errtmp = err;
118 }
119 errno = errtmp;
120 #endif
121 return errtmp;
122 }
123
124 /*
125 * setup_socket()
126 *
127 * Set the socket non-blocking, and other wonderful bits.
128 */
129 static void
130 setup_socket(int fd)
131 {
132 int opt = 1;
133
134 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
135
136 #ifdef IPTOS_LOWDELAY
137 opt = IPTOS_LOWDELAY;
138 setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
139 #endif
140
141 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
142 }
143
144 /** Mark a socket's address as reusable.
145 * @param[in] fd %Socket file descriptor to manipulate.
146 * @return Non-zero on success, or zero on failure.
147 */
148 int
149 os_set_reuseaddr(int fd)
150 {
151 unsigned int opt = 1;
152
153 return !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
154 }
155
156 /** Set a socket's send and receive buffer sizes.
157 * @param[in] fd %Socket file descriptor to manipulate.
158 * @param[in] ssize New send buffer size.
159 * @param[in] rsize New receive buffer size.
160 * @return Non-zero on success, or zero on failure.
161 */
162 int
163 os_set_sockbufs(int fd, unsigned int ssize, unsigned int rsize)
164 {
165 unsigned int sopt = ssize;
166 unsigned int ropt = rsize;
167
168 return !setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &ropt, sizeof(ropt)) &&
169 !setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sopt, sizeof(sopt));
170 }
171
172 /** Set a socket's "type of service" value.
173 * @param[in] fd %Socket file descriptor to manipulate.
174 * @param[in] tos New type of service value to use.
175 * @return Non-zero on success, or zero on failure.
176 */
177 int
178 os_set_tos(int fd, int tos)
179 {
180 #if defined(IP_TOS) && defined(IPPROTO_IP)
181 unsigned int opt = tos;
182
183 return !setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
184 #else
185 return 1;
186 #endif
187 }
188
189 /** Disable IP options on a socket.
190 * @param[in] fd %Socket file descriptor to manipulate.
191 * @return Non-zero on success, or zero on failure.
192 */
193 int
194 os_disable_options(int fd)
195 {
196 #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
197 return !setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0);
198 #else
199 return 1;
200 #endif
201 }
202
203 /** Start listening on a socket.
204 * @param[in] fd Disconnected file descriptor.
205 * @param[in] backlog Maximum number of un-accept()ed connections to keep.
206 * @return Non-zero on success; zero on error.
207 */
208 int
209 os_set_listen(int fd, int backlog)
210 {
211 return !listen(fd, backlog);
212 }
213
214 /** Attempt to read from a non-blocking socket.
215 * @param[in] fd File descriptor to read from.
216 * @param[out] buf Output buffer to read into.
217 * @param[in] length Number of bytes to read.
218 * @param[out] count_out Receives number of bytes actually read.
219 * @return An IOResult value indicating status.
220 */
221 IOResult
222 os_recv_nonb(int fd, char *buf, unsigned int length, unsigned int *count_out)
223 {
224 int res = 0;
225
226 assert(buf);
227 assert(count_out);
228
229 if ((res = recv(fd, buf, length, 0)) > 0)
230 {
231 *count_out = (unsigned int)res;
232 return IO_SUCCESS;
233 }
234
235 if (res == 0)
236 {
237 *count_out = 0;
238 errno = 0; /* Or ECONNRESET? */
239 return IO_FAILURE;
240 }
241
242 *count_out = 0;
243 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
244 }
245
246 /** Attempt to read from a non-blocking UDP socket.
247 * @param[in] fd File descriptor to read from.
248 * @param[out] buf Output buffer to read into.
249 * @param[in] length Number of bytes to read.
250 * @param[out] length_out Receives number of bytes actually read.
251 * @param[out] addr_out Peer address that sent the message.
252 * @return An IOResult value indicating status.
253 */
254 IOResult
255 os_recvfrom_nonb(int fd, char *buf, unsigned int length,
256 unsigned int *length_out,
257 struct irc_ssaddr *addr)
258 {
259 unsigned int len = sizeof(struct irc_ssaddr);
260 int res = 0;
261
262 assert(buf);
263 assert(length_out);
264 assert(addr_out);
265
266 res = recvfrom(fd, buf, length, 0, (struct sockaddr *)addr, &len);
267
268 if (res > -1)
269 {
270 *length_out = (unsigned int)res;
271 return IO_SUCCESS;
272 }
273
274 *length_out = 0;
275 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
276 }
277
278 /** Attempt to write on a connected socket.
279 * @param[in] fd File descriptor to write to.
280 * @param[in] buf Output buffer to send from.
281 * @param[in] length Number of bytes to write.
282 * @param[out] count_out Receives number of bytes actually written.
283 * @return An IOResult value indicating status.
284 */
285 IOResult
286 os_send_nonb(int fd, const char *buf, unsigned int length,
287 unsigned int *count_out)
288 {
289 int res = 0;
290
291 assert(buf);
292 assert(count_out);
293
294 if ((res = send(fd, buf, length, 0)) > -1)
295 {
296 *count_out = (unsigned int)res;
297 return IO_SUCCESS;
298 }
299
300 *count_out = 0;
301 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
302 }
303
304 /** Attempt a vectored write on a connected socket.
305 * @param[in] fd File descriptor to write to.
306 * @param[in] buf Message queue to send from.
307 * @param[out] count_in Number of bytes mapped from \a buf.
308 * @param[out] count_out Receives number of bytes actually written.
309 * @return An IOResult value indicating status.
310 */
311 IOResult
312 os_sendv_nonb(int fd, struct MsgQ *buf, unsigned int *count_in,
313 unsigned int *count_out)
314 {
315 int res = 0, count = 0;
316 struct iovec iov[IOV_MAX];
317
318 assert(buf);
319 assert(count_in);
320 assert(count_out);
321
322 *count_in = 0;
323 count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
324
325 if ((res = writev(fd, iov, count)) > -1)
326 {
327 *count_out = (unsigned int)res;
328 return IO_SUCCESS;
329 }
330
331 *count_out = 0;
332 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
333 }
334
335 /** Attempt to write on a non-blocking UDP socket.
336 * @param[in] fd File descriptor to write to.
337 * @param[in] buf Output buffer to send from.
338 * @param[in] length Number of bytes to write.
339 * @param[out] count_out Receives number of bytes actually written.
340 * @param[in] flags Flags for call to sendto().
341 * @param[in] peer Destination address of the message.
342 * @return An IOResult value indicating status.
343 */
344 IOResult os_sendto_nonb(int fd, const char *buf, unsigned int length,
345 unsigned int *count_out, unsigned int flags,
346 struct irc_ssaddr *peer)
347 {
348 int res = 0, size = 0;
349
350 assert(buf);
351
352 if ((res = sendto(fd, buf, length, flags, (struct sockaddr *)&peer, peer->ss_len)) > -1)
353 {
354 if (count_out)
355 *count_out = (unsigned int)res;
356 return IO_SUCCESS;
357 }
358
359 if (count_out)
360 *count_out = 0;
361 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
362 }
363
364 /** Start a non-blocking connection.
365 * @param[in] fd Disconnected file descriptor.
366 * @param[in] sin Target address for connection.
367 * @return IOResult code indicating status.
368 */
369 IOResult os_connect_nonb(int fd, const struct irc_ssaddr *addr)
370 {
371 int size;
372
373 // size = sockaddr_from_irc(&addr, sin, fd);
374 if (connect(fd, (struct sockaddr*) &addr, size))
375 return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
376 return IO_SUCCESS;
377 }
378
379 int
380 os_accept(int fd, struct irc_ssaddr *addr)
381 {
382 int new_fd = 0;
383 socklen_t addrlen = sizeof(struct irc_ssaddr);
384
385 new_fd = accept(fd, (struct sockaddr *)addr, &addrlen);
386 if (new_fd < 0)
387 return -1;
388
389 remove_ipv6_mapping(addr);
390 setup_socket(new_fd);
391 return new_fd;
392 }
393
394 int
395 os_socket(int family, int sock_type)
396 {
397 int fd;
398
399 fd = socket(family, sock_type, 0);
400 if (fd < 0)
401 return -1;
402 setup_socket(fd);
403 return fd;
404 }
405
406 /** Closes all file descriptors.
407 * @param close_stderr If non-zero, also close stderr.
408 */
409 void
410 close_connections(const int close_stderr)
411 {
412 int i = 0;
413
414 if (close_stderr)
415 {
416 close(0);
417 close(1);
418 close(2);
419 }
420
421 for (i = 3; i < 1024 /* XXX */; ++i)
422 close(i);
423 }
424
425 /*
426 * report_error - report an error from an errno.
427 * Record error to log and also send a copy to all *LOCAL* opers online.
428 *
429 * text is a *format* string for outputing error. It must
430 * contain only two '%s', the first will be replaced
431 * by the sockhost from the client_p, and the latter will
432 * be taken from sys_errlist[errno].
433 *
434 * client_p if not NULL, is the *LOCAL* client associated with
435 * the error.
436 *
437 * Cannot use perror() within daemon. stderr is closed in
438 * ircd and cannot be used. And, worse yet, it might have
439 * been reassigned to a normal connection...
440 *
441 * Actually stderr is still there IFF ircd was run with -s --Rodder
442 */
443
444 void
445 report_error(int level, const char *text, const char *who, int error)
446 {
447 int errtmp = errno; /* debug may change 'errno' */
448 const char *errmsg = (error) ? strerror(error) : "";
449
450 if (!errmsg)
451 errmsg = "Unknown error";
452
453 if (EmptyString(who))
454 who = "unknown";
455
456 sendto_realops_flags(UMODE_DEBUG, level, SEND_NOTICE,
457 text, who, errmsg);
458 ilog(LOG_TYPE_IRCD, text, who, errmsg);
459 errno = errtmp;
460 }
461
462 /** Complete non-blocking connect()-sequence. Check access and
463 * terminate connection, if trouble detected.
464 * @param client_p Client to which we have connected, with all ConfItem structs attached.
465 * @return Zero on failure (caller should exit_client()), non-zero on success.
466 */
467 static int
468 completed_connection(struct Client *client_p)
469 {
470 struct MaskItem *conf = NULL;
471
472 assert(client_p);
473
474 /*
475 * Get the socket status from the fd first to check if
476 * connection actually succeeded
477 */
478 if ((client_p->localClient->error = os_get_sockerr(s_fd(&client_p->localClient->socket))))
479 {
480 const char *msg = strerror(client_p->localClient->error);
481
482 if (!msg)
483 msg = "Unknown error";
484
485 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
486 "Connection failed to %s: %s",
487 get_client_name(client_p, HIDE_IP), msg);
488 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
489 "Connection failed to %s: %s",
490 get_client_name(client_p, MASK_IP), msg);
491 return 0;
492 }
493
494 conf = find_conf_name(&client_p->localClient->confs,
495 client_p->name, CONF_SERVER);
496 if (!conf)
497 {
498 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
499 "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
500 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
501 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
502 return 0;
503 }
504
505 if (s_state(&client_p->localClient->socket) == SS_CONNECTING)
506 socket_state(&client_p->localClient->socket, SS_CONNECTED);
507
508 if (!EmptyString(conf->spasswd))
509 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
510
511 send_capabilities(client_p, 0);
512
513 assert(client_p->serv);
514 SetHandshake(client_p);
515
516 /*
517 * Make us timeout after twice the timeout for DNS look ups
518 */
519 client_p->localClient->lasttime = CurrentTime;
520 AddFlag(client_p, FLAGS_PINGSENT);
521
522 sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
523 ConfigServerHide.hidden ? "(H) " : "", me.info);
524
525 return !IsDead(client_p);
526 }
527
528 /*
529 * close_connection
530 * Close the physical connection. This function must make
531 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
532 */
533 void
534 close_connection(struct Client *client_p)
535 {
536 dlink_node *ptr = NULL;
537
538 assert(client_p);
539
540 if (IsClient(client_p))
541 {
542 ++ServerStats.is_cl;
543 ServerStats.is_cbs += client_p->localClient->send.bytes;
544 ServerStats.is_cbr += client_p->localClient->recv.bytes;
545 ServerStats.is_cti += CurrentTime - client_p->localClient->firsttime;
546 }
547 else if (IsServer(client_p))
548 {
549 ++ServerStats.is_sv;
550 ServerStats.is_sbs += client_p->localClient->send.bytes;
551 ServerStats.is_sbr += client_p->localClient->recv.bytes;
552 ServerStats.is_sti += CurrentTime - client_p->localClient->firsttime;
553
554 DLINK_FOREACH(ptr, server_items.head)
555 {
556 struct MaskItem *conf = ptr->data;
557
558 if (irccmp(conf->name, client_p->name))
559 continue;
560
561 /*
562 * Reset next-connect cycle of all connect{} blocks that match
563 * this servername.
564 */
565 conf->until = CurrentTime + conf->class->con_freq;
566 }
567 }
568 else
569 ++ServerStats.is_ni;
570
571 if (s_fd(&client_p->localClient->socket)> -1)
572 {
573 flush_connections(client_p);
574 dlinkDelete(&client_p->localClient->node, &connection_list);
575 close(s_fd(&client_p->localClient->socket));
576 socket_del(&client_p->localClient->socket); /* Queue a socket delete */
577 s_fd(&client_p->localClient->socket) = -1;
578 }
579
580 AddFlag(client_p, FLAGS_DEADSOCKET);
581
582 MsgQClear(&client_p->localClient->sendQ);
583 client_drop_sendq(client_p->localClient);
584 DBufClear(&client_p->localClient->recvQ);
585
586 MyFree(client_p->localClient->passwd);
587 client_p->localClient->passwd = NULL;
588
589 detach_conf(client_p, CONF_CLIENT|CONF_OPER|CONF_SERVER);
590 client_p->from = NULL; /* ...this should catch them! >:) --msa */
591
592 if (client_p->localClient->listener)
593 {
594 assert(0 < client_p->localClient->listener->ref_count);
595 listener_release(client_p->localClient->listener);
596 client_p->localClient->listener = NULL;
597 }
598 }
599
600 /*
601 * add_connection - creates a client which has just connected to us on
602 * the given fd. The sockhost field is initialized with the ip# of the host.
603 * An unique id is calculated now, in case it is needed for auth.
604 * The client is sent to the auth module for verification, and not put in
605 * any client list yet.
606 */
607 void
608 add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
609 {
610 struct Client *new_client = make_client(NULL);
611
612 /*
613 * copy address to 'sockhost' as a string, copy it to host too
614 * so we have something valid to put into error messages...
615 */
616 memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
617
618 getnameinfo((struct sockaddr *)&new_client->localClient->ip,
619 new_client->localClient->ip.ss_len, new_client->sockhost,
620 sizeof(new_client->sockhost), NULL, 0, NI_NUMERICHOST);
621 new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
622
623 #ifdef HAVE_LIBGEOIP
624 /* XXX IPV6 SUPPORT XXX */
625 if (irn->ss.ss_family == AF_INET && geoip_ctx)
626 {
627 const struct sockaddr_in *v4 = (const struct sockaddr_in *)&new_client->localClient->ip;
628 new_client->localClient->country_id = GeoIP_id_by_ipnum(geoip_ctx, (unsigned long)ntohl(v4->sin_addr.s_addr));
629 }
630 #endif
631
632 if (new_client->sockhost[0] == ':' && new_client->sockhost[1] == ':')
633 {
634 strlcpy(new_client->host, "0", sizeof(new_client->host));
635 strlcpy(new_client->host+1, new_client->sockhost, sizeof(new_client->host)-1);
636 memmove(new_client->sockhost+1, new_client->sockhost, sizeof(new_client->sockhost)-1);
637 new_client->sockhost[0] = '0';
638 }
639 else
640 strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
641
642
643 s_fd(&new_client->localClient->socket) = fd;
644 if (!socket_add(&new_client->localClient->socket, client_sock_callback,
645 new_client->localClient, SS_CONNECTED, 0, fd))
646 {
647 ++ServerStats.is_ref;
648 // write(fd, register_message, strlen(register_message));
649 close(fd);
650 s_fd(&new_client->localClient->socket) = -1;
651 return;
652 }
653
654 new_client->localClient->freeflag |= FREEFLAG_SOCKET;
655 new_client->localClient->listener = listener;
656 ++listener->ref_count;
657
658 /* If we've made it this far we can put the client on the auth query pile */
659 start_auth(new_client);
660 }
661
662 /** Determines whether to tell the events engine we're interested in
663 * writable events.
664 * \param client_p Client for which to decide this.
665 */
666 void
667 update_write(struct Client *client_p)
668 {
669 /*
670 * If there are messages that need to be sent along, or if the client
671 * is in the middle of a /list, then we need to tell the engine that
672 * we're interested in writable events--otherwise, we need to drop
673 * that interest.
674 */
675 socket_events(&client_p->localClient->socket,
676 ((MsgQLength(&client_p->localClient->sendQ) || client_p->localClient->list_task) ?
677 SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
678 }
679
680 /** Read a 'packet' of data from a connection and process it. Read in
681 * 8k chunks to give a better performance rating (for server
682 * connections). Do some tricky stuff for client connections to make
683 * sure they don't do any flooding >:-) -avalon
684 * @param client_p Client from which to read data.
685 * @param socket_ready If non-zero, more data can be read from the client's socket.
686 * @return Positive number on success, zero on connection-fatal failure, negative
687 * if user is killed.
688 */
689 static int
690 read_packet(struct Client *client_p, int socket_ready)
691 {
692 unsigned int dolen = 0, length = 0;
693
694 if (socket_ready && !(IsClient(client_p) &&
695 DBufLength(&client_p->localClient->recvQ) > get_recvq(&client_p->localClient->confs)))
696 {
697 switch (os_recv_nonb(s_fd(&client_p->localClient->socket), readbuf, sizeof(readbuf), &length))
698 {
699 case IO_SUCCESS:
700 if (length)
701 {
702 client_p->localClient->lasttime = CurrentTime;
703
704 if (client_p->localClient->lasttime > client_p->localClient->since)
705 client_p->localClient->since = CurrentTime;
706
707 ClearPingSent(client_p);
708 DelFlag(client_p, FLAGS_NONEWLINE);
709 }
710 break;
711
712 case IO_BLOCKED:
713 break;
714 case IO_FAILURE:
715 client_p->localClient->error = errno;
716 /* AddFlag(client_p, FLAGS_DEADSOCKET); */
717 return 0;
718 }
719 }
720
721 /*
722 * For server connections, we process as many as we can without
723 * worrying about the time of day or anything :)
724 */
725 if (length > 0 && IsServer(client_p))
726 return server_dopacket(client_p, readbuf, length);
727 else if (length > 0 && (IsHandshake(client_p) || IsConnecting(client_p)))
728 return connect_dopacket(client_p, readbuf, length);
729 else
730 {
731 /*
732 * Before we even think of parsing what we just read, stick
733 * it on the end of the receive queue and do it when its
734 * turn comes around.
735 */
736 if (length > 0 && !dbuf_put(&client_p->localClient->recvQ, readbuf, length))
737 return exit_client(client_p, client_p, "dbuf_put fail");
738
739 if (DBufLength(&client_p->localClient->recvQ) > get_recvq(&client_p->localClient->confs))
740 return exit_client(client_p, client_p, "Excess Flood");
741
742 while (DBufLength(&client_p->localClient->recvQ) && !HasFlag(client_p, FLAGS_NONEWLINE) &&
743 (IsTrusted(client_p) || client_p->localClient->since - CurrentTime < 10))
744 {
745 dolen = dbuf_getmsg(&client_p->localClient->recvQ,
746 client_p->localClient->buffer, IRCD_BUFSIZE);
747
748 /*
749 * Devious looking...whats it do ? well..if a client
750 * sends a *long* message without any CR or LF, then
751 * dbuf_getmsg fails and we pull it out using this
752 * loop which just gets the next 512 bytes and then
753 * deletes the rest of the buffer contents.
754 * -avalon
755 */
756 if (dolen == 0)
757 {
758 if (DBufLength(&client_p->localClient->recvQ) < 510)
759 AddFlag(client_p, FLAGS_NONEWLINE);
760 else
761 {
762 /*
763 * More than 512 bytes in the line - drop the input and yell
764 * at the client.
765 */
766 DBufClear(&client_p->localClient->recvQ);
767 sendto_one(client_p, form_str(ERR_INPUTTOOLONG), me.name,
768 client_p->name[0] ? client_p->name : "*");
769 }
770 }
771 else if (client_dopacket(client_p, dolen) == CPTR_KILLED)
772 return CPTR_KILLED;
773
774 /*
775 * If it has become registered as a Server
776 * then skip the per-message parsing below.
777 */
778 if (IsHandshake(client_p) || IsServer(client_p))
779 {
780 while (-1)
781 {
782 dolen = dbuf_get(&client_p->localClient->recvQ, readbuf, sizeof(readbuf));
783
784 if (dolen <= 0)
785 return 1;
786 if (dolen == 0)
787 {
788 if (DBufLength(&client_p->localClient->recvQ) < 510)
789 AddFlag(client_p, FLAGS_NONEWLINE);
790 else
791 DBufClear(&client_p->localClient->recvQ);
792 }
793 else if ((IsServer(client_p) &&
794 server_dopacket(client_p, readbuf, dolen) == CPTR_KILLED) ||
795 (!IsServer(client_p) &&
796 connect_dopacket(client_p, readbuf, dolen) == CPTR_KILLED))
797 return CPTR_KILLED;
798 }
799 }
800 }
801
802 /* If there's still data to process, wait 2 seconds first */
803 if (DBufLength(&client_p->localClient->recvQ) && !HasFlag(client_p, FLAGS_NONEWLINE) &&
804 !t_onqueue(&client_p->localClient->proc))
805 {
806 client_p->localClient->freeflag |= FREEFLAG_TIMER;
807 timer_add(&client_p->localClient->proc, client_timer_callback, client_p->localClient,
808 TT_RELATIVE, 2);
809 }
810 }
811 return 1;
812 }
813
814 /** Attempt to send a sequence of bytes to the connection.
815 * As a side effect, updates \a client_p's FLAGS_BLOCKED setting
816 * and sendB/sendK fields.
817 * @param client_p Client that should receive data.
818 * @param buf Message buffer to send to client.
819 * @return Negative on connection-fatal error; otherwise
820 * number of bytes sent.
821 */
822 unsigned int
823 deliver_it(struct Client *client_p, struct MsgQ *buf)
824 {
825 unsigned int bytes_written = 0, bytes_count = 0;
826
827 assert(client_p);
828
829 switch (os_sendv_nonb(s_fd(&client_p->localClient->socket), buf, &bytes_count, &bytes_written))
830 {
831 case IO_SUCCESS:
832 DelFlag(client_p, FLAGS_BLOCKED);
833
834 client_p->localClient->send.bytes += bytes_written;
835 me.localClient->send.bytes += bytes_written;
836
837 /* A partial write implies that future writes will block. */
838 if (bytes_written < bytes_count)
839 AddFlag(client_p, FLAGS_BLOCKED);
840 break;
841 case IO_BLOCKED:
842 AddFlag(client_p, FLAGS_BLOCKED);
843 break;
844 case IO_FAILURE:
845 client_p->localClient->error = errno;
846 AddFlag(client_p, FLAGS_DEADSOCKET);
847 break;
848 }
849
850 return bytes_written;
851 }
852
853 /*
854 * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
855 * OSes with IPv6 mapping listening on both
856 * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
857 *
858 */
859 void
860 remove_ipv6_mapping(struct irc_ssaddr *addr)
861 {
862 if (addr->ss.ss_family == AF_INET6)
863 {
864 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr))
865 {
866 struct sockaddr_in6 v6;
867 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
868
869 memcpy(&v6, addr, sizeof(v6));
870 memset(v4, 0, sizeof(struct sockaddr_in));
871 memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr));
872
873 addr->ss.ss_family = AF_INET;
874 addr->ss_len = sizeof(struct sockaddr_in);
875 }
876 else
877 addr->ss_len = sizeof(struct sockaddr_in6);
878 }
879 else
880 addr->ss_len = sizeof(struct sockaddr_in);
881 }
882
883 /** Process events on a client socket.
884 * @param ev Socket event structure that has a struct Connection as
885 * its associated data.
886 */
887 static void
888 client_sock_callback(struct Event *ev)
889 {
890 struct Client *client_p = NULL;
891 struct Connection *con = NULL;
892 const char *fmt = "%s";
893 const char *fallback = NULL;
894
895 assert(ev_socket(ev));
896 assert(s_data(ev_socket(ev)));
897
898 con = s_data(ev_socket(ev));
899
900 assert(con->localClient || ev_type(ev) == ET_DESTROY);
901
902 client_p = con->client_p;
903
904 assert(!client_p || con == client_p->localClient);
905
906 switch (ev_type(ev))
907 {
908 case ET_DESTROY:
909 con->freeflag &= ~FREEFLAG_SOCKET;
910
911 if (!con->freeflag && !client_p)
912 free_connection(con);
913 break;
914
915 case ET_CONNECT: /* Socket connection completed */
916 if (!completed_connection(client_p) || IsDead(client_p))
917 fallback = client_p->info;
918 break;
919
920 case ET_ERROR: /* An error occurred */
921 fallback = client_p->info;
922 client_p->localClient->error = ev_data(ev);
923
924 /*
925 * If the OS told us we have a bad file descriptor, we should
926 * record that for future reference.
927 */
928 if (client_p->localClient->error == EBADF)
929 s_fd(&client_p->localClient->socket) = -1;
930
931 if (s_state(&con->socket) == SS_CONNECTING)
932 {
933 completed_connection(client_p);
934
935 /*
936 * For some reason, the os_get_sockerr() in completed_connect()
937 * can return 0 even when ev_data(ev) indicates a real error, so
938 * re-assign the client error here.
939 */
940 client_p->localClient->error = ev_data(ev);
941 break;
942 }
943
944 /*FALLTHROUGH*/
945 case ET_EOF: /* End of file on socket */
946 AddFlag(client_p, FLAGS_DEADSOCKET);
947
948 if ((IsServer(client_p) || IsHandshake(client_p)) && client_p->localClient->error == 0)
949 {
950 exit_client_msg(client_p, client_p, "Server %s closed the connection (%s)",
951 client_p->name, client_p->serv->last_error_msg);
952 return;
953 }
954 else
955 {
956 fmt = "Read error: %s";
957 fallback = "EOF from client";
958 }
959
960 break;
961
962 case ET_WRITE: /* Socket is writable */
963 DelFlag(client_p, FLAGS_BLOCKED);
964
965 if (client_p->localClient->list_task && MsgQLength(&client_p->localClient->sendQ) < 2048)
966 list_next_channels(client_p);
967 send_queued(client_p);
968 break;
969
970 case ET_READ: /* Socket is readable */
971 if (!IsDead(client_p))
972 {
973 if (read_packet(client_p, 1) == 0) /* Error while reading packet */
974 fallback = "EOF from client";
975 }
976
977 break;
978
979 default:
980 assert(0 && "Unrecognized socket event in client_sock_callback()");
981 break;
982 }
983
984 assert(!client_p || !client_p->localClient || con == client_p->localClient);
985
986 if (fallback)
987 {
988 const char *msg = (client_p->localClient->error) ? strerror(client_p->localClient->error) : fallback;
989
990 if (!msg)
991 msg = "Unknown error";
992 exit_client_msg(client_p, client_p, fmt, msg);
993 }
994 }
995
996 /** Process a timer on client socket.
997 * @param ev Timer event that has a struct Connection as its
998 * associated data.
999 */
1000 static void
1001 client_timer_callback(struct Event *ev)
1002 {
1003 struct Client *client_p = NULL;
1004 struct Connection *con = NULL;
1005
1006 assert(ev_timer(ev));
1007 assert(t_data(ev_timer(ev)));
1008 assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
1009
1010 con = t_data(ev_timer(ev));
1011
1012 assert(con->client || ev_type(ev) == ET_DESTROY);
1013
1014 client_p = con->client_p;
1015
1016 assert(!client_p || con == client_p->localClient);
1017
1018 if (ev_type(ev) == ET_DESTROY)
1019 {
1020 con->freeflag &= ~FREEFLAG_TIMER; /* Timer has expired... */
1021
1022 if (!con->freeflag && !client_p)
1023 free_connection(con); /* Client is being destroyed */
1024 }
1025 else
1026 read_packet(client_p, 0); /* read_packet will re-add timer if needed */
1027
1028 assert(!client_p || !client_p->localClient || con == client_p->localClient);
1029 }

Properties

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