ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/s_bsd.c
Revision: 2391
Committed: Thu Jul 11 20:57:08 2013 UTC (10 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 38955 byte(s)
Log Message:
- ioengine changes as of 11JUN13

File Contents

# User Rev Content
1 adx 30 /*
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 michael 2391 * Copyright (C) 1999 Thomas Helvey
7 adx 30 *
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 knight 31 * $Id$
24 adx 30 */
25    
26     #include "stdinc.h"
27     #include <netinet/in_systm.h>
28     #include <netinet/ip.h>
29     #include <netinet/tcp.h>
30 michael 1011 #include "list.h"
31 adx 30 #include "fdlist.h"
32     #include "s_bsd.h"
33     #include "client.h"
34     #include "dbuf.h"
35     #include "event.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 michael 1309 #include "conf.h"
45     #include "log.h"
46 adx 30 #include "s_serv.h"
47     #include "send.h"
48     #include "memory.h"
49     #include "s_user.h"
50 michael 2391 #include "msgq.h"
51 adx 30
52    
53 michael 2389 dlink_list connection_list;
54 adx 30
55 michael 2389 static void client_sock_callback(struct Event *);
56     static void client_timer_callback(struct Event *);
57 adx 30
58 michael 2389 /** Temporary buffer for reading data from a peer. */
59     static char readbuf[SERVER_TCP_WINDOW];
60 adx 30
61 michael 2389 /*
62     * report_error text constants
63     */
64     const char* const ACCEPT_ERROR_MSG = "error accepting connection for %s: %s";
65     const char* const BIND_ERROR_MSG = "bind error for %s: %s";
66     const char* const CONNECT_ERROR_MSG = "connect to host %s failed: %s";
67     const char* const CONNLIMIT_ERROR_MSG = "connect limit exceeded for %s: %s";
68     const char* const LISTEN_ERROR_MSG = "listen error for %s: %s";
69     const char* const NONB_ERROR_MSG = "error setting non-blocking for %s: %s";
70     const char* const PEERNAME_ERROR_MSG = "getpeername failed for %s: %s";
71     const char* const POLL_ERROR_MSG = "poll error for %s: %s";
72     const char* const REGISTER_ERROR_MSG = "registering %s: %s";
73     const char* const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
74     const char* const SELECT_ERROR_MSG = "select error for %s: %s";
75     const char* const SETBUFS_ERROR_MSG = "error setting buffer size for %s: %s";
76     const char* const SOCKET_ERROR_MSG = "error creating socket for %s: %s";
77     const char* const TOS_ERROR_MSG = "error setting TOS for %s: %s";
78    
79    
80 michael 2391 static int
81     is_blocked(int error)
82 adx 30 {
83 michael 2391 return EWOULDBLOCK == error
84     #ifdef ENOMEM
85     || ENOMEM == error
86 adx 30 #endif
87 michael 2391 #ifdef ENOBUFS
88     || ENOBUFS == error
89     #endif
90     || EAGAIN == error;
91 adx 30 }
92    
93     /* get_sockerr - get the error value from the socket or the current errno
94     *
95     * Get the *real* error from the socket (well try to anyway..).
96     * This may only work when SO_DEBUG is enabled but its worth the
97     * gamble anyway.
98     */
99     int
100     get_sockerr(int fd)
101     {
102     int errtmp = errno;
103     #ifdef SO_ERROR
104     int err = 0;
105     socklen_t len = sizeof(err);
106    
107 michael 967 if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len))
108 adx 30 {
109     if (err)
110     errtmp = err;
111     }
112     errno = errtmp;
113     #endif
114     return errtmp;
115     }
116    
117 michael 2391 /** Mark a socket's address as reusable.
118     * @param[in] fd %Socket file descriptor to manipulate.
119     * @return Non-zero on success, or zero on failure.
120     */
121     int
122     os_set_reuseaddr(int fd)
123     {
124     unsigned int opt = 1;
125    
126     return !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
127     }
128    
129     /** Set a socket's send and receive buffer sizes.
130     * @param[in] fd %Socket file descriptor to manipulate.
131     * @param[in] ssize New send buffer size.
132     * @param[in] rsize New receive buffer size.
133     * @return Non-zero on success, or zero on failure.
134     */
135     int
136     os_set_sockbufs(int fd, unsigned int ssize, unsigned int rsize)
137     {
138     unsigned int sopt = ssize;
139     unsigned int ropt = rsize;
140    
141     return !setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &ropt, sizeof(ropt)) &&
142     !setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sopt, sizeof(sopt));
143     }
144    
145     /** Set a socket's "type of service" value.
146     * @param[in] fd %Socket file descriptor to manipulate.
147     * @param[in] tos New type of service value to use.
148     * @return Non-zero on success, or zero on failure.
149     */
150     int
151     os_set_tos(int fd, int tos)
152     {
153     #if defined(IP_TOS) && defined(IPPROTO_IP)
154     unsigned int opt = tos;
155    
156     return !setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
157     #else
158     return 1;
159     #endif
160     }
161    
162     /** Disable IP options on a socket.
163     * @param[in] fd %Socket file descriptor to manipulate.
164     * @return Non-zero on success, or zero on failure.
165     */
166     int
167     os_disable_options(int fd)
168     {
169     #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
170     return !setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0);
171     #else
172     return 1;
173     #endif
174     }
175    
176     /** Start listening on a socket.
177     * @param[in] fd Disconnected file descriptor.
178     * @param[in] backlog Maximum number of un-accept()ed connections to keep.
179     * @return Non-zero on success; zero on error.
180     */
181     int
182     os_set_listen(int fd, int backlog)
183     {
184     return !listen(fd, backlog);
185     }
186    
187     /** Attempt to read from a non-blocking socket.
188     * @param[in] fd File descriptor to read from.
189     * @param[out] buf Output buffer to read into.
190     * @param[in] length Number of bytes to read.
191     * @param[out] count_out Receives number of bytes actually read.
192     * @return An IOResult value indicating status.
193     */
194     IOResult
195     os_recv_nonb(int fd, char *buf, unsigned int length, unsigned int *count_out)
196     {
197     int res = 0;
198    
199     assert(buf);
200     assert(count_out);
201    
202     if ((res = recv(fd, buf, length, 0)) > 0)
203     {
204     *count_out = (unsigned int)res;
205     return IO_SUCCESS;
206     }
207    
208     if (res == 0)
209     {
210     *count_out = 0;
211     errno = 0; /* Or ECONNRESET? */
212     return IO_FAILURE;
213     }
214    
215     *count_out = 0;
216     return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
217     }
218    
219     /** Attempt to read from a non-blocking UDP socket.
220     * @param[in] fd File descriptor to read from.
221     * @param[out] buf Output buffer to read into.
222     * @param[in] length Number of bytes to read.
223     * @param[out] length_out Receives number of bytes actually read.
224     * @param[out] addr_out Peer address that sent the message.
225     * @return An IOResult value indicating status.
226     */
227     IOResult
228     os_recvfrom_nonb(int fd, char *buf, unsigned int length,
229     unsigned int *length_out,
230     struct irc_ssaddr *addr)
231     {
232     unsigned int len = sizeof(struct irc_ssaddr);
233     int res = 0;
234    
235     assert(buf);
236     assert(length_out);
237     assert(addr_out);
238    
239     res = recvfrom(fd, buf, length, 0, (struct sockaddr *)addr, &len);
240    
241     if (res > -1)
242     {
243     *length_out = res;
244     return IO_SUCCESS;
245     }
246    
247     *length_out = 0;
248     return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
249     }
250    
251     /** Attempt to write on a connected socket.
252     * @param[in] fd File descriptor to write to.
253     * @param[in] buf Output buffer to send from.
254     * @param[in] length Number of bytes to write.
255     * @param[out] count_out Receives number of bytes actually written.
256     * @return An IOResult value indicating status.
257     */
258     IOResult
259     os_send_nonb(int fd, const char *buf, unsigned int length,
260     unsigned int *count_out)
261     {
262     int res = 0;
263    
264     assert(buf);
265     assert(count_out);
266    
267     if ((res = send(fd, buf, length, 0)) > -1)
268     {
269     *count_out = (unsigned) res;
270     return IO_SUCCESS;
271     }
272    
273     *count_out = 0;
274     return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
275     }
276    
277     /** Attempt a vectored write on a connected socket.
278     * @param[in] fd File descriptor to write to.
279     * @param[in] buf Message queue to send from.
280     * @param[out] count_in Number of bytes mapped from \a buf.
281     * @param[out] count_out Receives number of bytes actually written.
282     * @return An IOResult value indicating status.
283     */
284     IOResult
285     os_sendv_nonb(int fd, struct MsgQ *buf, unsigned int *count_in,
286     unsigned int *count_out)
287     {
288     int res = 0, count = 0;
289     struct iovec iov[IOV_MAX];
290    
291     assert(buf);
292     assert(count_in);
293     assert(count_out);
294    
295     *count_in = 0;
296     count = msgq_mapiov(buf, iov, IOV_MAX, count_in);
297    
298     if ((res = writev(fd, iov, count)) > -1)
299     {
300     *count_out = (unsigned int)res;
301     return IO_SUCCESS;
302     }
303    
304     *count_out = 0;
305     return is_blocked(errno) ? IO_BLOCKED : IO_FAILURE;
306     }
307    
308 adx 30 /*
309     * report_error - report an error from an errno.
310     * Record error to log and also send a copy to all *LOCAL* opers online.
311     *
312     * text is a *format* string for outputing error. It must
313     * contain only two '%s', the first will be replaced
314     * by the sockhost from the client_p, and the latter will
315     * be taken from sys_errlist[errno].
316     *
317     * client_p if not NULL, is the *LOCAL* client associated with
318     * the error.
319     *
320     * Cannot use perror() within daemon. stderr is closed in
321     * ircd and cannot be used. And, worse yet, it might have
322     * been reassigned to a normal connection...
323     *
324     * Actually stderr is still there IFF ircd was run with -s --Rodder
325     */
326    
327     void
328 michael 2389 report_error(int level, const char *text, const char *who, int error)
329 adx 30 {
330 michael 2389 int errtmp = errno; /* debug may change 'errno' */
331     const char *errmsg = (error) ? strerror(error) : "";
332 adx 30
333 michael 2389 if (!errmsg)
334     errmsg = "Unknown error";
335    
336     if (EmptyString(who))
337     who = "unknown";
338    
339 michael 1618 sendto_realops_flags(UMODE_DEBUG, level, SEND_NOTICE,
340 michael 2389 text, who, errmsg);
341     ilog(LOG_TYPE_IRCD, text, who, errmsg);
342     errno = errtmp;
343 adx 30 }
344    
345     /*
346     * setup_socket()
347     *
348     * Set the socket non-blocking, and other wonderful bits.
349     */
350 michael 2389 static void
351     setup_socket(int fd)
352 adx 30 {
353     int opt = 1;
354    
355 michael 967 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
356 adx 30
357     #ifdef IPTOS_LOWDELAY
358     opt = IPTOS_LOWDELAY;
359 michael 967 setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
360 adx 30 #endif
361    
362     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
363     }
364    
365     /*
366     * close_connection
367     * Close the physical connection. This function must make
368     * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
369     */
370     void
371     close_connection(struct Client *client_p)
372     {
373 michael 1391 dlink_node *ptr = NULL;
374 adx 30
375 michael 1391 assert(client_p);
376 adx 30
377 michael 683 if (!IsDead(client_p))
378     {
379     /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
380     /* there is still a chance that we might send data to this socket
381     * even if it is marked as blocked (COMM_SELECT_READ handler is called
382     * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
383     */
384     ClearSendqBlocked(client_p);
385     send_queued_write(client_p);
386     }
387    
388 michael 1143 if (IsClient(client_p))
389 adx 30 {
390 michael 1143 ++ServerStats.is_cl;
391     ServerStats.is_cbs += client_p->localClient->send.bytes;
392     ServerStats.is_cbr += client_p->localClient->recv.bytes;
393 michael 1241 ServerStats.is_cti += CurrentTime - client_p->localClient->firsttime;
394 michael 1143 }
395     else if (IsServer(client_p))
396     {
397 michael 896 ++ServerStats.is_sv;
398     ServerStats.is_sbs += client_p->localClient->send.bytes;
399     ServerStats.is_sbr += client_p->localClient->recv.bytes;
400 michael 1241 ServerStats.is_sti += CurrentTime - client_p->localClient->firsttime;
401 adx 30
402 michael 1391 DLINK_FOREACH(ptr, server_items.head)
403 adx 30 {
404 michael 1632 struct MaskItem *conf = ptr->data;
405 michael 1391
406     if (irccmp(conf->name, client_p->name))
407     continue;
408    
409 adx 30 /*
410 michael 1391 * Reset next-connect cycle of all connect{} blocks that match
411     * this servername.
412 adx 30 */
413 michael 1649 conf->until = CurrentTime + conf->class->con_freq;
414 adx 30 }
415     }
416     else
417 michael 896 ++ServerStats.is_ni;
418 adx 30
419 michael 2389 if (s_fd(&client_p->localClient->socket)> -1)
420 michael 451 {
421 michael 2389 flush_connections(client_p);
422     dlinkDelete(&client_p->localClient->node, &connection_list);
423     close(s_fd(&client_p->localClient->socket));
424     socket_del(&client_p->localClient->socket); /* Queue a socket delete */
425     s_fd(&client_p->localClient->socket) = -1;
426 michael 451 }
427 adx 30
428 michael 2389 AddFlag(client_p, FLAGS_DEADSOCKET);
429    
430     MsgQClear(&client_p->localClient->sendQ);
431     client_drop_sendq(client_p->localClient);
432     DBufClear(&client_p->localClient->recvQ);
433    
434 adx 30 MyFree(client_p->localClient->passwd);
435 michael 1632 detach_conf(client_p, CONF_CLIENT|CONF_OPER|CONF_SERVER);
436 adx 30 client_p->from = NULL; /* ...this should catch them! >:) --msa */
437 michael 2389
438     if (client_p->localClient->listener)
439     {
440     assert(0 < client_p->localClient->listener->ref_count);
441     if (0 == --client_p->localClient->listener->ref_count &&
442     !client_p->localClient->listener->active)
443     free_listener(client_p->localClient->listener);
444     }
445 adx 30 }
446    
447     #ifdef HAVE_LIBCRYPTO
448     /*
449     * ssl_handshake - let OpenSSL initialize the protocol. Register for
450     * read/write events if necessary.
451     */
452     static void
453     ssl_handshake(int fd, struct Client *client_p)
454     {
455 michael 2228 X509 *cert = NULL;
456 adx 30 int ret = SSL_accept(client_p->localClient->fd.ssl);
457 michael 2228 int err = SSL_get_error(client_p->localClient->fd.ssl, ret);
458 adx 30
459 michael 2228 ilog(LOG_TYPE_IRCD, "SSL Error %d %s", err, ERR_error_string(err, NULL));
460    
461     if ((cert = SSL_get_peer_certificate(client_p->localClient->fd.ssl)))
462     {
463     int res = SSL_get_verify_result(client_p->localClient->fd.ssl);
464 michael 2235 char buf[EVP_MAX_MD_SIZE * 2 + 1] = { '\0' };
465 michael 2287 unsigned char md[EVP_MAX_MD_SIZE] = { '\0' };
466 michael 2228
467     if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
468     res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
469     res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
470 michael 2229 {
471 michael 2235 unsigned int i = 0, n = 0;
472    
473     if (X509_digest(cert, EVP_sha256(), md, &n))
474     {
475     for (; i < n; ++i)
476     snprintf(buf + 2 * i, 3, "%02X", md[i]);
477     client_p->certfp = xstrdup(buf);
478     }
479 michael 2229 }
480 michael 2228 else
481     ilog(LOG_TYPE_IRCD, "Client %s!%s@%s gave bad SSL client certificate: %d",
482     client_p->name, client_p->username, client_p->host, res);
483     X509_free(cert);
484     }
485    
486 adx 30 if (ret <= 0)
487 michael 2228 {
488 adx 30 switch (SSL_get_error(client_p->localClient->fd.ssl, ret))
489     {
490     case SSL_ERROR_WANT_WRITE:
491     comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
492     (PF *) ssl_handshake, client_p, 0);
493     return;
494    
495     case SSL_ERROR_WANT_READ:
496     comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
497     (PF *) ssl_handshake, client_p, 0);
498     return;
499    
500     default:
501     exit_client(client_p, client_p, "Error during SSL handshake");
502     return;
503     }
504 michael 2228 }
505 adx 30
506 michael 2181 start_auth(client_p);
507 adx 30 }
508     #endif
509    
510     /*
511     * add_connection - creates a client which has just connected to us on
512     * the given fd. The sockhost field is initialized with the ip# of the host.
513     * An unique id is calculated now, in case it is needed for auth.
514     * The client is sent to the auth module for verification, and not put in
515     * any client list yet.
516     */
517     void
518 michael 549 add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd)
519 adx 30 {
520 michael 1123 struct Client *new_client = make_client(NULL);
521 michael 549
522 adx 30 fd_open(&new_client->localClient->fd, fd, 1,
523     (listener->flags & LISTENER_SSL) ?
524     "Incoming SSL connection" : "Incoming connection");
525    
526 michael 1123 /*
527 adx 30 * copy address to 'sockhost' as a string, copy it to host too
528     * so we have something valid to put into error messages...
529     */
530 michael 549 memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr));
531 adx 30
532 michael 1123 getnameinfo((struct sockaddr *)&new_client->localClient->ip,
533     new_client->localClient->ip.ss_len, new_client->sockhost,
534     sizeof(new_client->sockhost), NULL, 0, NI_NUMERICHOST);
535 adx 30 new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family;
536 michael 1072
537 michael 1858 #ifdef HAVE_LIBGEOIP
538     /* XXX IPV6 SUPPORT XXX */
539     if (irn->ss.ss_family == AF_INET && geoip_ctx)
540     {
541     const struct sockaddr_in *v4 = (const struct sockaddr_in *)&new_client->localClient->ip;
542     new_client->localClient->country_id = GeoIP_id_by_ipnum(geoip_ctx, (unsigned long)ntohl(v4->sin_addr.s_addr));
543     }
544     #endif
545    
546 michael 1123 if (new_client->sockhost[0] == ':' && new_client->sockhost[1] == ':')
547 adx 30 {
548 michael 1072 strlcpy(new_client->host, "0", sizeof(new_client->host));
549     strlcpy(new_client->host+1, new_client->sockhost, sizeof(new_client->host)-1);
550 michael 1123 memmove(new_client->sockhost+1, new_client->sockhost, sizeof(new_client->sockhost)-1);
551     new_client->sockhost[0] = '0';
552 michael 549 }
553     else
554 michael 1072 strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
555 adx 30
556     new_client->localClient->listener = listener;
557     ++listener->ref_count;
558    
559     #ifdef HAVE_LIBCRYPTO
560 michael 549 if (listener->flags & LISTENER_SSL)
561 adx 30 {
562 michael 967 if ((new_client->localClient->fd.ssl = SSL_new(ServerInfo.server_ctx)) == NULL)
563 adx 30 {
564 michael 1247 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
565 adx 30 ERR_error_string(ERR_get_error(), NULL));
566    
567     SetDead(new_client);
568     exit_client(new_client, new_client, "SSL_new failed");
569     return;
570     }
571    
572 michael 2246 AddFlag(new_client, FLAGS_SSL);
573 adx 30 SSL_set_fd(new_client->localClient->fd.ssl, fd);
574     ssl_handshake(0, new_client);
575     }
576     else
577     #endif
578 michael 2181 start_auth(new_client);
579 michael 2389 #ifdef NEWIO
580    
581     s_fd(&new_client->localClient->socket) = fd;
582     if (!socket_add(&new_client->localClient->socket, client_sock_callback,
583     new_client->localClient, SS_CONNECTED, 0, fd))
584     {
585     ++ServerStats.is_ref;
586     write(fd, register_message, strlen(register_message));
587     close(fd);
588     s_fd(&new_client->localClient->socket) = -1;
589     return;
590     }
591    
592     new_client->localClient->freeflag |= FREEFLAG_SOCKET;
593     new_client->localClient->listener = listener;
594     ++listener->ref_count;
595    
596     /* if we've made it this far we can put the client on the auth query pile */
597     start_auth(new_client);
598     #endif
599 adx 30 }
600    
601 michael 2389 /** Determines whether to tell the events engine we're interested in
602     * writable events.
603     * \param client_p Client for which to decide this.
604     */
605     void
606     update_write(struct Client *client_p)
607     {
608     /*
609     * If there are messages that need to be sent along, or if the client
610     * is in the middle of a /list, then we need to tell the engine that
611     * we're interested in writable events--otherwise, we need to drop
612     * that interest.
613     */
614     socket_events(&client_p->localClient->socket,
615     ((MsgQLength(&client_p->localClient->sendQ) || client_p->localClient->list_task) ?
616     SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE);
617     }
618    
619     /** Read a 'packet' of data from a connection and process it. Read in
620     * 8k chunks to give a better performance rating (for server
621     * connections). Do some tricky stuff for client connections to make
622     * sure they don't do any flooding >:-) -avalon
623     * @param client_p Client from which to read data.
624     * @param socket_ready If non-zero, more data can be read from the client's socket.
625     * @return Positive number on success, zero on connection-fatal failure, negative
626     * if user is killed.
627     */
628     static int
629     read_packet(struct Client *client_p, int socket_ready)
630     {
631     unsigned int dolen = 0, length = 0;
632    
633     if (socket_ready && !(IsClient(client_p) &&
634     DBufLength&(client_p->localClient->recvQ) > feature_int(FEAT_CLIENT_FLOOD)))
635     {
636     switch (os_recv_nonb(cli_fd(client_p), readbuf, sizeof(readbuf), &length))
637     {
638     case IO_SUCCESS:
639     if (length)
640     {
641     client_p->localClient->lasttime = CurrentTime;
642    
643     if (client_p->localClient->lasttime > client_p->localClient->since)
644     client_p->localClient->since = CurrentTime;
645    
646     ClearPingSent(client_p);
647     DelFlag(client_p, FLAGS_NOEWLINE);
648     }
649     break;
650    
651     case IO_BLOCKED:
652     break;
653     case IO_FAILURE:
654     client_p->localClient->error = errno;
655     /* AddFlag(client_p, FLAG_DEADSOCKET); */
656     return 0;
657     }
658     }
659    
660     /*
661     * For server connections, we process as many as we can without
662     * worrying about the time of day or anything :)
663     */
664     if (length > 0 && IsServer(client_p))
665     return server_dopacket(client_p, readbuf, length);
666     else if (length > 0 && (IsHandshake(client_p) || IsConnecting(client_p)))
667     return connect_dopacket(client_p, readbuf, length);
668     else
669     {
670     /*
671     * Before we even think of parsing what we just read, stick
672     * it on the end of the receive queue and do it when its
673     * turn comes around.
674     */
675     if (length > 0 && !dbuf_put(&client_p->localClient->recvQ, readbuf, length))
676     return exit_client(client_p, client_p, "dbuf_put fail");
677    
678     if (DBufLength(&client_p->localClient_recvQ) > feature_int(FEAT_CLIENT_FLOOD))
679     return exit_client(client_p, client_p, "Excess Flood");
680    
681     while (DBufLength(&client_p->localClient->recvQ) && !NoNewLine(client_p) &&
682     (IsTrusted(client_p) || cli_since(client_p) - CurrentTime < 10))
683     {
684     dolen = dbuf_getmsg(&client_p->localClient->recvQ,
685     client_p->localClient->buffer, IRCD_BUFSIZE);
686    
687     /*
688     * Devious looking...whats it do ? well..if a client
689     * sends a *long* message without any CR or LF, then
690     * dbuf_getmsg fails and we pull it out using this
691     * loop which just gets the next 512 bytes and then
692     * deletes the rest of the buffer contents.
693     * -avalon
694     */
695     if (dolen == 0)
696     {
697     if (DBufLength(&client_p->localClient->recvQ) < 510)
698     AddFlag(client_p, FLAGS_NONEWLINE);
699     else
700     {
701     /*
702     * More than 512 bytes in the line - drop the input and yell
703     * at the client.
704     */
705     DBufClear(&client_p->localClient->recvQ);
706     send_reply(client_p, ERR_INPUTTOOLONG);
707     }
708     }
709     else if (client_dopacket(client_p, dolen) == CPTR_KILLED)
710     return CPTR_KILLED;
711    
712     /*
713     * If it has become registered as a Server
714     * then skip the per-message parsing below.
715     */
716     if (IsHandshake(client_p) || IsServer(client_p))
717     {
718     while (-1)
719     {
720     dolen = dbuf_get(&client_p->localClient->recvQ, readbuf, sizeof(readbuf));
721    
722     if (dolen <= 0)
723     return 1;
724     if (dolen == 0)
725     {
726     if (DBufLength(&client_p->localClient->recvQ) < 510)
727     AddFlag(client_p, FLAGS_NONEWLINE);
728     else
729     DBufClear(&client_p->localClient->recvQ);
730     }
731     else if ((IsServer(client_p) &&
732     server_dopacket(client_p, readbuf, dolen) == CPTR_KILLED) ||
733     (!IsServer(client_p) &&
734     connect_dopacket(client_p, readbuf, dolen) == CPTR_KILLED))
735     return CPTR_KILLED;
736     }
737     }
738     }
739    
740     /* If there's still data to process, wait 2 seconds first */
741     if (DBufLength(&client_p->localClient->recvQ) && !HasFlag(client_p, FLAGS_NONEWLINE) &&
742     !t_onqueue(&client_p->localClient->proc))
743     {
744     client_p->localClient->freeflag |= FREEFLAG_TIMER;
745     timer_add(&client_p->localClient->proc, client_timer_callback, client_p->localClient,
746     TT_RELATIVE, 2);
747     }
748     }
749     return 1;
750     }
751    
752     /** Attempt to send a sequence of bytes to the connection.
753     * As a side effect, updates \a cptr's FLAG_BLOCKED setting
754     * and sendB/sendK fields.
755     * @param cptr Client that should receive data.
756     * @param buf Message buffer to send to client.
757     * @return Negative on connection-fatal error; otherwise
758     * number of bytes sent.
759     */
760     unsigned int
761     deliver_it(struct Client *client_p, struct MsgQ *buf)
762     {
763     unsigned int bytes_written = 0, bytes_count = 0;
764    
765     assert(client_p);
766    
767     switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written))
768     {
769     case IO_SUCCESS:
770     DelFlag(client_p, FLAG_BLOCKED);
771    
772     client_p->localClient->send.bytes += bytes_written;
773     me.localClient->send.bytes += bytes_written;
774    
775     /* A partial write implies that future writes will block. */
776     if (bytes_written < bytes_count)
777     AddFlag(client_p, FLAG_BLOCKED);
778     break;
779     case IO_BLOCKED:
780     AddFlag(client_p, FLAG_BLOCKED);
781     break;
782     case IO_FAILURE:
783     client_p->localClient->error = errno;
784     AddFlag(client_p, FLAG_DEADSOCKET);
785     break;
786     }
787    
788     return bytes_written;
789     }
790    
791 adx 30 /*
792     * stolen from squid - its a neat (but overused! :) routine which we
793     * can use to see whether we can ignore this errno or not. It is
794     * generally useful for non-blocking network IO related errnos.
795     * -- adrian
796     */
797     int
798     ignoreErrno(int ierrno)
799     {
800     switch (ierrno)
801     {
802     case EINPROGRESS:
803     case EWOULDBLOCK:
804     #if EAGAIN != EWOULDBLOCK
805     case EAGAIN:
806     #endif
807     case EALREADY:
808     case EINTR:
809     #ifdef ERESTART
810     case ERESTART:
811     #endif
812     return 1;
813     default:
814     return 0;
815     }
816     }
817    
818     /*
819     * comm_settimeout() - set the socket timeout
820     *
821     * Set the timeout for the fd
822     */
823     void
824     comm_settimeout(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
825     {
826     assert(fd->flags.open);
827    
828     fd->timeout = CurrentTime + (timeout / 1000);
829     fd->timeout_handler = callback;
830     fd->timeout_data = cbdata;
831     }
832    
833     /*
834     * comm_setflush() - set a flush function
835     *
836     * A flush function is simply a function called if found during
837     * comm_timeouts(). Its basically a second timeout, except in this case
838     * I'm too lazy to implement multiple timeout functions! :-)
839     * its kinda nice to have it separate, since this is designed for
840     * flush functions, and when comm_close() is implemented correctly
841     * with close functions, we _actually_ don't call comm_close() here ..
842     * -- originally Adrian's notes
843     * comm_close() is replaced with fd_close() in fdlist.c
844     */
845     void
846     comm_setflush(fde_t *fd, time_t timeout, PF *callback, void *cbdata)
847     {
848     assert(fd->flags.open);
849    
850     fd->flush_timeout = CurrentTime + (timeout / 1000);
851     fd->flush_handler = callback;
852     fd->flush_data = cbdata;
853     }
854    
855     /*
856     * comm_checktimeouts() - check the socket timeouts
857     *
858     * All this routine does is call the given callback/cbdata, without closing
859     * down the file descriptor. When close handlers have been implemented,
860     * this will happen.
861     */
862     void
863     comm_checktimeouts(void *notused)
864     {
865     int i;
866     fde_t *F;
867     PF *hdl;
868     void *data;
869    
870     for (i = 0; i < FD_HASH_SIZE; i++)
871     for (F = fd_hash[i]; F != NULL; F = fd_next_in_loop)
872     {
873     assert(F->flags.open);
874     fd_next_in_loop = F->hnext;
875    
876     /* check flush functions */
877     if (F->flush_handler && F->flush_timeout > 0 &&
878     F->flush_timeout < CurrentTime)
879     {
880     hdl = F->flush_handler;
881     data = F->flush_data;
882     comm_setflush(F, 0, NULL, NULL);
883     hdl(F, data);
884     }
885    
886     /* check timeouts */
887     if (F->timeout_handler && F->timeout > 0 &&
888     F->timeout < CurrentTime)
889     {
890     /* Call timeout handler */
891     hdl = F->timeout_handler;
892     data = F->timeout_data;
893     comm_settimeout(F, 0, NULL, NULL);
894     hdl(F, data);
895     }
896     }
897     }
898    
899     /*
900     * void comm_connect_tcp(int fd, const char *host, unsigned short port,
901     * struct sockaddr *clocal, int socklen,
902     * CNCB *callback, void *data, int aftype, int timeout)
903     * Input: An fd to connect with, a host and port to connect to,
904     * a local sockaddr to connect from + length(or NULL to use the
905     * default), a callback, the data to pass into the callback, the
906     * address family.
907     * Output: None.
908     * Side-effects: A non-blocking connection to the host is started, and
909     * if necessary, set up for selection. The callback given
910     * may be called now, or it may be called later.
911     */
912     void
913     comm_connect_tcp(fde_t *fd, const char *host, unsigned short port,
914     struct sockaddr *clocal, int socklen, CNCB *callback,
915     void *data, int aftype, int timeout)
916     {
917     struct addrinfo hints, *res;
918 michael 992 char portname[PORTNAMELEN + 1];
919 adx 30
920     assert(callback);
921     fd->connect.callback = callback;
922     fd->connect.data = data;
923    
924     fd->connect.hostaddr.ss.ss_family = aftype;
925     fd->connect.hostaddr.ss_port = htons(port);
926    
927     /* Note that we're using a passed sockaddr here. This is because
928     * generally you'll be bind()ing to a sockaddr grabbed from
929     * getsockname(), so this makes things easier.
930     * XXX If NULL is passed as local, we should later on bind() to the
931     * virtual host IP, for completeness.
932     * -- adrian
933     */
934     if ((clocal != NULL) && (bind(fd->fd, clocal, socklen) < 0))
935     {
936     /* Failure, call the callback with COMM_ERR_BIND */
937     comm_connect_callback(fd, COMM_ERR_BIND);
938     /* ... and quit */
939     return;
940     }
941    
942     /* Next, if we have been given an IP, get the addr and skip the
943     * DNS check (and head direct to comm_connect_tryconnect().
944     */
945     memset(&hints, 0, sizeof(hints));
946     hints.ai_family = AF_UNSPEC;
947     hints.ai_socktype = SOCK_STREAM;
948     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
949    
950 michael 992 snprintf(portname, sizeof(portname), "%d", port);
951 adx 30
952 michael 1123 if (getaddrinfo(host, portname, &hints, &res))
953 adx 30 {
954     /* Send the DNS request, for the next level */
955 db 871 if (aftype == AF_INET6)
956 michael 992 gethost_byname_type(comm_connect_dns_callback, fd, host, T_AAAA);
957 db 871 else
958 michael 992 gethost_byname_type(comm_connect_dns_callback, fd, host, T_A);
959 adx 30 }
960     else
961     {
962     /* We have a valid IP, so we just call tryconnect */
963     /* Make sure we actually set the timeout here .. */
964     assert(res != NULL);
965     memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen);
966     fd->connect.hostaddr.ss_len = res->ai_addrlen;
967     fd->connect.hostaddr.ss.ss_family = res->ai_family;
968 michael 1123 freeaddrinfo(res);
969 adx 30 comm_settimeout(fd, timeout*1000, comm_connect_timeout, NULL);
970     comm_connect_tryconnect(fd, NULL);
971     }
972     }
973    
974     /*
975     * comm_connect_callback() - call the callback, and continue with life
976     */
977     static void
978     comm_connect_callback(fde_t *fd, int status)
979     {
980     CNCB *hdl;
981    
982     /* This check is gross..but probably necessary */
983     if (fd->connect.callback == NULL)
984     return;
985    
986     /* Clear the connect flag + handler */
987     hdl = fd->connect.callback;
988     fd->connect.callback = NULL;
989    
990     /* Clear the timeout handler */
991     comm_settimeout(fd, 0, NULL, NULL);
992    
993     /* Call the handler */
994     hdl(fd, status, fd->connect.data);
995     }
996    
997     /*
998     * comm_connect_timeout() - this gets called when the socket connection
999     * times out. This *only* can be called once connect() is initially
1000     * called ..
1001     */
1002     static void
1003     comm_connect_timeout(fde_t *fd, void *notused)
1004     {
1005     /* error! */
1006     comm_connect_callback(fd, COMM_ERR_TIMEOUT);
1007     }
1008    
1009     /*
1010     * comm_connect_dns_callback() - called at the completion of the DNS request
1011     *
1012     * The DNS request has completed, so if we've got an error, return it,
1013     * otherwise we initiate the connect()
1014     */
1015     static void
1016 michael 992 comm_connect_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
1017 adx 30 {
1018     fde_t *F = vptr;
1019    
1020 michael 992 if (name == NULL)
1021 adx 30 {
1022     comm_connect_callback(F, COMM_ERR_DNS);
1023     return;
1024     }
1025    
1026     /* No error, set a 10 second timeout */
1027     comm_settimeout(F, 30*1000, comm_connect_timeout, NULL);
1028    
1029     /* Copy over the DNS reply info so we can use it in the connect() */
1030     /*
1031     * Note we don't fudge the refcount here, because we aren't keeping
1032     * the DNS record around, and the DNS cache is gone anyway..
1033     * -- adrian
1034     */
1035 michael 992 memcpy(&F->connect.hostaddr, addr, addr->ss_len);
1036 adx 30 /* The cast is hacky, but safe - port offset is same on v4 and v6 */
1037     ((struct sockaddr_in *) &F->connect.hostaddr)->sin_port =
1038     F->connect.hostaddr.ss_port;
1039 michael 992 F->connect.hostaddr.ss_len = addr->ss_len;
1040 adx 30
1041     /* Now, call the tryconnect() routine to try a connect() */
1042     comm_connect_tryconnect(F, NULL);
1043     }
1044    
1045     /* static void comm_connect_tryconnect(int fd, void *notused)
1046     * Input: The fd, the handler data(unused).
1047     * Output: None.
1048     * Side-effects: Try and connect with pending connect data for the FD. If
1049     * we succeed or get a fatal error, call the callback.
1050     * Otherwise, it is still blocking or something, so register
1051     * to select for a write event on this FD.
1052     */
1053     static void
1054     comm_connect_tryconnect(fde_t *fd, void *notused)
1055     {
1056     int retval;
1057    
1058     /* This check is needed or re-entrant s_bsd_* like sigio break it. */
1059     if (fd->connect.callback == NULL)
1060     return;
1061    
1062     /* Try the connect() */
1063     retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr,
1064     fd->connect.hostaddr.ss_len);
1065    
1066     /* Error? */
1067     if (retval < 0)
1068     {
1069     /*
1070     * If we get EISCONN, then we've already connect()ed the socket,
1071     * which is a good thing.
1072     * -- adrian
1073     */
1074     if (errno == EISCONN)
1075     comm_connect_callback(fd, COMM_OK);
1076     else if (ignoreErrno(errno))
1077     /* Ignore error? Reschedule */
1078     comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect,
1079     NULL, 0);
1080     else
1081     /* Error? Fail with COMM_ERR_CONNECT */
1082     comm_connect_callback(fd, COMM_ERR_CONNECT);
1083     return;
1084     }
1085    
1086     /* If we get here, we've suceeded, so call with COMM_OK */
1087     comm_connect_callback(fd, COMM_OK);
1088     }
1089    
1090     /*
1091     * comm_errorstr() - return an error string for the given error condition
1092     */
1093     const char *
1094     comm_errstr(int error)
1095     {
1096     if (error < 0 || error >= COMM_ERR_MAX)
1097     return "Invalid error number!";
1098     return comm_err_str[error];
1099     }
1100    
1101     /*
1102     * comm_open() - open a socket
1103     *
1104     * This is a highly highly cut down version of squid's comm_open() which
1105     * for the most part emulates socket(), *EXCEPT* it fails if we're about
1106     * to run out of file descriptors.
1107     */
1108     int
1109     comm_open(fde_t *F, int family, int sock_type, int proto, const char *note)
1110     {
1111     int fd;
1112    
1113     /* First, make sure we aren't going to run out of file descriptors */
1114     if (number_fd >= hard_fdlimit)
1115     {
1116     errno = ENFILE;
1117     return -1;
1118     }
1119    
1120     /*
1121     * Next, we try to open the socket. We *should* drop the reserved FD
1122     * limit if/when we get an error, but we can deal with that later.
1123     * XXX !!! -- adrian
1124     */
1125     fd = socket(family, sock_type, proto);
1126     if (fd < 0)
1127     return -1; /* errno will be passed through, yay.. */
1128    
1129 michael 2389 setup_socket(fd);
1130 adx 30
1131     /* update things in our fd tracking */
1132     fd_open(F, fd, 1, note);
1133     return 0;
1134     }
1135    
1136     /*
1137     * comm_accept() - accept an incoming connection
1138     *
1139     * This is a simple wrapper for accept() which enforces FD limits like
1140     * comm_open() does. Returned fd must be either closed or tagged with
1141     * fd_open (this function no longer does it).
1142     */
1143     int
1144     comm_accept(struct Listener *lptr, struct irc_ssaddr *pn)
1145     {
1146     int newfd;
1147     socklen_t addrlen = sizeof(struct irc_ssaddr);
1148    
1149     if (number_fd >= hard_fdlimit)
1150     {
1151     errno = ENFILE;
1152     return -1;
1153     }
1154    
1155     /*
1156     * Next, do the accept(). if we get an error, we should drop the
1157     * reserved fd limit, but we can deal with that when comm_open()
1158     * also does it. XXX -- adrian
1159     */
1160 michael 1013 newfd = accept(lptr->fd.fd, (struct sockaddr *)pn, &addrlen);
1161 adx 30 if (newfd < 0)
1162     return -1;
1163    
1164     #ifdef IPV6
1165     remove_ipv6_mapping(pn);
1166     #else
1167     pn->ss_len = addrlen;
1168     #endif
1169    
1170     execute_callback(setup_socket_cb, newfd);
1171    
1172     /* .. and return */
1173     return newfd;
1174     }
1175    
1176     /*
1177     * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address
1178 michael 1122 * OSes with IPv6 mapping listening on both
1179 adx 30 * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures
1180     *
1181     */
1182     #ifdef IPV6
1183     void
1184     remove_ipv6_mapping(struct irc_ssaddr *addr)
1185     {
1186     if (addr->ss.ss_family == AF_INET6)
1187     {
1188 michael 1122 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr))
1189     {
1190     struct sockaddr_in6 v6;
1191     struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
1192 adx 30
1193 michael 1122 memcpy(&v6, addr, sizeof(v6));
1194     memset(v4, 0, sizeof(struct sockaddr_in));
1195     memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr));
1196    
1197 adx 30 addr->ss.ss_family = AF_INET;
1198     addr->ss_len = sizeof(struct sockaddr_in);
1199     }
1200     else
1201     addr->ss_len = sizeof(struct sockaddr_in6);
1202     }
1203     else
1204     addr->ss_len = sizeof(struct sockaddr_in);
1205     }
1206     #endif
1207 michael 2389
1208     /** Process events on a client socket.
1209     * @param ev Socket event structure that has a struct Connection as
1210     * its associated data.
1211     */
1212     static void
1213     client_sock_callback(struct Event *ev)
1214     {
1215     struct Client *client_p = NULL;
1216     struct Connection *con = NULL;
1217     const char *fmt = "%s";
1218     const char *fallback = NULL;
1219    
1220     assert(ev_socket(ev));
1221     assert(s_data(ev_socket(ev)));
1222    
1223     con = (struct Connection *)s_data(ev_socket(ev));
1224    
1225     assert(con->localClient || ev_type(ev) == ET_DESTROY);
1226    
1227     client_p = con->client_p;
1228    
1229     assert(!client_p || con == client_p->localClient);
1230    
1231     switch (ev_type(ev))
1232     {
1233     case ET_DESTROY:
1234     con->freeflag &= ~FREEFLAG_SOCKET;
1235    
1236     if (!con_freeflag(con) && !client_p)
1237     free_connection(con);
1238     break;
1239    
1240     case ET_CONNECT: /* Socket connection completed */
1241     if (!completed_connection(client_p) || IsDead(client_p))
1242     fallback = client_p->info;
1243     break;
1244    
1245     case ET_ERROR: /* An error occurred */
1246     fallback = client_p->info;
1247     client_p->error = ev_data(ev);
1248    
1249     /*
1250     * If the OS told us we have a bad file descriptor, we should
1251     * record that for future reference.
1252     */
1253     if (client_p->error == EBADF)
1254     s_fd(&client_p->localClient->socket) = -1;
1255    
1256     if (s_state(&con->socket) == SS_CONNECTING)
1257     {
1258     completed_connection(client_p);
1259    
1260     /*
1261     * For some reason, the os_get_sockerr() in completed_connect()
1262     * can return 0 even when ev_data(ev) indicates a real error, so
1263     * re-assign the client error here.
1264     */
1265     client_p->error = ev_data(ev);
1266     break;
1267     }
1268    
1269     /*FALLTHROUGH*/
1270     case ET_EOF: /* End of file on socket */
1271     SetFlag(client_p, FLAG_DEADSOCKET);
1272    
1273     if ((IsServer(client_p) || IsHandshake(client_p)) && client_p->error == 0)
1274     {
1275     exit_client_msg(client_p, client_p, "Server %s closed the connection (%s)",
1276     client_p->name, client_p->servptr->->last_error_msg);
1277     return;
1278     }
1279     else
1280     {
1281     fmt = "Read error: %s";
1282     fallback = "EOF from client";
1283     }
1284    
1285     break;
1286    
1287     case ET_WRITE: /* Socket is writable */
1288     DelFlag(client_p, FLAGS_BLOCKED);
1289    
1290     if (cli_listing(client_p) && MsgQLength(&client_p->sendQ) < 2048)
1291     list_next_channels(client_p);
1292     send_queued(client_p);
1293     break;
1294    
1295     case ET_READ: /* Socket is readable */
1296     if (!IsDead(client_p))
1297     {
1298     if (read_packet(client_p, 1) == 0) /* Error while reading packet */
1299     fallback = "EOF from client";
1300     }
1301    
1302     break;
1303    
1304     default:
1305     assert(0 && "Unrecognized socket event in client_sock_callback()");
1306     break;
1307     }
1308    
1309     assert(!client_p || !client_p->localClient || con == client_p->localClient);
1310    
1311     if (fallback)
1312     {
1313     const char *msg = (client_p->error) ? strerror(client_p->error) : fallback;
1314    
1315     if (!msg)
1316     msg = "Unknown error";
1317     exit_client_msg(client_p, client_p, fmt, msg);
1318     }
1319     }
1320    
1321     /** Process a timer on client socket.
1322     * @param ev Timer event that has a struct Connection as its
1323     * associated data.
1324     */
1325     static void
1326     client_timer_callback(struct Event *ev)
1327     {
1328     struct Client *client_p = NULL;
1329     struct Connection *con = NULL;
1330    
1331     assert(ev_timer(ev));
1332     assert(t_data(ev_timer(ev)));
1333     assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));
1334    
1335     con = (struct Connection *)t_data(ev_timer(ev));
1336    
1337     assert(con->client || ev_type(ev) == ET_DESTROY);
1338    
1339     client_p = con->client;
1340    
1341     assert(!client_p || con == client_p->localClient);
1342    
1343     if (ev_type(ev) == ET_DESTROY)
1344     {
1345     conf->freeflag &= ~FREEFLAG_TIMER; /* Timer has expired... */
1346    
1347     if (!con->freeflag && !client_p)
1348     free_connection(con); /* Client is being destroyed */
1349     }
1350     else
1351     read_packet(client_p, 0); /* read_packet will re-add timer if needed */
1352    
1353     assert(!client_p || !client_p->localClient || con == client_p->localClient);
1354     }

Properties

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