2 * ircd-ratbox: A slightly useful ircd.
3 * commio.c: Network/file related functions
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
24 * $Id: commio.c 25795 2008-07-29 15:26:55Z androsyn $
26 #include <libratbox_config.h>
27 #include <ratbox_lib.h>
28 #include <commio-int.h>
29 #include <commio-ssl.h>
30 #include <event-int.h>
37 #define MSG_NOSIGNAL 0
50 rb_dlink_list
*rb_fd_table
;
51 static rb_bh
*fd_heap
;
53 static rb_dlink_list timeout_list
;
54 static rb_dlink_list closed_list
;
56 static struct ev_entry
*rb_timeout_ev
;
59 static const char *rb_err_str
[] = { "Comm OK", "Error during bind()",
60 "Error during DNS lookup", "connect timeout",
61 "Error during connect()",
65 /* Highest FD and number of open FDs .. */
66 static int number_fd
= 0;
67 static int rb_maxconnections
= 0;
69 static PF rb_connect_timeout
;
70 static PF rb_connect_tryconnect
;
72 static void mangle_mapped_sockaddr(struct sockaddr
*in
);
75 #ifndef HAVE_SOCKETPAIR
76 static int rb_inet_socketpair(int d
, int type
, int protocol
, int sv
[2]);
79 static inline rb_fde_t
*
82 rb_fde_t
*F
= rb_find_fd(fd
);
84 /* look up to see if we have it already */
88 F
= rb_bh_alloc(fd_heap
);
90 rb_dlinkAdd(F
, &F
->node
, &rb_fd_table
[rb_hash_fd(fd
)]);
95 remove_fd(rb_fde_t
*F
)
97 if(F
== NULL
|| !IsFDOpen(F
))
100 rb_dlinkMoveNode(&F
->node
, &rb_fd_table
[rb_hash_fd(F
->fd
)], &closed_list
);
107 rb_dlink_node
*ptr
, *next
;
108 RB_DLINK_FOREACH_SAFE(ptr
, next
, closed_list
.head
)
111 rb_dlinkDelete(ptr
, &closed_list
);
112 rb_bh_free(fd_heap
, F
);
116 /* 32bit solaris is kinda slow and stdio only supports fds < 256
117 * so we got to do this crap below.
118 * (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
121 #if defined (__SVR4) && defined (__sun)
126 if(*fd
> 256 || *fd
< 0)
128 if((newfd
= fcntl(*fd
, F_DUPFD
, 256)) != -1)
136 #define rb_fd_hack(fd)
140 /* close_all_connections() can be used *before* the system come up! */
150 /* XXX someone tell me why we care about 4 fd's ? */
151 /* XXX btw, fd 3 is used for profiler ! */
152 for (i
= 4; i
< rb_maxconnections
; ++i
)
157 /* XXX should his hack be done in all cases? */
159 /* fugly hack to reserve fd == 2 */
161 fd
= open("stderr.log", O_WRONLY
| O_CREAT
| O_APPEND
, 0644);
171 * get_sockerr - get the error value from the socket or the current errno
173 * Get the *real* error from the socket (well try to anyway..).
174 * This may only work when SO_DEBUG is enabled but its worth the
178 rb_get_sockerr(rb_fde_t
*F
)
182 rb_socklen_t len
= sizeof(err
);
184 if(!(F
->type
& RB_FD_SOCKET
))
191 if(F
!= NULL
&& !getsockopt(rb_get_fd(F
), SOL_SOCKET
, SO_ERROR
, (char *) &err
, (rb_socklen_t
*) & len
))
202 * rb_getmaxconnect - return the max number of connections allowed
205 rb_getmaxconnect(void)
207 return(rb_maxconnections
);
211 * set_sock_buffers - set send and receive buffers for socket
213 * inputs - fd file descriptor
215 * output - returns true (1) if successful, false (0) otherwise
219 rb_set_buffers(rb_fde_t
*F
, int size
)
224 (F
->fd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &size
, sizeof(size
))
225 || setsockopt(F
->fd
, SOL_SOCKET
, SO_SNDBUF
, (char *) &size
, sizeof(size
)))
231 * set_non_blocking - Set the client connection into non-blocking mode.
233 * inputs - fd to set into non blocking mode
234 * output - 1 if successful 0 if not
235 * side effects - use POSIX compliant non blocking and
239 rb_set_nb(rb_fde_t
*F
)
248 if((res
= rb_setup_fd(F
)))
252 res
= fcntl(fd
, F_GETFL
, 0);
253 if(-1 == res
|| fcntl(fd
, F_SETFL
, res
| nonb
) == -1)
258 if(ioctl(fd
, FIONBIO
, (char *)&nonb
) == -1)
266 * rb_settimeout() - set the socket timeout
268 * Set the timeout for the fd
271 rb_settimeout(rb_fde_t
*F
, time_t timeout
, PF
* callback
, void *cbdata
)
273 struct timeout_data
*td
;
278 lrb_assert(IsFDOpen(F
));
280 if(callback
== NULL
) /* user wants to remove */
284 rb_dlinkDelete(&td
->node
, &timeout_list
);
287 if(rb_dlink_list_length(&timeout_list
) == 0)
289 rb_event_delete(rb_timeout_ev
);
290 rb_timeout_ev
= NULL
;
295 if(F
->timeout
== NULL
)
296 td
= F
->timeout
= rb_malloc(sizeof(struct timeout_data
));
299 td
->timeout
= rb_current_time() + timeout
;
300 td
->timeout_handler
= callback
;
301 td
->timeout_data
= cbdata
;
302 rb_dlinkAdd(td
, &td
->node
, &timeout_list
);
303 if(rb_timeout_ev
== NULL
)
305 rb_timeout_ev
= rb_event_add("rb_checktimeouts", rb_checktimeouts
, NULL
, 5);
310 * rb_checktimeouts() - check the socket timeouts
312 * All this routine does is call the given callback/cbdata, without closing
313 * down the file descriptor. When close handlers have been implemented,
317 rb_checktimeouts(void *notused
)
319 rb_dlink_node
*ptr
, *next
;
320 struct timeout_data
*td
;
325 RB_DLINK_FOREACH_SAFE(ptr
, next
, timeout_list
.head
)
329 if(F
== NULL
|| !IsFDOpen(F
))
332 if(td
->timeout
< rb_current_time())
334 hdl
= td
->timeout_handler
;
335 data
= td
->timeout_data
;
336 rb_dlinkDelete(&td
->node
, &timeout_list
);
345 rb_accept_tryaccept(rb_fde_t
*F
, void *data
)
347 struct rb_sockaddr_storage st
;
349 rb_socklen_t addrlen
= sizeof(st
);
354 new_fd
= accept(F
->fd
, (struct sockaddr
*)&st
, &addrlen
);
358 rb_setselect(F
, RB_SELECT_ACCEPT
, rb_accept_tryaccept
, NULL
);
364 new_F
= rb_open(new_fd
, RB_FD_SOCKET
, "Incoming Connection");
368 rb_lib_log("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d\n", new_fd
);
373 if(rb_unlikely(!rb_set_nb(new_F
)))
376 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F
->fd
);
381 mangle_mapped_sockaddr((struct sockaddr
*)&st
);
384 if(F
->accept
->precb
!= NULL
)
386 if(!F
->accept
->precb(new_F
, (struct sockaddr
*)&st
, addrlen
, F
->accept
->data
)) /* pre-callback decided to drop it */
390 if(F
->type
& RB_FD_SSL
)
392 rb_ssl_accept_setup(F
, new_F
, (struct sockaddr
*)&st
, addrlen
);
395 #endif /* HAVE_SSL */
397 F
->accept
->callback(new_F
, RB_OK
, (struct sockaddr
*)&st
, addrlen
, F
->accept
->data
);
403 /* try to accept a TCP connection */
405 rb_accept_tcp(rb_fde_t
*F
, ACPRE
*precb
, ACCB
*callback
, void *data
)
409 lrb_assert(callback
);
411 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
412 F
->accept
->callback
= callback
;
413 F
->accept
->data
= data
;
414 F
->accept
->precb
= precb
;
415 rb_accept_tryaccept(F
, NULL
);
419 * void rb_connect_tcp(int fd, struct sockaddr *dest,
420 * struct sockaddr *clocal, int socklen,
421 * CNCB *callback, void *data, int timeout)
422 * Input: An fd to connect with, a host and port to connect to,
423 * a local sockaddr to connect from + length(or NULL to use the
424 * default), a callback, the data to pass into the callback, the
427 * Side-effects: A non-blocking connection to the host is started, and
428 * if necessary, set up for selection. The callback given
429 * may be called now, or it may be called later.
432 rb_connect_tcp(rb_fde_t
*F
, struct sockaddr
*dest
,
433 struct sockaddr
*clocal
, int socklen
, CNCB
* callback
, void *data
, int timeout
)
438 lrb_assert(callback
);
439 F
->connect
= rb_malloc(sizeof(struct conndata
));
440 F
->connect
->callback
= callback
;
441 F
->connect
->data
= data
;
443 memcpy(&F
->connect
->hostaddr
, dest
, sizeof(F
->connect
->hostaddr
));
445 /* Note that we're using a passed sockaddr here. This is because
446 * generally you'll be bind()ing to a sockaddr grabbed from
447 * getsockname(), so this makes things easier.
448 * XXX If NULL is passed as local, we should later on bind() to the
449 * virtual host IP, for completeness.
452 if((clocal
!= NULL
) && (bind(F
->fd
, clocal
, socklen
) < 0))
454 /* Failure, call the callback with RB_ERR_BIND */
455 rb_connect_callback(F
, RB_ERR_BIND
);
460 /* We have a valid IP, so we just call tryconnect */
461 /* Make sure we actually set the timeout here .. */
462 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
463 rb_connect_tryconnect(F
, NULL
);
468 * rb_connect_callback() - call the callback, and continue with life
471 rb_connect_callback(rb_fde_t
*F
, int status
)
475 int errtmp
= errno
; /* save errno as rb_settimeout clobbers it sometimes */
477 /* This check is gross..but probably necessary */
478 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
480 /* Clear the connect flag + handler */
481 hdl
= F
->connect
->callback
;
482 data
= F
->connect
->data
;
483 F
->connect
->callback
= NULL
;
486 /* Clear the timeout handler */
487 rb_settimeout(F
, 0, NULL
, NULL
);
489 /* Call the handler */
490 hdl(F
, status
, data
);
495 * rb_connect_timeout() - this gets called when the socket connection
496 * times out. This *only* can be called once connect() is initially
500 rb_connect_timeout(rb_fde_t
*F
, void *notused
)
503 rb_connect_callback(F
, RB_ERR_TIMEOUT
);
506 /* static void rb_connect_tryconnect(int fd, void *notused)
507 * Input: The fd, the handler data(unused).
509 * Side-effects: Try and connect with pending connect data for the FD. If
510 * we succeed or get a fatal error, call the callback.
511 * Otherwise, it is still blocking or something, so register
512 * to select for a write event on this FD.
515 rb_connect_tryconnect(rb_fde_t
*F
, void *notused
)
519 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
521 /* Try the connect() */
522 retval
= connect(F
->fd
,
523 (struct sockaddr
*) &F
->connect
->hostaddr
, GET_SS_LEN(&F
->connect
->hostaddr
));
528 * If we get EISCONN, then we've already connect()ed the socket,
529 * which is a good thing.
534 rb_connect_callback(F
, RB_OK
);
535 else if(rb_ignore_errno(errno
))
536 /* Ignore error? Reschedule */
537 rb_setselect(F
, RB_SELECT_CONNECT
,
538 rb_connect_tryconnect
, NULL
);
540 /* Error? Fail with RB_ERR_CONNECT */
541 rb_connect_callback(F
, RB_ERR_CONNECT
);
544 /* If we get here, we've suceeded, so call with RB_OK */
545 rb_connect_callback(F
, RB_OK
);
550 rb_connect_sockaddr(rb_fde_t
*F
, struct sockaddr
*addr
, int len
)
555 memcpy(addr
, &F
->connect
->hostaddr
, len
);
560 * rb_error_str() - return an error string for the given error condition
565 if(error
< 0 || error
>= RB_ERR_MAX
)
566 return "Invalid error number!";
567 return rb_err_str
[error
];
572 rb_socketpair(int family
, int sock_type
, int proto
, rb_fde_t
**F1
, rb_fde_t
**F2
, const char *note
)
575 if(number_fd
>= rb_maxconnections
)
582 if(socketpair(family
, sock_type
, proto
, nfd
))
584 if(rb_inet_socketpair(AF_INET
, SOCK_STREAM
, proto
, nfd
))
591 *F1
= rb_open(nfd
[0], RB_FD_SOCKET
, note
);
592 *F2
= rb_open(nfd
[1], RB_FD_SOCKET
, note
);
607 /* Set the socket non-blocking, and other wonderful bits */
608 if(rb_unlikely(!rb_set_nb(*F1
)))
610 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[0], strerror(errno
));
616 if(rb_unlikely(!rb_set_nb(*F2
)))
618 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[1], strerror(errno
));
629 rb_pipe(rb_fde_t
**F1
, rb_fde_t
**F2
, const char *desc
)
633 if(number_fd
>= rb_maxconnections
)
642 *F1
= rb_open(fd
[0], RB_FD_PIPE
, desc
);
643 *F2
= rb_open(fd
[1], RB_FD_PIPE
, desc
);
645 if(rb_unlikely(!rb_set_nb(*F1
)))
647 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[0], strerror(errno
));
653 if(rb_unlikely(!rb_set_nb(*F2
)))
655 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[1], strerror(errno
));
664 /* Its not a pipe..but its selectable. I'll take dirty hacks
667 return rb_socketpair(AF_INET
, SOCK_STREAM
, 0, F1
, F2
, desc
);
672 * rb_socket() - open a socket
674 * This is a highly highly cut down version of squid's rb_open() which
675 * for the most part emulates socket(), *EXCEPT* it fails if we're about
676 * to run out of file descriptors.
679 rb_socket(int family
, int sock_type
, int proto
, const char *note
)
683 /* First, make sure we aren't going to run out of file descriptors */
684 if(rb_unlikely(number_fd
>= rb_maxconnections
))
691 * Next, we try to open the socket. We *should* drop the reserved FD
692 * limit if/when we get an error, but we can deal with that later.
695 fd
= socket(family
, sock_type
, proto
);
697 if(rb_unlikely(fd
< 0))
698 return NULL
; /* errno will be passed through, yay.. */
700 #if defined(RB_IPV6) && defined(IPV6_V6ONLY)
702 * Make sure we can take both IPv4 and IPv6 connections
703 * on an AF_INET6 socket
705 if(family
== AF_INET6
)
708 if(setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &off
, sizeof(off
)) == -1)
710 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to 1 on FD %d: %s",
711 fd
, strerror(errno
));
718 F
= rb_open(fd
, RB_FD_SOCKET
, note
);
721 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd
, strerror(errno
));
725 /* Set the socket non-blocking, and other wonderful bits */
726 if(rb_unlikely(!rb_set_nb(F
)))
728 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
, strerror(errno
));
737 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
738 * socket manged the sockaddr.
742 mangle_mapped_sockaddr(struct sockaddr
*in
)
744 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*) in
;
746 if(in
->sa_family
== AF_INET
)
749 if(in
->sa_family
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&in6
->sin6_addr
))
751 struct sockaddr_in in4
;
752 memset(&in4
, 0, sizeof(struct sockaddr_in
));
753 in4
.sin_family
= AF_INET
;
754 in4
.sin_port
= in6
->sin6_port
;
755 in4
.sin_addr
.s_addr
= ((uint32_t *) & in6
->sin6_addr
)[3];
756 memcpy(in
, &in4
, sizeof(struct sockaddr_in
));
763 * rb_listen() - listen on a port
766 rb_listen(rb_fde_t
*F
, int backlog
)
768 F
->type
= RB_FD_SOCKET
|RB_FD_LISTEN
;
769 /* Currently just a simple wrapper for the sake of being complete */
770 return listen(F
->fd
, backlog
);
774 rb_fdlist_init(int closeall
, int maxfds
, size_t heapsize
)
776 static int initialized
= 0;
780 int vers
= MAKEWORD(2, 0);
782 err
= WSAStartup(vers
, &wsaData
);
785 rb_lib_die("WSAStartup failed");
791 rb_maxconnections
= maxfds
;
794 /* Since we're doing this once .. */
797 fd_heap
= rb_bh_create(sizeof(rb_fde_t
), heapsize
, "librb_fd_heap");
802 /* Called to open a given filedescriptor */
804 rb_open(int fd
, uint8_t type
, const char *desc
)
811 lrb_assert(!IsFDOpen(F
));
812 if(rb_unlikely(IsFDOpen(F
)))
815 if(F
!= NULL
&& F
->desc
!= NULL
)
819 rb_lib_log("Trying to rb_open an already open FD: %d desc: %d", fd
, fdesc
);
827 F
->desc
= rb_strndup(desc
, FD_DESC_SZ
);
833 /* Called to close a given filedescriptor */
835 rb_close(rb_fde_t
*F
)
844 lrb_assert(IsFDOpen(F
));
846 lrb_assert(!(type
& RB_FD_FILE
));
847 if(rb_unlikely(type
& RB_FD_FILE
))
849 lrb_assert(F
->read_handler
== NULL
);
850 lrb_assert(F
->write_handler
== NULL
);
852 rb_setselect(F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
853 rb_settimeout(F
, 0, NULL
, NULL
);
862 #endif /* HAVE_SSL */
872 if(type
& (RB_FD_SOCKET
|RB_FD_PIPE
))
883 * rb_dump_fd() - dump the list of active filedescriptors
886 rb_dump_fd(DUMPCB
* cb
, void *data
)
888 static const char *empty
= "";
890 rb_dlink_list
*bucket
;
894 for(i
= 0; i
< RB_FD_HASH_SIZE
; i
++)
896 bucket
= &rb_fd_table
[i
];
898 if(rb_dlink_list_length(bucket
) <= 0)
901 RB_DLINK_FOREACH(ptr
, bucket
->head
)
904 if(F
== NULL
|| !IsFDOpen(F
))
907 cb(F
->fd
, F
->desc
? F
->desc
: empty
, data
);
913 * rb_note() - set the fd note
915 * Note: must be careful not to overflow rb_fd_table[fd].desc when
919 rb_note(rb_fde_t
*F
, const char *string
)
925 F
->desc
= rb_strndup(string
, FD_DESC_SZ
);
929 rb_set_type(rb_fde_t
*F
, uint8_t type
)
931 /* if the caller is calling this, lets assume they have a clue */
937 rb_get_type(rb_fde_t
*F
)
943 rb_fd_ssl(rb_fde_t
*F
)
947 if(F
->type
& RB_FD_SSL
)
953 rb_get_fd(rb_fde_t
*F
)
963 return rb_find_fd(fd
);
967 rb_read(rb_fde_t
*F
, void *buf
, int count
)
973 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
974 * an SSL socket as a regular socket
977 if(F
->type
& RB_FD_SSL
)
979 return rb_ssl_read(F
, buf
, count
);
982 if(F
->type
& RB_FD_SOCKET
)
984 ret
= recv(F
->fd
, buf
, count
, 0);
994 return read(F
->fd
, buf
, count
);
999 rb_write(rb_fde_t
*F
, const void *buf
, int count
)
1006 if(F
->type
& RB_FD_SSL
)
1008 return rb_ssl_write(F
, buf
, count
);
1011 if(F
->type
& RB_FD_SOCKET
)
1013 ret
= send(F
->fd
, buf
, count
, MSG_NOSIGNAL
);
1020 return write(F
->fd
, buf
, count
);
1023 #if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1025 rb_fake_writev(rb_fde_t
*F
, const struct rb_iovec
*vp
, size_t vpcount
)
1029 while (vpcount
-- > 0)
1031 ssize_t written
= rb_write(F
, vp
->iov_base
, vp
->iov_len
);
1047 #if defined(WIN32) || !defined(HAVE_WRITEV)
1049 rb_writev(rb_fde_t
*F
, struct rb_iovec
*vecount
, int count
)
1051 return rb_fake_writev(F
, vecount
, count
);
1056 rb_writev(rb_fde_t
*F
, struct rb_iovec
*vector
, int count
)
1063 if(F
->type
& RB_FD_SSL
)
1065 return rb_fake_writev(F
, vector
, count
);
1067 #endif /* HAVE_SSL */
1069 if(F
->type
& RB_FD_SOCKET
)
1072 memset(&msg
, 0, sizeof(msg
));
1073 msg
.msg_iov
= (struct iovec
*)vector
;
1074 msg
.msg_iovlen
= count
;
1075 return sendmsg(F
->fd
, &msg
, MSG_NOSIGNAL
);
1077 #endif /* HAVE_SENDMSG */
1078 return writev(F
->fd
, (struct iovec
*)vector
, count
);
1085 * From: Thomas Helvey <tomh@inxpress.net>
1087 static const char *IpQuadTab
[] = {
1088 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1089 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1090 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1091 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1092 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1093 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1094 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1095 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1096 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1097 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1098 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1099 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1100 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1101 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1102 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1103 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1104 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1105 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1106 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1107 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1108 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1109 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1110 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1111 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1112 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1113 "250", "251", "252", "253", "254", "255"
1117 * inetntoa - in_addr to string
1118 * changed name to remove collision possibility and
1119 * so behaviour is guaranteed to take a pointer arg.
1121 * inet_ntoa -- returned the dotted notation of a given
1124 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1128 inetntoa(const char *in
)
1130 static char buf
[16];
1132 const unsigned char *a
= (const unsigned char *) in
;
1135 n
= IpQuadTab
[*a
++];
1139 n
= IpQuadTab
[*a
++];
1143 n
= IpQuadTab
[*a
++];
1156 * Copyright (c) 1996-1999 by Internet Software Consortium.
1158 * Permission to use, copy, modify, and distribute this software for any
1159 * purpose with or without fee is hereby granted, provided that the above
1160 * copyright notice and this permission notice appear in all copies.
1162 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1163 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1164 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1165 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1166 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1167 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1168 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1172 #define SPRINTF(x) ((size_t)rb_sprintf x)
1175 * WARNING: Don't even consider trying to compile this on a system where
1176 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1179 static const char *inet_ntop4(const unsigned char * src
, char *dst
, unsigned int size
);
1181 static const char *inet_ntop6(const unsigned char * src
, char *dst
, unsigned int size
);
1185 * inet_ntop4(src, dst, size)
1186 * format an IPv4 address
1188 * `dst' (as a const)
1190 * (1) uses no statics
1191 * (2) takes a unsigned char* not an in_addr as input
1196 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
1200 return strcpy(dst
, inetntoa((const char *) src
));
1204 * inet_ntop6(src, dst, size)
1205 * convert IPv6 binary address into presentation (printable) format
1211 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
1214 * Note that int32_t and int16_t need only be "at least" large enough
1215 * to contain a value of the specified size. On some systems, like
1216 * Crays, there is no such thing as an integer variable with 16 bits.
1217 * Keep this in mind if you think this function should have been coded
1218 * to use pointer overlays. All the world's not a VAX.
1220 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
1226 unsigned int words
[IN6ADDRSZ
/ INT16SZ
];
1231 * Copy the input (bytewise) array into a wordwise array.
1232 * Find the longest run of 0x00's in src[] for :: shorthanding.
1234 memset(words
, '\0', sizeof words
);
1235 for (i
= 0; i
< IN6ADDRSZ
; i
+= 2)
1236 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
1241 for (i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1246 cur
.base
= i
, cur
.len
= 1;
1254 if(best
.base
== -1 || cur
.len
> best
.len
)
1262 if(best
.base
== -1 || cur
.len
> best
.len
)
1265 if(best
.base
!= -1 && best
.len
< 2)
1269 * Format the result.
1272 for (i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1274 /* Are we inside the best run of 0x00's? */
1275 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
1285 /* Are we following an initial run of 0x00s or any real hex? */
1288 /* Is this address an encapsulated IPv4? */
1289 if(i
== 6 && best
.base
== 0 &&
1290 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
1292 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
1297 tp
+= SPRINTF((tp
, "%x", words
[i
]));
1299 /* Was it a trailing run of 0x00's? */
1300 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
1305 * Check for overflow, copy, and we're done.
1308 if((unsigned int) (tp
- tmp
) > size
)
1312 return strcpy(dst
, tmp
);
1317 rb_inet_pton_sock(const char *src
, struct sockaddr
*dst
)
1319 if(rb_inet_pton(AF_INET
, src
, &((struct sockaddr_in
*) dst
)->sin_addr
))
1321 ((struct sockaddr_in
*) dst
)->sin_port
= 0;
1322 ((struct sockaddr_in
*) dst
)->sin_family
= AF_INET
;
1323 SET_SS_LEN(dst
, sizeof(struct sockaddr_in
));
1327 else if(rb_inet_pton(AF_INET6
, src
, &((struct sockaddr_in6
*) dst
)->sin6_addr
))
1329 ((struct sockaddr_in6
*) dst
)->sin6_port
= 0;
1330 ((struct sockaddr_in6
*) dst
)->sin6_family
= AF_INET6
;
1331 SET_SS_LEN(dst
, sizeof(struct sockaddr_in6
));
1339 rb_inet_ntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
1341 switch (src
->sa_family
)
1344 return (rb_inet_ntop(AF_INET
, &((struct sockaddr_in
*) src
)->sin_addr
, dst
, size
));
1348 return (rb_inet_ntop(AF_INET6
, &((struct sockaddr_in6
*) src
)->sin6_addr
, dst
, size
));
1358 * rb_inet_ntop(af, src, dst, size)
1359 * convert a network format address to presentation format.
1361 * pointer to presentation format address (`dst'), or NULL (see errno).
1366 rb_inet_ntop(int af
, const void *src
, char *dst
, unsigned int size
)
1371 return (inet_ntop4(src
, dst
, size
));
1374 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*) src
) ||
1375 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*) src
))
1377 ((const unsigned char *)
1378 &((const struct in6_addr
*) src
)->s6_addr
[12], dst
, size
));
1380 return (inet_ntop6(src
, dst
, size
));
1391 * WARNING: Don't even consider trying to compile this on a system where
1392 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1396 * rb_inet_pton(af, src, dst)
1397 * convert from presentation format (which usually means ASCII printable)
1398 * to network format (which is usually some kind of binary format).
1400 * 1 if the address was valid for the specified address family
1401 * 0 if the address wasn't valid (`dst' is untouched in this case)
1402 * -1 if some other error occurred (`dst' is untouched in this case, too)
1408 * inet_pton4(src, dst)
1409 * like inet_aton() but without all the hexadecimal and shorthand.
1411 * 1 if `src' is a valid dotted quad, else 0.
1413 * does not touch `dst' unless it's returning 1.
1418 inet_pton4(const char *src
, unsigned char *dst
)
1420 int saw_digit
, octets
, ch
;
1421 unsigned char tmp
[INADDRSZ
], *tp
;
1426 while ((ch
= *src
++) != '\0')
1429 if(ch
>= '0' && ch
<= '9')
1431 unsigned int new = *tp
* 10 + (ch
- '0');
1443 else if(ch
== '.' && saw_digit
)
1455 memcpy(dst
, tmp
, INADDRSZ
);
1461 * inet_pton6(src, dst)
1462 * convert presentation level address to network order binary form.
1464 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1466 * (1) does not touch `dst' unless it's returning 1.
1467 * (2) :: in a full address is silently ignored.
1469 * inspired by Mark Andrews.
1475 inet_pton6(const char *src
, unsigned char *dst
)
1477 static const char xdigits
[] = "0123456789abcdef";
1478 unsigned char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
1483 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
1484 endp
= tp
+ IN6ADDRSZ
;
1486 /* Leading :: requires some special handling. */
1493 while ((ch
= tolower(*src
++)) != '\0')
1497 pch
= strchr(xdigits
, ch
);
1501 val
|= (pch
- xdigits
);
1517 else if(*src
== '\0')
1521 if(tp
+ INT16SZ
> endp
)
1523 *tp
++ = (unsigned char) (val
>> 8) & 0xff;
1524 *tp
++ = (unsigned char) val
& 0xff;
1529 if(*src
!= '\0' && ch
== '.')
1531 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
1535 break; /* '\0' was seen by inet_pton4(). */
1544 if(tp
+ INT16SZ
> endp
)
1546 *tp
++ = (unsigned char) (val
>> 8) & 0xff;
1547 *tp
++ = (unsigned char) val
& 0xff;
1552 * Since some memmove()'s erroneously fail to handle
1553 * overlapping regions, we'll do the shift by hand.
1555 const int n
= tp
- colonp
;
1560 for (i
= 1; i
<= n
; i
++)
1562 endp
[-i
] = colonp
[n
- i
];
1569 memcpy(dst
, tmp
, IN6ADDRSZ
);
1574 rb_inet_pton(int af
, const char *src
, void *dst
)
1579 return (inet_pton4(src
, dst
));
1582 /* Somebody might have passed as an IPv4 address this is sick but it works */
1583 if(inet_pton4(src
, dst
))
1585 char tmp
[HOSTIPLEN
];
1586 rb_sprintf(tmp
, "::ffff:%s", src
);
1587 return (inet_pton6(tmp
, dst
));
1590 return (inet_pton6(src
, dst
));
1599 #ifndef HAVE_SOCKETPAIR
1601 rb_inet_socketpair(int family
, int type
, int protocol
, int fd
[2])
1606 struct sockaddr_in listen_addr
;
1607 struct sockaddr_in connect_addr
;
1610 if(protocol
|| family
!= AF_INET
)
1612 errno
= EAFNOSUPPORT
;
1621 listener
= socket(AF_INET
, type
, 0);
1624 memset(&listen_addr
, 0, sizeof(listen_addr
));
1625 listen_addr
.sin_family
= AF_INET
;
1626 listen_addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1627 listen_addr
.sin_port
= 0; /* kernel choses port. */
1628 if(bind(listener
, (struct sockaddr
*) &listen_addr
, sizeof(listen_addr
)) == -1)
1629 goto tidy_up_and_fail
;
1630 if(listen(listener
, 1) == -1)
1631 goto tidy_up_and_fail
;
1633 connector
= socket(AF_INET
, type
, 0);
1635 goto tidy_up_and_fail
;
1636 /* We want to find out the port number to connect to. */
1637 size
= sizeof(connect_addr
);
1638 if(getsockname(listener
, (struct sockaddr
*) &connect_addr
, &size
) == -1)
1639 goto tidy_up_and_fail
;
1640 if(size
!= sizeof(connect_addr
))
1641 goto abort_tidy_up_and_fail
;
1642 if(connect(connector
, (struct sockaddr
*) &connect_addr
, sizeof(connect_addr
)) == -1)
1643 goto tidy_up_and_fail
;
1645 size
= sizeof(listen_addr
);
1646 acceptor
= accept(listener
, (struct sockaddr
*) &listen_addr
, &size
);
1648 goto tidy_up_and_fail
;
1649 if(size
!= sizeof(listen_addr
))
1650 goto abort_tidy_up_and_fail
;
1652 /* Now check we are talking to ourself by matching port and host on the
1654 if(getsockname(connector
, (struct sockaddr
*) &connect_addr
, &size
) == -1)
1655 goto tidy_up_and_fail
;
1656 if(size
!= sizeof(connect_addr
)
1657 || listen_addr
.sin_family
!= connect_addr
.sin_family
1658 || listen_addr
.sin_addr
.s_addr
!= connect_addr
.sin_addr
.s_addr
1659 || listen_addr
.sin_port
!= connect_addr
.sin_port
)
1661 goto abort_tidy_up_and_fail
;
1667 abort_tidy_up_and_fail
:
1668 errno
= EINVAL
; /* I hope this is portable and appropriate. */
1672 int save_errno
= errno
;
1687 static void (*setselect_handler
) (rb_fde_t
*, unsigned int, PF
*, void *);
1688 static int (*select_handler
) (long);
1689 static int (*setup_fd_handler
) (rb_fde_t
*);
1690 static int (*io_sched_event
) (struct ev_entry
*, int);
1691 static void (*io_unsched_event
) (struct ev_entry
*);
1692 static int (*io_supports_event
) (void);
1693 static void (*io_init_event
) (void);
1694 static char iotype
[25];
1703 rb_unsupported_event(void)
1711 if(!rb_init_netio_kqueue())
1713 setselect_handler
= rb_setselect_kqueue
;
1714 select_handler
= rb_select_kqueue
;
1715 setup_fd_handler
= rb_setup_fd_kqueue
;
1716 io_sched_event
= rb_kqueue_sched_event
;
1717 io_unsched_event
= rb_kqueue_unsched_event
;
1718 io_init_event
= rb_kqueue_init_event
;
1719 io_supports_event
= rb_kqueue_supports_event
;
1720 rb_strlcpy(iotype
, "kqueue", sizeof(iotype
));
1729 if(!rb_init_netio_epoll())
1731 setselect_handler
= rb_setselect_epoll
;
1732 select_handler
= rb_select_epoll
;
1733 setup_fd_handler
= rb_setup_fd_epoll
;
1734 io_sched_event
= rb_epoll_sched_event
;
1735 io_unsched_event
= rb_epoll_unsched_event
;
1736 io_supports_event
= rb_epoll_supports_event
;
1737 io_init_event
= rb_epoll_init_event
;
1738 rb_strlcpy(iotype
, "epoll", sizeof(iotype
));
1747 if(!rb_init_netio_ports())
1749 setselect_handler
= rb_setselect_ports
;
1750 select_handler
= rb_select_ports
;
1751 setup_fd_handler
= rb_setup_fd_ports
;
1752 io_sched_event
= NULL
;
1753 io_unsched_event
= NULL
;
1754 io_init_event
= NULL
;
1755 io_supports_event
= rb_unsupported_event
;
1756 rb_strlcpy(iotype
, "ports", sizeof(iotype
));
1765 if(!rb_init_netio_devpoll())
1767 setselect_handler
= rb_setselect_devpoll
;
1768 select_handler
= rb_select_devpoll
;
1769 setup_fd_handler
= rb_setup_fd_devpoll
;
1770 io_sched_event
= NULL
;
1771 io_unsched_event
= NULL
;
1772 io_init_event
= NULL
;
1773 io_supports_event
= rb_unsupported_event
;
1774 rb_strlcpy(iotype
, "devpoll", sizeof(iotype
));
1783 if(!rb_init_netio_sigio())
1785 setselect_handler
= rb_setselect_sigio
;
1786 select_handler
= rb_select_sigio
;
1787 setup_fd_handler
= rb_setup_fd_sigio
;
1788 io_sched_event
= rb_sigio_sched_event
;
1789 io_unsched_event
= rb_sigio_unsched_event
;
1790 io_supports_event
= rb_sigio_supports_event
;
1791 io_init_event
= rb_sigio_init_event
;
1793 rb_strlcpy(iotype
, "sigio", sizeof(iotype
));
1802 if(!rb_init_netio_poll())
1804 setselect_handler
= rb_setselect_poll
;
1805 select_handler
= rb_select_poll
;
1806 setup_fd_handler
= rb_setup_fd_poll
;
1807 io_sched_event
= NULL
;
1808 io_unsched_event
= NULL
;
1809 io_init_event
= NULL
;
1810 io_supports_event
= rb_unsupported_event
;
1811 rb_strlcpy(iotype
, "poll", sizeof(iotype
));
1820 if(!rb_init_netio_win32())
1822 setselect_handler
= rb_setselect_win32
;
1823 select_handler
= rb_select_win32
;
1824 setup_fd_handler
= rb_setup_fd_win32
;
1825 io_sched_event
= NULL
;
1826 io_unsched_event
= NULL
;
1827 io_init_event
= NULL
;
1828 io_supports_event
= rb_unsupported_event
;
1829 rb_strlcpy(iotype
, "win32", sizeof(iotype
));
1838 if(!rb_init_netio_select())
1840 setselect_handler
= rb_setselect_select
;
1841 select_handler
= rb_select_select
;
1842 setup_fd_handler
= rb_setup_fd_select
;
1843 io_sched_event
= NULL
;
1844 io_unsched_event
= NULL
;
1845 io_init_event
= NULL
;
1846 io_supports_event
= rb_unsupported_event
;
1847 rb_strlcpy(iotype
, "select", sizeof(iotype
));
1855 rb_io_sched_event(struct ev_entry
*ev
, int when
)
1857 if(ev
== NULL
|| io_supports_event
== NULL
|| io_sched_event
== NULL
|| !io_supports_event())
1859 return io_sched_event(ev
, when
);
1863 rb_io_unsched_event(struct ev_entry
*ev
)
1865 if(ev
== NULL
|| io_supports_event
== NULL
|| io_unsched_event
== NULL
|| !io_supports_event())
1867 io_unsched_event(ev
);
1870 rb_io_supports_event(void)
1872 if(io_supports_event
== NULL
)
1874 return io_supports_event();
1878 rb_io_init_event(void)
1881 rb_event_io_register_all();
1887 char *ioenv
= getenv("LIBRB_USE_IOTYPE");
1888 rb_fd_table
= rb_malloc(RB_FD_HASH_SIZE
* sizeof(rb_dlink_list
));
1893 if(!strcmp("epoll", ioenv
))
1898 if(!strcmp("kqueue", ioenv
))
1903 if(!strcmp("ports", ioenv
))
1908 if(!strcmp("poll", ioenv
))
1913 if(!strcmp("devpoll", ioenv
))
1918 if(!strcmp("sigio", ioenv
))
1923 if(!strcmp("win32", ioenv
))
1928 if(!strcmp("select", ioenv
))
1953 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
1959 rb_setselect(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
1961 setselect_handler(F
, type
, handler
, client_data
);
1965 rb_select(unsigned long timeout
)
1967 int ret
= select_handler(timeout
);
1973 rb_setup_fd(rb_fde_t
*F
)
1975 return setup_fd_handler(F
);
1981 rb_ignore_errno(int error
)
1988 #if defined EWOULDBLOCK
1991 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
2012 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2015 struct cmsghdr
*cmsg
;
2016 struct iovec iov
[1];
2018 uint8_t stype
= RB_FD_UNKNOWN
;
2020 int fd
, len
, x
, rfds
;
2022 int control_len
= CMSG_SPACE(sizeof(int) * nfds
);
2024 iov
[0].iov_base
= data
;
2025 iov
[0].iov_len
= datasize
;
2027 msg
.msg_name
= NULL
;
2028 msg
.msg_namelen
= 0;
2032 cmsg
= alloca(control_len
);
2033 msg
.msg_control
= cmsg
;
2034 msg
.msg_controllen
= control_len
;
2036 if((len
= recvmsg(rb_get_fd(F
), &msg
, 0)) <= 0)
2039 if(msg
.msg_controllen
> 0 && msg
.msg_control
!= NULL
&& (cmsg
= CMSG_FIRSTHDR(&msg
)) != NULL
)
2041 rfds
= (msg
.msg_controllen
- sizeof(struct cmsghdr
)) / sizeof(int);
2043 for(x
= 0; x
< nfds
&& x
< rfds
; x
++)
2045 fd
= ((int *)CMSG_DATA(cmsg
))[x
];
2046 stype
= RB_FD_UNKNOWN
;
2047 desc
= "remote unknown";
2050 if(S_ISSOCK(st
.st_mode
))
2052 stype
= RB_FD_SOCKET
;
2053 desc
= "remote socket";
2055 else if(S_ISFIFO(st
.st_mode
))
2058 desc
= "remote pipe";
2060 else if(S_ISREG(st
.st_mode
))
2063 desc
= "remote file";
2066 xF
[x
] = rb_open(fd
, stype
, desc
);
2075 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
)
2079 struct cmsghdr
*cmsg
;
2080 struct iovec iov
[1];
2084 memset(&msg
, 0, sizeof(&msg
));
2087 iov
[0].iov_base
= &empty
;
2090 iov
[0].iov_base
= data
;
2091 iov
[0].iov_len
= datasize
;
2095 msg
.msg_name
= NULL
;
2096 msg
.msg_namelen
= 0;
2098 msg
.msg_control
= NULL
;
2099 msg
.msg_controllen
= 0;
2104 int len
= CMSG_SPACE(sizeof(int) * count
);
2107 msg
.msg_control
= buf
;
2108 msg
.msg_controllen
= len
;
2109 cmsg
= CMSG_FIRSTHDR(&msg
);
2110 cmsg
->cmsg_level
= SOL_SOCKET
;
2111 cmsg
->cmsg_type
= SCM_RIGHTS
;
2112 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * count
);
2114 for(i
= 0; i
< count
; i
++)
2116 ((int *)CMSG_DATA(cmsg
))[i
] = rb_get_fd(F
[i
]);
2118 msg
.msg_controllen
= cmsg
->cmsg_len
;
2120 n
= sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);