/[svn]/branches/newio/src/s_bsd.c
ViewVC logotype

Contents of /branches/newio/src/s_bsd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2415 - (show annotations)
Sun Jul 21 14:33:22 2013 UTC (6 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 27816 byte(s)
- ioengine changes as of 21JUL13

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28