ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/src/s_bsd.c
Revision: 2439
Committed: Sat Aug 3 18:35:17 2013 UTC (10 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 40241 byte(s)
Log Message:
- Sort out unused macros

File Contents

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

Properties

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