ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/s_bsd.c
Revision: 2456
Committed: Wed Aug 14 17:46:30 2013 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 41257 byte(s)
Log Message:
- ioengine changes as of 14AUG13

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 1997-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 /*! \file s_bsd.c
23 * \brief Network functions.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include <netinet/in_systm.h>
29 #include <netinet/ip.h>
30 #include <netinet/tcp.h>
31 #include <sys/uio.h>
32 #include "ircd_defs.h"
33 #include "list.h"
34 #include "s_bsd.h"
35 #include "parse.h"
36 #include "client.h"
37 #include "dbuf.h"
38 #include "irc_string.h"
39 #include "ircd.h"
40 #include "listener.h"
41 #include "numeric.h"
42 #include "packet.h"
43 #include "irc_res.h"
44 #include "restart.h"
45 #include "s_auth.h"
46 #include "conf.h"
47 #include "log.h"
48 #include "s_serv.h"
49 #include "send.h"
50 #include "memory.h"
51 #include "s_user.h"
52 #include "msgq.h"
53 #include "ioengine.h"
54 #include "dbuf.h"
55 #include "hash.h"
56 #include "ssl.h"
57
58
59 #ifndef IOV_MAX
60 #define IOV_MAX 16 /**< Minimum required length of an iovec array */
61 #endif
62
63
64 dlink_list connection_list;
65
66 static void client_sock_callback(struct Event *);
67 static void client_timer_callback(struct Event *);
68
69 /** Temporary buffer for reading data from a peer. */
70 static char readbuf[SERVER_TCP_WINDOW];
71
72 /*
73 * report_error text constants
74 */
75 const char *const ACCEPT_ERROR_MSG = "error accepting connection for %s: %s";
76 const char *const BIND_ERROR_MSG = "bind error for %s: %s";
77 const char *const CONNECT_ERROR_MSG = "connect to host %s failed: %s";
78 const char *const CONNLIMIT_ERROR_MSG = "connect limit exceeded for %s: %s";
79 const char *const LISTEN_ERROR_MSG = "listen error for %s: %s";
80 const char *const NONB_ERROR_MSG = "error setting non-blocking for %s: %s";
81 const char *const PEERNAME_ERROR_MSG = "getpeername failed for %s: %s";
82 const char *const POLL_ERROR_MSG = "poll error for %s: %s";
83 const char *const REGISTER_ERROR_MSG = "registering %s: %s";
84 const char *const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
85 const char *const SELECT_ERROR_MSG = "select error for %s: %s";
86 const char *const SETBUFS_ERROR_MSG = "error setting buffer size for %s: %s";
87 const char *const SOCKET_ERROR_MSG = "error creating socket for %s: %s";
88 const char *const TOS_ERROR_MSG = "error setting TOS for %s: %s";
89
90
91 static int
92 is_blocked(int error)
93 {
94 return EWOULDBLOCK == error
95 #ifdef ENOMEM
96 || ENOMEM == error
97 #endif
98 #ifdef ENOBUFS
99 || ENOBUFS == error
100 #endif
101 || EAGAIN == error;
102 }
103
104 /* get_sockerr - get the error value from the socket or the current errno
105 *
106 * Get the *real* error from the socket (well try to anyway..).
107 * This may only work when SO_DEBUG is enabled but its worth the
108 * gamble anyway.
109 */
110 int
111 os_get_sockerr(int fd)
112 {
113 int errtmp = errno;
114 #ifdef SO_ERROR
115 int err = 0;
116 socklen_t len = sizeof(err);
117
118 if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len))
119 {
120 if (err)
121 errtmp = err;
122 }
123 errno = errtmp;
124 #endif
125 return errtmp;
126 }
127
128 /** Set a file descriptor to non-blocking mode.
129 * @param[in] fd %Socket file descriptor.
130 * @return Non-zero on success, or zero on failure.
131 */
132 int
133 os_set_nonblocking(int fd)
134 {
135 int res = 0;
136
137 if ((res = fcntl(fd, F_GETFL, 0)) == -1)
138 return 0;
139 if (fcntl(fd, F_SETFL, res | O_NONBLOCK) == -1)
140 return 0;
141 return 1;
142 }
143
144 /*
145 * setup_socket()
146 *
147 * Set the socket non-blocking, and other wonderful bits.
148 */
149 static void
150 setup_socket(int fd)
151 {
152 int opt = 1;
153
154 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
155
156 #ifdef IPTOS_LOWDELAY
157 opt = IPTOS_LOWDELAY;
158 setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
159 #endif
160 }
161
162 /** Mark a socket's address as reusable.
163 * @param[in] fd %Socket file descriptor to manipulate.
164 * @return Non-zero on success, or zero on failure.
165 */
166 int
167 os_set_reuseaddr(int fd)
168 {
169 unsigned int opt = 1;
170
171 return !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
172 }
173
174 /** Set a socket's send and receive buffer sizes.
175 * @param[in] fd %Socket file descriptor to manipulate.
176 * @param[in] ssize New send buffer size.
177 * @param[in] rsize New receive buffer size.
178 * @return Non-zero on success, or zero on failure.
179 */
180 int
181 os_set_sockbufs(int fd, unsigned int ssize, unsigned int rsize)
182 {
183 unsigned int sopt = ssize;
184 unsigned int ropt = rsize;
185
186 return !setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &ropt, sizeof(ropt)) &&
187 !setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sopt, sizeof(sopt));
188 }
189
190 /** Set a socket's "type of service" value.
191 * @param[in] fd %Socket file descriptor to manipulate.
192 * @param[in] tos New type of service value to use.
193 * @return Non-zero on success, or zero on failure.
194 */
195 int
196 os_set_tos(int fd, int tos)
197 {
198 #if defined(IP_TOS) && defined(IPPROTO_IP)
199 unsigned int opt = tos;
200
201 return !setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
202 #else
203 return 1;
204 #endif
205 }
206
207 /** Disable IP options on a socket.
208 * @param[in] fd %Socket file descriptor to manipulate.
209 * @return Non-zero on success, or zero on failure.
210 */
211 int
212 os_disable_options(int fd)
213 {
214 #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
215 return !setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0);
216 #else
217 return 1;
218 #endif
219 }
220
221 /** Start listening on a socket.
222 * @param[in] fd Disconnected file descriptor.
223 * @param[in] backlog Maximum number of un-accept()ed connections to keep.
224 * @return Non-zero on success; zero on error.
225 */
226 int
227 os_set_listen(int fd, int backlog)
228 {
229 return !listen(fd, backlog);
230 }
231
232 /** Attempt to read from a non-blocking socket.
233 * @param[in] fd File descriptor to read from.
234 * @param[out] buf Output buffer to read into.
235 * @param[in] length Number of bytes to read.
236 * @param[out] count_out Receives number of bytes actually read.
237 * @return An IOResult value indicating status.
238 */
239 IOResult
240 os_recv_nonb(int fd, char *buf, unsigned int length, unsigned int *count_out)
241 {
242 int res = 0;
243
244 assert(buf);
245 assert(count_out);
246
247 if ((res = recv(fd, buf, length, 0)) > 0)
248 {
249 *count_out = (unsigned int)res;
250 return IO_SUCCESS;
251 }
252
253 if (res == 0)
254 {
255 *count_out = 0;
256 errno = 0; /* Or ECONNRESET? */
257 return IO_FAILURE;
258 }
259
260 *count_out = 0;
261 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
262 }
263
264 /** Attempt to read from a non-blocking UDP socket.
265 * @param[in] fd File descriptor to read from.
266 * @param[out] buf Output buffer to read into.
267 * @param[in] length Number of bytes to read.
268 * @param[out] length_out Receives number of bytes actually read.
269 * @param[out] addr_out Peer address that sent the message.
270 * @return An IOResult value indicating status.
271 */
272 IOResult
273 os_recvfrom_nonb(int fd, char *buf, unsigned int length,
274 unsigned int *length_out,
275 struct irc_ssaddr *addr)
276 {
277 unsigned int len = sizeof(struct irc_ssaddr);
278 int res = 0;
279
280 assert(buf);
281 assert(length_out);
282 assert(addr);
283
284 res = recvfrom(fd, buf, length, 0, (struct sockaddr *)addr, &len);
285
286 if (res > -1)
287 {
288 *length_out = (unsigned int)res;
289 return IO_SUCCESS;
290 }
291
292 *length_out = 0;
293 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
294 }
295
296 /** Attempt to write on a connected socket.
297 * @param[in] fd File descriptor to write to.
298 * @param[in] buf Output buffer to send from.
299 * @param[in] length Number of bytes to write.
300 * @param[out] count_out Receives number of bytes actually written.
301 * @return An IOResult value indicating status.
302 */
303 IOResult
304 os_send_nonb(int fd, const char *buf, unsigned int length,
305 unsigned int *count_out)
306 {
307 int res = 0;
308
309 assert(buf);
310 assert(count_out);
311
312 if ((res = send(fd, buf, length, 0)) > -1)
313 {
314 *count_out = (unsigned int)res;
315 return IO_SUCCESS;
316 }
317
318 *count_out = 0;
319 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
320 }
321
322 /** Attempt a vectored write on a connected socket.
323 * @param[in] fd File descriptor to write to.
324 * @param[in] buf Message queue to send from.
325 * @param[out] count_in Number of bytes mapped from \a buf.
326 * @param[out] count_out Receives number of bytes actually written.
327 * @return An IOResult value indicating status.
328 */
329 IOResult
330 os_sendv_nonb(int fd, struct MsgQ *buf, unsigned int *count_in,
331 unsigned int *count_out)
332 {
333 int res = 0, count = 0;
334 struct iovec iov[IOV_MAX];
335
336 assert(buf);
337 assert(count_in);
338 assert(count_out);
339
340 *count_in = 0;
341 count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
342
343 if ((res = writev(fd, iov, count)) > -1)
344 {
345 *count_out = (unsigned int)res;
346 return IO_SUCCESS;
347 }
348
349 *count_out = 0;
350 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
351 }
352
353 /** Attempt to write on a non-blocking UDP socket.
354 * @param[in] fd File descriptor to write to.
355 * @param[in] buf Output buffer to send from.
356 * @param[in] length Number of bytes to write.
357 * @param[out] count_out Receives number of bytes actually written.
358 * @param[in] flags Flags for call to sendto().
359 * @param[in] peer Destination address of the message.
360 * @return An IOResult value indicating status.
361 */
362 IOResult os_sendto_nonb(int fd, const char *buf, unsigned int length,
363 unsigned int *count_out, unsigned int flags,
364 struct irc_ssaddr *peer)
365 {
366 int res = 0;
367
368 assert(buf);
369
370 if ((res = sendto(fd, buf, length, flags, (struct sockaddr *)peer, peer->ss_len)) > -1)
371 {
372 if (count_out)
373 *count_out = (unsigned int)res;
374 return IO_SUCCESS;
375 }
376
377 if (count_out)
378 *count_out = 0;
379 return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
380 }
381
382 /** Start a non-blocking connection.
383 * @param[in] fd Disconnected file descriptor.
384 * @param[in] sin Target address for connection.
385 * @return IOResult code indicating status.
386 */
387 IOResult os_connect_nonb(int fd, const struct irc_ssaddr *addr)
388 {
389 if (connect(fd, (const struct sockaddr *)addr, addr->ss_len))
390 return (errno == EINPROGRESS) ? IO_BLOCKED : IO_FAILURE;
391 return IO_SUCCESS;
392 }
393
394 int
395 os_accept(int fd, struct irc_ssaddr *addr)
396 {
397 int new_fd = 0;
398 socklen_t addrlen = sizeof(struct irc_ssaddr);
399
400 new_fd = accept(fd, (struct sockaddr *)addr, &addrlen);
401 if (new_fd < 0)
402 return -1;
403
404 remove_ipv6_mapping(addr);
405 setup_socket(new_fd);
406 os_set_nonblocking(new_fd);
407 return new_fd;
408 }
409
410 int
411 os_socket(int family, int sock_type, const char *port_name)
412 {
413 int fd;
414
415 if ((fd = socket(family, sock_type, 0)) < 0)
416 {
417 report_error(L_ALL, SOCKET_ERROR_MSG, port_name, errno);
418 return -1;
419 }
420
421 if (fd > MAXCLIENTS - 1)
422 {
423 report_error(L_ALL, CONNLIMIT_ERROR_MSG, port_name, 0);
424 close(fd);
425 return -1;
426 }
427
428 if (!os_set_reuseaddr(fd))
429 {
430 report_error(L_ALL, REUSEADDR_ERROR_MSG, port_name, errno);
431 close(fd);
432 return -1;
433 }
434
435 if (!os_set_nonblocking(fd))
436 {
437 report_error(L_ALL, NONB_ERROR_MSG, port_name, errno);
438 close(fd);
439 return -1;
440 }
441
442 setup_socket(fd);
443 return fd;
444 }
445
446 int
447 os_bind(int fd, struct irc_ssaddr *local)
448 {
449 return bind(fd, (struct sockaddr *)local, local->ss_len);
450 }
451
452 /** Closes all file descriptors.
453 * @param close_stderr If non-zero, also close stderr.
454 */
455 void
456 close_connections(const int close_stderr)
457 {
458 int i = 0;
459
460 if (close_stderr)
461 {
462 close(0);
463 close(1);
464 close(2);
465 }
466
467 for (i = 3; i < MAXCONNECTIONS; ++i)
468 close(i);
469 }
470
471 #ifdef HAVE_LIBCRYPTO
472 static IOResult
473 client_recv(struct Client *client_p, char *buf, unsigned int length, unsigned int *count_out)
474 {
475 if (client_p->localClient->socket.ssl)
476 return ssl_recv(&client_p->localClient->socket, buf, length, count_out);
477
478 return os_recv_nonb(s_fd(&client_p->localClient->socket), buf, length, count_out);
479 }
480
481 static IOResult
482 client_sendv(struct Client *client_p, struct MsgQ *buf, unsigned int *count_in, unsigned int *count_out)
483 {
484 if (client_p->localClient->socket.ssl)
485 return ssl_sendv(&client_p->localClient->socket, buf, count_in, count_out);
486 return os_sendv_nonb(s_fd(&client_p->localClient->socket), buf, count_in, count_out);
487 }
488 #endif
489
490 /*
491 * report_error - report an error from an errno.
492 * Record error to log and also send a copy to all *LOCAL* opers online.
493 *
494 * text is a *format* string for outputing error. It must
495 * contain only two '%s', the first will be replaced
496 * by the sockhost from the client_p, and the latter will
497 * be taken from sys_errlist[errno].
498 *
499 * client_p if not NULL, is the *LOCAL* client associated with
500 * the error.
501 *
502 * Cannot use perror() within daemon. stderr is closed in
503 * ircd and cannot be used. And, worse yet, it might have
504 * been reassigned to a normal connection...
505 *
506 * Actually stderr is still there IFF ircd was run with -s --Rodder
507 */
508
509 void
510 report_error(int level, const char *text, const char *who, int error)
511 {
512 int errtmp = errno; /* debug may change 'errno' */
513 const char *errmsg = (error) ? strerror(error) : "";
514
515 if (!errmsg)
516 errmsg = "Unknown error";
517
518 if (EmptyString(who))
519 who = "unknown";
520
521 sendto_realops_flags(UMODE_DEBUG, level, SEND_NOTICE,
522 text, who, errmsg);
523 ilog(LOG_TYPE_IRCD, text, who, errmsg);
524 errno = errtmp;
525 }
526
527 /** Complete non-blocking connect()-sequence. Check access and
528 * terminate connection, if trouble detected.
529 * @param client_p Client to which we have connected, with all ConfItem structs attached.
530 * @return Zero on failure (caller should exit_client()), non-zero on success.
531 */
532 static int
533 completed_connection(struct Client *client_p)
534 {
535 struct MaskItem *conf = NULL;
536
537 assert(client_p);
538
539 /*
540 * Get the socket status from the fd first to check if
541 * connection actually succeeded
542 */
543 if ((client_p->localClient->error = os_get_sockerr(s_fd(&client_p->localClient->socket))))
544 {
545 const char *msg = strerror(client_p->localClient->error);
546
547 if (!msg)
548 msg = "Unknown error";
549
550 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
551 "Connection failed to %s: %s",
552 get_client_name(client_p, HIDE_IP), msg);
553 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
554 "Connection failed to %s: %s",
555 get_client_name(client_p, MASK_IP), msg);
556 return 0;
557 }
558
559 conf = find_conf_name(&client_p->localClient->confs,
560 client_p->name, CONF_SERVER);
561 if (!conf)
562 {
563 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
564 "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
565 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
566 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
567 return 0;
568 }
569
570 if (s_state(&client_p->localClient->socket) == SS_CONNECTING)
571 socket_state(&client_p->localClient->socket, SS_CONNECTED);
572
573 if (!EmptyString(conf->spasswd))
574 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
575
576 send_capabilities(client_p, 0);
577
578 assert(client_p->serv);
579 SetHandshake(client_p);
580
581 /*
582 * Make us timeout after twice the timeout for DNS look ups
583 */
584 client_p->localClient->lasttime = CurrentTime;
585 AddFlag(client_p, FLAGS_PINGSENT);
586
587 sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
588 ConfigServerHide.hidden ? "(H) " : "", me.info);
589
590 return !IsDead(client_p);
591 }
592
593 /*
594 * close_connection
595 * Close the physical connection. This function must make
596 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
597 */
598 void
599 close_connection(struct Client *client_p)
600 {
601 dlink_node *ptr = NULL;
602
603 assert(client_p);
604
605 if (IsClient(client_p))
606 {
607 ++ServerStats.is_cl;
608 ServerStats.is_cbs += client_p->localClient->send.bytes;
609 ServerStats.is_cbr += client_p->localClient->recv.bytes;
610 ServerStats.is_cti += CurrentTime - client_p->localClient->firsttime;
611 }
612 else if (IsServer(client_p))
613 {
614 ++ServerStats.is_sv;
615 ServerStats.is_sbs += client_p->localClient->send.bytes;
616 ServerStats.is_sbr += client_p->localClient->recv.bytes;
617 ServerStats.is_sti += CurrentTime - client_p->localClient->firsttime;
618
619 DLINK_FOREACH(ptr, server_items.head)
620 {
621 struct MaskItem *conf = ptr->data;
622
623 if (irccmp(conf->name, client_p->name))
624 continue;
625
626 /*
627 * Reset next-connect cycle of all connect{} blocks that match
628 * this servername.
629 */
630 conf->until = CurrentTime + conf->class->con_freq;
631 }
632 }
633 else
634 ++ServerStats.is_ni;
635
636 if (s_fd(&client_p->localClient->socket)> -1)
637 {
638 flush_connections(client_p);
639 dlinkDelete(&client_p->localClient->node, &connection_list);
640 close(s_fd(&client_p->localClient->socket));
641 socket_del(&client_p->localClient->socket); /* Queue a socket delete */
642 s_fd(&client_p->localClient->socket) = -1;
643 }
644
645 AddFlag(client_p, FLAGS_DEADSOCKET);
646
647 MsgQClear(&client_p->localClient->sendQ);
648 client_drop_sendq(client_p->localClient);
649 DBufClear(&client_p->localClient->recvQ);
650
651 MyFree(client_p->localClient->passwd);
652 client_p->localClient->passwd = NULL;
653
654 detach_conf(client_p, CONF_CLIENT|CONF_OPER|CONF_SERVER);
655 client_p->from = NULL; /* ...this should catch them! >:) --msa */
656
657 if (client_p->localClient->listener)
658 {
659 assert(0 < client_p->localClient->listener->ref_count);
660 listener_release(client_p->localClient->listener);
661 client_p->localClient->listener = NULL;
662 }
663 }
664
665 /*
666 * add_connection - creates a client which has just connected to us on
667 * the given fd. The sockhost field is initialized with the ip# of the host.
668 * An unique id is calculated now, in case it is needed for auth.
669 * The client is sent to the auth module for verification, and not put in
670 * any client list yet.
671 */
672 void
673 add_connection(struct Listener *listener, int fd, struct irc_ssaddr *irn)
674 {
675 struct Client *new_client = make_client(NULL);
676
677 /*
678 * copy address to 'sockhost' as a string, copy it to host too
679 * so we have something valid to put into error messages...
680 */
681 memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
682
683 getnameinfo((struct sockaddr *)&new_client->localClient->ip,
684 new_client->localClient->ip.ss_len, new_client->sockhost,
685 sizeof(new_client->sockhost), NULL, 0, NI_NUMERICHOST);
686 new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
687
688 #ifdef HAVE_LIBGEOIP
689 /* XXX IPV6 SUPPORT XXX */
690 if (irn->ss.ss_family == AF_INET && geoip_ctx)
691 {
692 const struct sockaddr_in *v4 = (const struct sockaddr_in *)&new_client->localClient->ip;
693 new_client->localClient->country_id = GeoIP_id_by_ipnum(geoip_ctx, (unsigned long)ntohl(v4->sin_addr.s_addr));
694 }
695 #endif
696
697 if (new_client->sockhost[0] == ':' && new_client->sockhost[1] == ':')
698 {
699 strlcpy(new_client->host, "0", sizeof(new_client->host));
700 strlcpy(new_client->host+1, new_client->sockhost, sizeof(new_client->host)-1);
701 memmove(new_client->sockhost+1, new_client->sockhost, sizeof(new_client->sockhost)-1);
702 new_client->sockhost[0] = '0';
703 }
704 else
705 strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
706
707 s_fd(&new_client->localClient->socket) = fd;
708 if (!socket_add(&new_client->localClient->socket, client_sock_callback,
709 new_client->localClient, SS_CONNECTED, 0, fd))
710 {
711 ++ServerStats.is_ref;
712 // write(fd, register_message, strlen(register_message));
713 close(fd);
714 s_fd(&new_client->localClient->socket) = -1;
715 return;
716 }
717
718 #ifdef HAVE_LIBCRYPTO
719 if ((listener->flags & LISTENER_SSL))
720 {
721 if (!ssl_new_accept(new_client, fd))
722 {
723 ++ServerStats.is_ref;
724
725 close(fd);
726 s_fd(&new_client->localClient->socket) = -1;
727 return;
728 }
729 }
730 #endif
731
732 new_client->localClient->freeflag |= FREEFLAG_SOCKET;
733 new_client->localClient->listener = listener;
734 ++listener->ref_count;
735
736 /* If we've made it this far we can put the client on the auth query pile */
737 start_auth(new_client);
738 }
739
740 /** Determines whether to tell the events engine we're interested in
741 * writable events.
742 * \param client_p Client for which to decide this.
743 */
744 void
745 update_write(struct Client *client_p)
746 {
747 /*
748 * If there are messages that need to be sent along, or if the client
749 * is in the middle of a /list, then we need to tell the engine that
750 * we're interested in writable events--otherwise, we need to drop
751 * that interest.
752 */
753 socket_events(&client_p->localClient->socket,
754 ((MsgQLength(&client_p->localClient->sendQ) || client_p->localClient->list_task) ?
755 SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
756 }
757
758 /** Read a 'packet' of data from a connection and process it. Read in
759 * 8k chunks to give a better performance rating (for server
760 * connections). Do some tricky stuff for client connections to make
761 * sure they don't do any flooding >:-) -avalon
762 * @param client_p Client from which to read data.
763 * @param socket_ready If non-zero, more data can be read from the client's socket.
764 * @return Positive number on success, zero on connection-fatal failure, negative
765 * if user is killed.
766 */
767 static int
768 read_packet(struct Client *client_p, int socket_ready)
769 {
770 unsigned int dolen = 0, length = 0;
771
772 if (socket_ready && !(IsClient(client_p) &&
773 DBufLength(&client_p->localClient->recvQ) > get_recvq(&client_p->localClient->confs)))
774 {
775 #ifdef HAVE_LIBCRYPTO
776 switch (client_recv(client_p, readbuf, sizeof(readbuf), &length))
777 #else
778 switch (os_recv_nonb(s_fd(&client_p->localClient->socket), readbuf, sizeof(readbuf), &length))
779 #endif
780 {
781 case IO_SUCCESS:
782 if (length)
783 {
784 client_p->localClient->lasttime = CurrentTime;
785
786 if (client_p->localClient->lasttime > client_p->localClient->since)
787 client_p->localClient->since = CurrentTime;
788
789 ClearPingSent(client_p);
790 DelFlag(client_p, FLAGS_NONEWLINE);
791 }
792 break;
793
794 case IO_BLOCKED:
795 break;
796 case IO_FAILURE:
797 client_p->localClient->error = errno;
798 /* AddFlag(client_p, FLAGS_DEADSOCKET); */
799 return 0;
800 }
801 }
802
803 /*
804 * For server connections, we process as many as we can without
805 * worrying about the time of day or anything :)
806 */
807 if (length > 0 && IsServer(client_p))
808 return server_dopacket(client_p, readbuf, length);
809 else if (length > 0 && (IsHandshake(client_p) || IsConnecting(client_p)))
810 return connect_dopacket(client_p, readbuf, length);
811 else
812 {
813 /*
814 * Before we even think of parsing what we just read, stick
815 * it on the end of the receive queue and do it when its
816 * turn comes around.
817 */
818 if (length > 0 && !dbuf_put(&client_p->localClient->recvQ, readbuf, length))
819 return exit_client(client_p, client_p, &me, "dbuf_put fail");
820
821 if (DBufLength(&client_p->localClient->recvQ) > get_recvq(&client_p->localClient->confs))
822 return exit_client(client_p, client_p, &me, "Excess Flood");
823
824 while (DBufLength(&client_p->localClient->recvQ) && !HasFlag(client_p, FLAGS_NONEWLINE) &&
825 (IsTrusted(client_p) || client_p->localClient->since - CurrentTime < 10))
826 {
827 dolen = dbuf_getmsg(&client_p->localClient->recvQ,
828 client_p->localClient->buffer, IRCD_BUFSIZE);
829
830 /*
831 * Devious looking...whats it do ? well..if a client
832 * sends a *long* message without any CR or LF, then
833 * dbuf_getmsg fails and we pull it out using this
834 * loop which just gets the next 512 bytes and then
835 * deletes the rest of the buffer contents.
836 * -avalon
837 */
838 if (dolen == 0)
839 {
840 if (DBufLength(&client_p->localClient->recvQ) < 510)
841 AddFlag(client_p, FLAGS_NONEWLINE);
842 else
843 {
844 /*
845 * More than 512 bytes in the line - drop the input and yell
846 * at the client.
847 */
848 DBufClear(&client_p->localClient->recvQ);
849 sendto_one(client_p, form_str(ERR_INPUTTOOLONG), me.name,
850 client_p->name[0] ? client_p->name : "*");
851 }
852 }
853 else if (client_dopacket(client_p, dolen) == CPTR_KILLED)
854 return CPTR_KILLED;
855
856 /*
857 * If it has become registered as a Server
858 * then skip the per-message parsing below.
859 */
860 if (IsHandshake(client_p) || IsServer(client_p))
861 {
862 while (-1)
863 {
864 dolen = dbuf_get(&client_p->localClient->recvQ, readbuf, sizeof(readbuf));
865
866 if (dolen <= 0)
867 return 1;
868 if (dolen == 0)
869 {
870 if (DBufLength(&client_p->localClient->recvQ) < 510)
871 AddFlag(client_p, FLAGS_NONEWLINE);
872 else
873 DBufClear(&client_p->localClient->recvQ);
874 }
875 else if ((IsServer(client_p) &&
876 server_dopacket(client_p, readbuf, dolen) == CPTR_KILLED) ||
877 (!IsServer(client_p) &&
878 connect_dopacket(client_p, readbuf, dolen) == CPTR_KILLED))
879 return CPTR_KILLED;
880 }
881 }
882 }
883
884 /* If there's still data to process, wait 2 seconds first */
885 if (DBufLength(&client_p->localClient->recvQ) && !HasFlag(client_p, FLAGS_NONEWLINE) &&
886 !t_onqueue(&client_p->localClient->proc))
887 {
888 client_p->localClient->freeflag |= FREEFLAG_TIMER;
889 timer_add(&client_p->localClient->proc, client_timer_callback, client_p->localClient,
890 TT_RELATIVE, 2);
891 }
892 }
893 return 1;
894 }
895
896 /** Attempt to send a sequence of bytes to the connection.
897 * As a side effect, updates \a client_p's FLAGS_BLOCKED setting
898 * and sendB/sendK fields.
899 * @param client_p Client that should receive data.
900 * @param buf Message buffer to send to client.
901 * @return Negative on connection-fatal error; otherwise
902 * number of bytes sent.
903 */
904 unsigned int
905 deliver_it(struct Client *client_p, struct MsgQ *buf)
906 {
907 unsigned int bytes_written = 0, bytes_count = 0;
908
909 assert(client_p);
910
911 #ifdef HAVE_LIBCRYPTO
912 switch (client_sendv(client_p, buf, &bytes_count, &bytes_written))
913 #else
914 switch (os_sendv_nonb(s_fd(&client_p->localClient->socket), buf, &bytes_count, &bytes_written))
915 #endif
916 {
917 case IO_SUCCESS:
918 DelFlag(client_p, FLAGS_BLOCKED);
919
920 client_p->localClient->send.bytes += bytes_written;
921 me.localClient->send.bytes += bytes_written;
922
923 /* A partial write implies that future writes will block. */
924 if (bytes_written < bytes_count)
925 AddFlag(client_p, FLAGS_BLOCKED);
926 break;
927 case IO_BLOCKED:
928 AddFlag(client_p, FLAGS_BLOCKED);
929 break;
930 case IO_FAILURE:
931 client_p->localClient->error = errno;
932 AddFlag(client_p, FLAGS_DEADSOCKET);
933 break;
934 }
935
936 return bytes_written;
937 }
938
939 /** Set up address and port and make a connection.
940 * @param conf Provides the connection information.
941 * @param client_p Client structure for the peer.
942 * @return Non-zero on success; zero on failure.
943 */
944 static int
945 connect_inet(struct MaskItem *conf, struct Client *client_p)
946 {
947 struct addrinfo hints, *res;
948 char portname[PORTNAMELEN + 1];
949 /* conversion structs */
950 struct sockaddr_in *v4;
951 struct sockaddr_in6 *v6;
952 IOResult result;
953
954 assert(conf);
955 assert(client_p);
956
957 s_fd(&client_p->localClient->socket) = os_socket(conf->aftype, SOCK_STREAM, client_p->name);
958 if (s_fd(&client_p->localClient->socket) < 0)
959 return 0;
960
961 switch (conf->aftype)
962 {
963 case AF_INET:
964 v4 = (struct sockaddr_in *)&conf->bind;
965 if (v4->sin_addr.s_addr != 0)
966 {
967 struct irc_ssaddr ipn;
968 memset(&ipn, 0, sizeof(struct irc_ssaddr));
969 ipn.ss.ss_family = AF_INET;
970 ipn.ss_port = 0;
971 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
972 /* XXX ipn.ss_len */
973 os_bind(s_fd(&client_p->localClient->socket), &ipn);
974 }
975 else if (ServerInfo.specific_ipv4_vhost)
976 {
977 struct irc_ssaddr ipn;
978 memset(&ipn, 0, sizeof(struct irc_ssaddr));
979 ipn.ss.ss_family = AF_INET;
980 ipn.ss_port = 0;
981 memcpy(&ipn, &ServerInfo.ip, sizeof(struct irc_ssaddr));
982
983 os_bind(s_fd(&client_p->localClient->socket), &ipn);
984 }
985
986 break;
987
988 case AF_INET6:
989 {
990 struct irc_ssaddr ipn;
991 struct sockaddr_in6 *v6conf;
992
993 memset(&ipn, 0, sizeof(struct irc_ssaddr));
994 v6conf = (struct sockaddr_in6 *)&conf->bind;
995 v6 = (struct sockaddr_in6 *)&ipn;
996
997 if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, sizeof(struct in6_addr)) != 0)
998 {
999 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
1000 ipn.ss.ss_family = AF_INET6;
1001 ipn.ss_port = 0;
1002 os_bind(s_fd(&client_p->localClient->socket), &ipn);
1003 }
1004 else if (ServerInfo.specific_ipv6_vhost)
1005 {
1006 memcpy(&ipn, &ServerInfo.ip6, sizeof(struct irc_ssaddr));
1007 ipn.ss.ss_family = AF_INET6;
1008 ipn.ss_port = 0;
1009 os_bind(s_fd(&client_p->localClient->socket), &ipn);
1010 }
1011 }
1012 }
1013
1014
1015 /*
1016 * Save connection info in client
1017 */
1018 #ifdef XXX___
1019 memcpy(&cli_ip(cptr), &conf->addr, sizeof(cli_ip(cptr)));
1020 ircd_ntoa_r(cli_sock_ip(cptr), &cli_ip(cptr));
1021 #endif
1022 /*
1023 * We want a big buffer for server connections
1024 */
1025 if (!os_set_sockbufs(s_fd(&client_p->localClient->socket), /* XXX */ CLIENT_TCP_WINDOW, CLIENT_TCP_WINDOW))
1026 {
1027 client_p->localClient->error = errno;
1028 report_error(L_ALL, SETBUFS_ERROR_MSG, client_p->name, errno);
1029 close(s_fd(&client_p->localClient->socket));
1030 s_fd(&client_p->localClient->socket) = -1;
1031 return 0;
1032 }
1033
1034 /*
1035 * Set the TOS bits - this is nonfatal if it doesn't stick.
1036 */
1037 #ifdef XXX___
1038 if (!os_set_tos(cli_fd(cptr), FEAT_TOS_SERVER))
1039 report_error(L_ALL, TOS_ERROR_MSG, cli_name(cptr), errno);
1040 #endif
1041
1042 memset(&hints, 0, sizeof(hints));
1043 hints.ai_family = AF_UNSPEC;
1044 hints.ai_socktype = SOCK_STREAM;
1045 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1046
1047 snprintf(portname, sizeof(portname), "%d", conf->port);
1048
1049 #if 0
1050 if (getaddrinfo(host, portname, &hints, &res))
1051 {
1052 #if 0
1053 /* Send the DNS request, for the next level */
1054 if (aftype == AF_INET6)
1055 gethost_byname_type(comm_connect_dns_callback, fd, host, T_AAAA);
1056 else
1057 gethost_byname_type(comm_connect_dns_callback, fd, host, T_A);
1058 }
1059 #endif
1060 else
1061 {
1062 /* We have a valid IP, so we just call tryconnect */
1063 /* Make sure we actually set the timeout here .. */
1064 assert(res != NULL);
1065 memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen);
1066 fd->connect.hostaddr.ss_len = res->ai_addrlen;
1067 fd->connect.hostaddr.ss.ss_family = res->ai_family;
1068 freeaddrinfo(res);
1069 }
1070 #endif
1071 if ((result = os_connect_nonb(s_fd(&client_p->localClient->socket), &conf->addr)) == IO_FAILURE)
1072 {
1073 client_p->localClient->error = errno;
1074 report_error(L_ALL, CONNECT_ERROR_MSG, client_p->name, errno);
1075 close(s_fd(&client_p->localClient->socket));
1076 s_fd(&client_p->localClient->socket) = -1;
1077 return 0;
1078 }
1079
1080 if (!socket_add(&client_p->localClient->socket, client_sock_callback, client_p->localClient,
1081 (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING,
1082 SOCK_EVENT_READABLE, s_fd(&client_p->localClient->socket)))
1083 {
1084 client_p->localClient->error = ENFILE;
1085 report_error(L_ALL, REGISTER_ERROR_MSG, client_p->name, ENFILE);
1086 close(s_fd(&client_p->localClient->socket));
1087 s_fd(&client_p->localClient->socket) = -1;
1088 return 0;
1089 }
1090
1091 client_p->localClient->freeflag |= FREEFLAG_SOCKET;
1092 return 1;
1093 }
1094
1095 /** Start a connection to another server.
1096 * @param aconf Connect block data for target server.
1097 * @param by Client who requested the connection (if any).
1098 * @return Non-zero on success; zero on failure.
1099 */
1100 int
1101 connect_server(struct MaskItem *conf, struct Client *by)
1102 {
1103 struct Client *client_p = NULL;
1104
1105 assert(conf);
1106
1107 if (conf->dns_pending)
1108 {
1109 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1110 "Server %s connect DNS pending",
1111 conf->name);
1112 return 0;
1113 }
1114
1115 if ((client_p = hash_find_client(conf->name)))
1116 {
1117 if (IsServer(client_p) || IsMe(client_p))
1118 {
1119 sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
1120 "Server %s already present from %s",
1121 conf->name, get_client_name(client_p, SHOW_IP));
1122 sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
1123 "Server %s already present from %s",
1124 conf->name, get_client_name(client_p, MASK_IP));
1125 if (by && IsClient(by) && !MyClient(by))
1126 sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
1127 me.name, by->name, conf->name,
1128 get_client_name(client_p, MASK_IP));
1129 return 0;
1130 }
1131 else if (IsHandshake(client_p) || IsConnecting(client_p))
1132 {
1133 if (by && IsClient(by))
1134 sendto_one(by, ":%s NOTICE %s :Connection to %s already in progress",
1135 me.name, by->name, client_p->name,
1136 get_client_name(client_p, MASK_IP));
1137 return 0;
1138 }
1139 }
1140 #ifdef XXX___
1141 /*
1142 * If we don't know the IP# for this host and it is a hostname and
1143 * not a ip# string, then try and find the appropriate host record.
1144 */
1145 if (!irc_in_addr_valid(&aconf->address.addr)
1146 && !ircd_aton(&aconf->address.addr, aconf->host)) {
1147 gethost_byname(connect_dns_callback, conf, conf->host);
1148 aconf->dns_pending = 1;
1149 return 0;
1150 }
1151 #endif
1152 /* Create a local client */
1153 client_p = make_client(NULL);
1154
1155 /*
1156 * Copy these in so we have something for error detection.
1157 */
1158 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
1159 strlcpy(client_p->host, conf->host, sizeof(client_p->host));
1160
1161 /* We already converted the ip once, so lets use it - stu */ /* XXX */
1162 // strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
1163 client_p->localClient->aftype = conf->aftype;
1164
1165 /*
1166 * Attach config entries to client here rather than in
1167 * completed_connection. This to avoid null pointer references
1168 */
1169 if (!attach_connect_block(client_p, conf->name, conf->host))
1170 {
1171 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1172 "Host %s is not enabled for connecting: no connect{} block",
1173 conf->name);
1174 if (by && IsClient(by) && !MyClient(by))
1175 sendto_one(by, ":%s NOTICE %s :Connect to host %s failed: no connect{} block",
1176 me.name, by->name, client_p->name);
1177
1178 detach_conf(client_p, CONF_CLIENT|CONF_OPER|CONF_SERVER);
1179 free_client(client_p);
1180 return 0;
1181 }
1182
1183 /*
1184 * Attempt to connect to the server in the conf line
1185 */
1186 if (!connect_inet(conf, client_p))
1187 {
1188 if (by && IsClient(by) && !MyClient(by))
1189 sendto_one(by, ":%s NOTICE %s :Couldn't connect to %s",
1190 me.name, by->name, client_p->name);
1191
1192 detach_conf(client_p, CONF_CLIENT|CONF_OPER|CONF_SERVER);
1193 free_client(client_p);
1194 return 0;
1195 }
1196
1197 /*
1198 * NOTE: if we're here we have a valid C:Line and the client should
1199 * have started the connection and stored the remote address/port and
1200 * ip address name in itself
1201 *
1202 * The socket has been connected or connect is in progress.
1203 */
1204 make_server(client_p);
1205
1206 if (by && IsClient(by))
1207 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
1208 else
1209 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
1210
1211 SetConnecting(client_p);
1212 dlinkAdd(client_p, &client_p->node, &global_client_list);
1213
1214 /* from def_fam */
1215 client_p->localClient->aftype = conf->aftype;
1216
1217 dlinkAdd(client_p, &client_p->localClient->node, &connection_list);
1218
1219 /*
1220 * Actually we lie, the connect hasn't succeeded yet, but we have a valid
1221 * client_p, so we register it now.
1222 * Maybe these two calls should be merged.
1223 */
1224 add_client_to_list(client_p);
1225 hash_add_client(client_p);
1226 /* nextping = CurrentTime; */
1227
1228 return (s_state(&client_p->localClient->socket) == SS_CONNECTED) ?
1229 completed_connection(client_p) : 1;
1230 }
1231
1232 /*
1233 * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
1234 * OSes with IPv6 mapping listening on both
1235 * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
1236 *
1237 */
1238 void
1239 remove_ipv6_mapping(struct irc_ssaddr *addr)
1240 {
1241 if (addr->ss.ss_family == AF_INET6)
1242 {
1243 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr))
1244 {
1245 struct sockaddr_in6 v6;
1246 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
1247
1248 memcpy(&v6, addr, sizeof(v6));
1249 memset(v4, 0, sizeof(struct sockaddr_in));
1250 memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr));
1251
1252 addr->ss.ss_family = AF_INET;
1253 addr->ss_len = sizeof(struct sockaddr_in);
1254 }
1255 else
1256 addr->ss_len = sizeof(struct sockaddr_in6);
1257 }
1258 else
1259 addr->ss_len = sizeof(struct sockaddr_in);
1260 }
1261
1262 /** Process events on a client socket.
1263 * @param ev Socket event structure that has a struct Connection as
1264 * its associated data.
1265 */
1266 static void
1267 client_sock_callback(struct Event *ev)
1268 {
1269 struct Client *client_p = NULL;
1270 struct Connection *con = NULL;
1271 const char *fmt = "%s";
1272 const char *fallback = NULL;
1273
1274 assert(ev_socket(ev));
1275 assert(s_data(ev_socket(ev)));
1276
1277 con = s_data(ev_socket(ev));
1278
1279 assert(con->client_p || ev_type(ev) == ET_DESTROY);
1280
1281 client_p = con->client_p;
1282
1283 assert(!client_p || con == client_p->localClient);
1284
1285 switch (ev_type(ev))
1286 {
1287 case ET_DESTROY:
1288 con->freeflag &= ~FREEFLAG_SOCKET;
1289
1290 if (!con->freeflag && !client_p)
1291 free_connection(con);
1292 break;
1293
1294 case ET_CONNECT: /* Socket connection completed */
1295 if (!completed_connection(client_p) || IsDead(client_p))
1296 fallback = client_p->info;
1297 break;
1298
1299 case ET_ERROR: /* An error occurred */
1300 fallback = client_p->info;
1301 client_p->localClient->error = ev_data(ev);
1302
1303 /*
1304 * If the OS told us we have a bad file descriptor, we should
1305 * record that for future reference.
1306 */
1307 if (client_p->localClient->error == EBADF)
1308 s_fd(&client_p->localClient->socket) = -1;
1309
1310 if (s_state(&con->socket) == SS_CONNECTING)
1311 {
1312 completed_connection(client_p);
1313
1314 /*
1315 * For some reason, the os_get_sockerr() in completed_connect()
1316 * can return 0 even when ev_data(ev) indicates a real error, so
1317 * re-assign the client error here.
1318 */
1319 client_p->localClient->error = ev_data(ev);
1320 break;
1321 }
1322
1323 /*FALLTHROUGH*/
1324 case ET_EOF: /* End of file on socket */
1325 AddFlag(client_p, FLAGS_DEADSOCKET);
1326
1327 if ((IsServer(client_p) || IsHandshake(client_p)) && client_p->localClient->error == 0)
1328 {
1329 exit_client_msg(client_p, client_p, &me, "Server %s closed the connection (%s)",
1330 client_p->name, client_p->serv->last_error_msg);
1331 return;
1332 }
1333 else
1334 {
1335 fmt = "Read error: %s";
1336 fallback = "EOF from client";
1337 }
1338
1339 break;
1340
1341 case ET_WRITE: /* Socket is writable */
1342 DelFlag(client_p, FLAGS_BLOCKED);
1343
1344 if (client_p->localClient->list_task && MsgQLength(&client_p->localClient->sendQ) < 2048)
1345 safe_list_channels(client_p, 0);
1346 send_queued(client_p);
1347 break;
1348
1349 case ET_READ: /* Socket is readable */
1350 if (!IsDead(client_p))
1351 {
1352 if (read_packet(client_p, 1) == 0) /* Error while reading packet */
1353 fallback = "EOF from client";
1354 }
1355
1356 break;
1357
1358 default:
1359 assert(0 && "Unrecognized socket event in client_sock_callback()");
1360 break;
1361 }
1362
1363 assert(!client_p || !client_p->localClient || con == client_p->localClient);
1364
1365 if (fallback)
1366 {
1367 const char *msg = (client_p->localClient->error) ? strerror(client_p->localClient->error) : fallback;
1368
1369 if (!msg)
1370 msg = "Unknown error";
1371 exit_client_msg(client_p, client_p, &me, fmt, msg);
1372 }
1373 }
1374
1375 /** Process a timer on client socket.
1376 * @param ev Timer event that has a struct Connection as its
1377 * associated data.
1378 */
1379 static void
1380 client_timer_callback(struct Event *ev)
1381 {
1382 struct Client *client_p = NULL;
1383 struct Connection *con = NULL;
1384
1385 assert(ev_timer(ev));
1386 assert(t_data(ev_timer(ev)));
1387 assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
1388
1389 con = t_data(ev_timer(ev));
1390
1391 assert(con->client_p || ev_type(ev) == ET_DESTROY);
1392
1393 client_p = con->client_p;
1394
1395 assert(!client_p || con == client_p->localClient);
1396
1397 if (ev_type(ev) == ET_DESTROY)
1398 {
1399 con->freeflag &= ~FREEFLAG_TIMER; /* Timer has expired... */
1400
1401 if (!con->freeflag && !client_p)
1402 free_connection(con); /* Client is being destroyed */
1403 }
1404 else
1405 read_packet(client_p, 0); /* read_packet will re-add timer if needed */
1406
1407 assert(!client_p || !client_p->localClient || con == client_p->localClient);
1408 }

Properties

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