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
26 #include <librb_config.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()",
66 /* Highest FD and number of open FDs .. */
67 static int number_fd
= 0;
68 int rb_maxconnections
= 0;
70 static PF rb_connect_timeout
;
71 static PF rb_connect_outcome
;
72 static void mangle_mapped_sockaddr(struct sockaddr
*in
);
74 #ifndef HAVE_SOCKETPAIR
75 static int rb_inet_socketpair(int d
, int type
, int protocol
, rb_platform_fd_t sv
[2]);
76 static int rb_inet_socketpair_udp(rb_fde_t
**newF1
, rb_fde_t
**newF2
);
79 static inline rb_fde_t
*
80 add_fd(rb_platform_fd_t fd
)
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
)
115 if(F
->type
& (RB_FD_SOCKET
| RB_FD_PIPE
))
121 rb_dlinkDelete(ptr
, &closed_list
);
122 rb_bh_free(fd_heap
, F
);
126 /* 32bit solaris is kinda slow and stdio only supports fds < 256
127 * so we got to do this crap below.
128 * (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
131 #if defined (__SVR4) && defined (__sun)
136 if(*fd
> 256 || *fd
< 0)
138 if((newfd
= fcntl(*fd
, F_DUPFD
, 256)) != -1)
146 #define rb_fd_hack(fd)
150 /* close_all_connections() can be used *before* the system come up! */
158 /* XXX someone tell me why we care about 4 fd's ? */
159 /* XXX btw, fd 3 is used for profiler ! */
160 for(i
= 3; i
< rb_maxconnections
; ++i
)
168 * get_sockerr - get the error value from the socket or the current errno
170 * Get the *real* error from the socket (well try to anyway..).
171 * This may only work when SO_DEBUG is enabled but its worth the
175 rb_get_sockerr(rb_fde_t
*F
)
179 rb_socklen_t len
= sizeof(err
);
181 if(!(F
->type
& RB_FD_SOCKET
))
189 && !getsockopt(rb_get_fd(F
), SOL_SOCKET
, SO_ERROR
, (char *)&err
, (rb_socklen_t
*) & len
))
200 * rb_getmaxconnect - return the max number of connections allowed
203 rb_getmaxconnect(void)
205 return (rb_maxconnections
);
209 * set_sock_buffers - set send and receive buffers for socket
211 * inputs - fd file descriptor
213 * output - returns true (1) if successful, false (0) otherwise
217 rb_set_buffers(rb_fde_t
*F
, int size
)
222 (F
->fd
, SOL_SOCKET
, SO_RCVBUF
, (char *)&size
, sizeof(size
))
223 || setsockopt(F
->fd
, SOL_SOCKET
, SO_SNDBUF
, (char *)&size
, sizeof(size
)))
229 * set_non_blocking - Set the client connection into non-blocking mode.
231 * inputs - fd to set into non blocking mode
232 * output - 1 if successful 0 if not
233 * side effects - use POSIX compliant non blocking and
237 rb_set_nb(rb_fde_t
*F
)
246 if((res
= rb_setup_fd(F
)))
250 res
= fcntl(fd
, F_GETFL
, 0);
251 if(-1 == res
|| fcntl(fd
, F_SETFL
, res
| nonb
) == -1)
256 if(ioctl(fd
, FIONBIO
, (char *)&nonb
) == -1)
264 * rb_settimeout() - set the socket timeout
266 * Set the timeout for the fd
269 rb_settimeout(rb_fde_t
*F
, time_t timeout
, PF
* callback
, void *cbdata
)
271 struct timeout_data
*td
;
276 lrb_assert(IsFDOpen(F
));
278 if(callback
== NULL
) /* user wants to remove */
282 rb_dlinkDelete(&td
->node
, &timeout_list
);
285 if(rb_dlink_list_length(&timeout_list
) == 0)
287 rb_event_delete(rb_timeout_ev
);
288 rb_timeout_ev
= NULL
;
293 if(F
->timeout
== NULL
)
294 td
= F
->timeout
= rb_malloc(sizeof(struct timeout_data
));
297 td
->timeout
= rb_current_time() + timeout
;
298 td
->timeout_handler
= callback
;
299 td
->timeout_data
= cbdata
;
300 rb_dlinkAdd(td
, &td
->node
, &timeout_list
);
301 if(rb_timeout_ev
== NULL
)
303 rb_timeout_ev
= rb_event_add("rb_checktimeouts", rb_checktimeouts
, NULL
, 5);
308 * rb_checktimeouts() - check the socket timeouts
310 * All this routine does is call the given callback/cbdata, without closing
311 * down the file descriptor. When close handlers have been implemented,
315 rb_checktimeouts(void *notused
__attribute__((unused
)))
317 rb_dlink_node
*ptr
, *next
;
318 struct timeout_data
*td
;
323 RB_DLINK_FOREACH_SAFE(ptr
, next
, timeout_list
.head
)
327 if(F
== NULL
|| !IsFDOpen(F
))
330 if(td
->timeout
< rb_current_time())
332 hdl
= td
->timeout_handler
;
333 data
= td
->timeout_data
;
334 rb_dlinkDelete(&td
->node
, &timeout_list
);
343 rb_setsockopt_reuseaddr(rb_fde_t
*F
)
348 ret
= setsockopt(F
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt_one
, sizeof(opt_one
));
350 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
351 F
->fd
, strerror(rb_get_sockerr(F
)));
360 rb_setsockopt_sctp(rb_fde_t
*F
)
364 /* workaround for https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sctp?id=299ee123e19889d511092347f5fc14db0f10e3a6 */
365 char *env_mapped
= getenv("SCTP_I_WANT_MAPPED_V4_ADDR");
366 int opt_mapped
= env_mapped
!= NULL
? atoi(env_mapped
) : opt_zero
;
368 struct sctp_initmsg initmsg
;
369 struct sctp_rtoinfo rtoinfo
;
370 struct sctp_paddrparams paddrparams
;
371 struct sctp_assocparams assocparams
;
373 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_NODELAY
, &opt_one
, sizeof(opt_one
));
375 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
376 F
->fd
, strerror(rb_get_sockerr(F
)));
380 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_I_WANT_MAPPED_V4_ADDR
, &opt_mapped
, sizeof(opt_mapped
));
382 rb_lib_log("rb_setsockopt_sctp: Cannot unset SCTP_I_WANT_MAPPED_V4_ADDR for fd %d: %s",
383 F
->fd
, strerror(rb_get_sockerr(F
)));
387 /* Configure INIT message to specify that we only want one stream */
388 memset(&initmsg
, 0, sizeof(initmsg
));
389 initmsg
.sinit_num_ostreams
= 1;
390 initmsg
.sinit_max_instreams
= 1;
392 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_INITMSG
, &initmsg
, sizeof(initmsg
));
394 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
395 F
->fd
, strerror(rb_get_sockerr(F
)));
399 /* Configure RTO values to reduce the maximum timeout */
400 memset(&rtoinfo
, 0, sizeof(rtoinfo
));
401 rtoinfo
.srto_initial
= 3000;
402 rtoinfo
.srto_min
= 1000;
403 rtoinfo
.srto_max
= 10000;
405 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_RTOINFO
, &rtoinfo
, sizeof(rtoinfo
));
407 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
408 F
->fd
, strerror(rb_get_sockerr(F
)));
413 * Configure peer address parameters to ensure that we monitor the connection
414 * more often than the default and don't timeout retransmit attempts before
415 * the ping timeout does.
417 * Each peer address will timeout reachability in about 750s.
419 memset(&paddrparams
, 0, sizeof(paddrparams
));
420 paddrparams
.spp_assoc_id
= 0;
421 memcpy(&paddrparams
.spp_address
, &in6addr_any
, sizeof(in6addr_any
));
422 paddrparams
.spp_pathmaxrxt
= 50;
423 paddrparams
.spp_hbinterval
= 5000;
424 paddrparams
.spp_flags
|= SPP_HB_ENABLE
;
426 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_PEER_ADDR_PARAMS
, &paddrparams
, sizeof(paddrparams
));
428 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_PEER_ADDR_PARAMS for fd %d: %s",
429 F
->fd
, strerror(rb_get_sockerr(F
)));
433 /* Configure association parameters for retransmit attempts as above */
434 memset(&assocparams
, 0, sizeof(assocparams
));
435 assocparams
.sasoc_assoc_id
= 0;
436 assocparams
.sasoc_asocmaxrxt
= 50;
438 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_ASSOCINFO
, &assocparams
, sizeof(assocparams
));
440 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
441 F
->fd
, strerror(rb_get_sockerr(F
)));
450 rb_bind(rb_fde_t
*F
, struct sockaddr
*addr
)
454 ret
= rb_setsockopt_reuseaddr(F
);
458 ret
= bind(F
->fd
, addr
, GET_SS_LEN(addr
));
467 rb_sctp_bindx_only(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
471 for (size_t i
= 0; i
< len
; i
++) {
472 if (GET_SS_FAMILY(&addrs
[i
]) == AF_UNSPEC
)
475 ret
= sctp_bindx(F
->fd
, (struct sockaddr
*)&addrs
[i
], 1, SCTP_BINDX_ADD_ADDR
);
485 rb_sctp_bindx(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
490 if ((F
->type
& RB_FD_SCTP
) == 0)
493 ret
= rb_setsockopt_reuseaddr(F
);
497 ret
= rb_sctp_bindx_only(F
, addrs
, len
);
508 rb_inet_get_proto(rb_fde_t
*F
)
511 if (F
->type
& RB_FD_SCTP
)
517 static void rb_accept_tryaccept(rb_fde_t
*F
, void *data
__attribute__((unused
))) {
518 struct rb_sockaddr_storage st
;
520 rb_socklen_t addrlen
;
525 memset(&st
, 0, sizeof(st
));
526 addrlen
= sizeof(st
);
528 new_fd
= accept(F
->fd
, (struct sockaddr
*)&st
, &addrlen
);
532 rb_setselect(F
, RB_SELECT_ACCEPT
, rb_accept_tryaccept
, NULL
);
538 new_F
= rb_open(new_fd
, RB_FD_SOCKET
| (F
->type
& RB_FD_INHERIT_TYPES
), "Incoming Connection");
543 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
549 if(rb_unlikely(!rb_set_nb(new_F
)))
552 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F
->fd
);
556 mangle_mapped_sockaddr((struct sockaddr
*)&st
);
558 if(F
->accept
->precb
!= NULL
)
560 if(!F
->accept
->precb(new_F
, (struct sockaddr
*)&st
, addrlen
, F
->accept
->data
)) /* pre-callback decided to drop it */
564 if(F
->type
& RB_FD_SSL
)
566 rb_ssl_accept_setup(F
, new_F
, (struct sockaddr
*)&st
, addrlen
);
569 #endif /* HAVE_SSL */
571 F
->accept
->callback(new_F
, RB_OK
, (struct sockaddr
*)&st
, addrlen
,
578 /* try to accept a TCP connection */
580 rb_accept_tcp(rb_fde_t
*F
, ACPRE
* precb
, ACCB
* callback
, void *data
)
584 lrb_assert(callback
);
586 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
587 F
->accept
->callback
= callback
;
588 F
->accept
->data
= data
;
589 F
->accept
->precb
= precb
;
590 rb_accept_tryaccept(F
, NULL
);
594 * void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
595 * struct sockaddr *clocal,
596 * CNCB *callback, void *data, int timeout)
597 * Input: An fd to connect with, a host and port to connect to,
598 * a local sockaddr to connect from (or NULL to use the
599 * default), a callback, the data to pass into the callback, the
602 * Side-effects: A non-blocking connection to the host is started, and
603 * if necessary, set up for selection. The callback given
604 * may be called now, or it may be called later.
607 rb_connect_tcp(rb_fde_t
*F
, struct sockaddr
*dest
,
608 struct sockaddr
*clocal
, CNCB
* callback
, void *data
, int timeout
)
615 lrb_assert(callback
);
616 F
->connect
= rb_malloc(sizeof(struct conndata
));
617 F
->connect
->callback
= callback
;
618 F
->connect
->data
= data
;
620 memcpy(&F
->connect
->hostaddr
, dest
, sizeof(F
->connect
->hostaddr
));
622 /* Note that we're using a passed sockaddr here. This is because
623 * generally you'll be bind()ing to a sockaddr grabbed from
624 * getsockname(), so this makes things easier.
625 * XXX If NULL is passed as local, we should later on bind() to the
626 * virtual host IP, for completeness.
629 if((clocal
!= NULL
) && (bind(F
->fd
, clocal
, GET_SS_LEN(clocal
)) < 0))
631 /* Failure, call the callback with RB_ERR_BIND */
632 rb_connect_callback(F
, RB_ERR_BIND
);
637 /* We have a valid IP, so we just call tryconnect */
638 /* Make sure we actually set the timeout here .. */
639 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
641 retval
= connect(F
->fd
,
642 (struct sockaddr
*)&F
->connect
->hostaddr
,
643 GET_SS_LEN(&F
->connect
->hostaddr
));
647 * If we get EISCONN, then we've already connect()ed the socket,
648 * which is a good thing.
652 if (errno
== EISCONN
) {
653 rb_connect_callback(F
, RB_OK
);
654 } else if (rb_ignore_errno(errno
)) {
655 /* Ignore error? Reschedule */
656 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
658 /* Error? Fail with RB_ERR_CONNECT */
659 rb_connect_callback(F
, RB_ERR_CONNECT
);
663 /* If we get here, we've succeeded, so call with RB_OK */
664 rb_connect_callback(F
, RB_OK
);
668 rb_connect_sctp(rb_fde_t
*F
, struct sockaddr_storage
*dest
, size_t dest_len
,
669 struct sockaddr_storage
*clocal
, size_t clocal_len
,
670 CNCB
*callback
, void *data
, int timeout
)
673 uint8_t packed_dest
[sizeof(struct sockaddr_storage
) * dest_len
];
674 uint8_t *p
= &packed_dest
[0];
681 lrb_assert(callback
);
682 F
->connect
= rb_malloc(sizeof(struct conndata
));
683 F
->connect
->callback
= callback
;
684 F
->connect
->data
= data
;
686 if ((F
->type
& RB_FD_SCTP
) == 0) {
687 rb_connect_callback(F
, RB_ERR_CONNECT
);
691 for (size_t i
= 0; i
< dest_len
; i
++) {
692 if (GET_SS_FAMILY(&dest
[i
]) == AF_INET6
) {
693 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in6
));
695 p
+= sizeof(struct sockaddr_in6
);
696 } else if (GET_SS_FAMILY(&dest
[i
]) == AF_INET
) {
697 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in
));
699 p
+= sizeof(struct sockaddr_in
);
704 memcpy(&F
->connect
->hostaddr
, &dest
[0], sizeof(F
->connect
->hostaddr
));
706 if ((clocal_len
> 0) && (rb_sctp_bindx_only(F
, clocal
, clocal_len
) < 0)) {
707 /* Failure, call the callback with RB_ERR_BIND */
708 rb_connect_callback(F
, RB_ERR_BIND
);
713 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
715 retval
= sctp_connectx(F
->fd
, (struct sockaddr
*)packed_dest
, dest_len
, NULL
);
719 * If we get EISCONN, then we've already connect()ed the socket,
720 * which is a good thing.
724 if (errno
== EISCONN
) {
725 rb_connect_callback(F
, RB_OK
);
726 } else if (rb_ignore_errno(errno
)) {
727 /* Ignore error? Reschedule */
728 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
730 /* Error? Fail with RB_ERR_CONNECT */
731 rb_connect_callback(F
, RB_ERR_CONNECT
);
735 /* If we get here, we've succeeded, so call with RB_OK */
736 rb_connect_callback(F
, RB_OK
);
738 rb_connect_callback(F
, RB_ERR_CONNECT
);
743 * rb_connect_callback() - call the callback, and continue with life
746 rb_connect_callback(rb_fde_t
*F
, int status
)
750 int errtmp
= errno
; /* save errno as rb_settimeout clobbers it sometimes */
752 /* This check is gross..but probably necessary */
753 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
755 /* Clear the connect flag + handler */
756 hdl
= F
->connect
->callback
;
757 data
= F
->connect
->data
;
758 F
->connect
->callback
= NULL
;
761 /* Clear the timeout handler */
762 rb_settimeout(F
, 0, NULL
, NULL
);
764 /* Call the handler */
765 hdl(F
, status
, data
);
770 * rb_connect_timeout() - this gets called when the socket connection
771 * times out. This *only* can be called once connect() is initially
775 rb_connect_timeout(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
778 rb_connect_callback(F
, RB_ERR_TIMEOUT
);
782 rb_connect_outcome(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
786 socklen_t len
= sizeof(err
);
788 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
790 retval
= getsockopt(F
->fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
793 } else if (err
!= 0) {
798 /* Error? Fail with RB_ERR_CONNECT */
799 rb_connect_callback(F
, RB_ERR_CONNECT
);
802 /* If we get here, we've succeeded, so call with RB_OK */
803 rb_connect_callback(F
, RB_OK
);
808 rb_connect_sockaddr(rb_fde_t
*F
, struct sockaddr
*addr
, int len
)
813 memcpy(addr
, &F
->connect
->hostaddr
, len
);
818 * rb_error_str() - return an error string for the given error condition
823 if(error
< 0 || error
>= RB_ERR_MAX
)
824 return "Invalid error number!";
825 return rb_err_str
[error
];
830 rb_socketpair(int family
, int sock_type
, int proto
, rb_fde_t
**F1
, rb_fde_t
**F2
, const char *note
)
832 rb_platform_fd_t nfd
[2];
833 if(number_fd
>= rb_maxconnections
)
839 #ifdef HAVE_SOCKETPAIR
840 if(socketpair(family
, sock_type
, proto
, nfd
))
842 if(sock_type
== SOCK_DGRAM
)
844 return rb_inet_socketpair_udp(F1
, F2
);
847 if(rb_inet_socketpair(AF_INET
, sock_type
, proto
, nfd
))
854 *F1
= rb_open(nfd
[0], RB_FD_SOCKET
, note
);
855 *F2
= rb_open(nfd
[1], RB_FD_SOCKET
, note
);
870 /* Set the socket non-blocking, and other wonderful bits */
871 if(rb_unlikely(!rb_set_nb(*F1
)))
873 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[0], strerror(errno
));
879 if(rb_unlikely(!rb_set_nb(*F2
)))
881 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[1], strerror(errno
));
892 rb_pipe(rb_fde_t
**F1
, rb_fde_t
**F2
, const char *desc
)
895 rb_platform_fd_t fd
[2];
896 if(number_fd
>= rb_maxconnections
)
905 *F1
= rb_open(fd
[0], RB_FD_PIPE
, desc
);
906 *F2
= rb_open(fd
[1], RB_FD_PIPE
, desc
);
908 if(rb_unlikely(!rb_set_nb(*F1
)))
910 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[0], strerror(errno
));
916 if(rb_unlikely(!rb_set_nb(*F2
)))
918 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[1], strerror(errno
));
927 /* Its not a pipe..but its selectable. I'll take dirty hacks
930 return rb_socketpair(AF_INET
, SOCK_STREAM
, 0, F1
, F2
, desc
);
935 * rb_socket() - open a socket
937 * This is a highly highly cut down version of squid's rb_open() which
938 * for the most part emulates socket(), *EXCEPT* it fails if we're about
939 * to run out of file descriptors.
942 rb_socket(int family
, int sock_type
, int proto
, const char *note
)
946 /* First, make sure we aren't going to run out of file descriptors */
947 if(rb_unlikely(number_fd
>= rb_maxconnections
))
954 * Next, we try to open the socket. We *should* drop the reserved FD
955 * limit if/when we get an error, but we can deal with that later.
958 fd
= socket(family
, sock_type
, proto
);
960 if(rb_unlikely(fd
< 0))
961 return NULL
; /* errno will be passed through, yay.. */
964 * Make sure we can take both IPv4 and IPv6 connections
965 * on an AF_INET6 SCTP socket, otherwise keep them separate
967 if(family
== AF_INET6
)
970 int v6only
= (proto
== IPPROTO_SCTP
) ? 0 : 1;
974 if(setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (void *) &v6only
, sizeof(v6only
)) == -1)
976 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
977 v6only
, fd
, strerror(errno
));
983 F
= rb_open(fd
, RB_FD_SOCKET
, note
);
986 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd
,
993 if (proto
== IPPROTO_SCTP
) {
994 F
->type
|= RB_FD_SCTP
;
996 if (rb_setsockopt_sctp(F
)) {
997 rb_lib_log("rb_socket: Could not set SCTP socket options on FD %d: %s",
998 fd
, strerror(errno
));
1005 /* Set the socket non-blocking, and other wonderful bits */
1006 if(rb_unlikely(!rb_set_nb(F
)))
1008 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
, strerror(errno
));
1017 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
1018 * socket manged the sockaddr.
1021 mangle_mapped_sockaddr(struct sockaddr
*in
)
1023 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)in
;
1025 if(in
->sa_family
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&in6
->sin6_addr
))
1027 struct sockaddr_in in4
;
1028 memset(&in4
, 0, sizeof(struct sockaddr_in
));
1029 in4
.sin_family
= AF_INET
;
1030 in4
.sin_port
= in6
->sin6_port
;
1031 in4
.sin_addr
.s_addr
= ((uint32_t *)&in6
->sin6_addr
)[3];
1032 memcpy(in
, &in4
, sizeof(struct sockaddr_in
));
1037 * rb_listen() - listen on a port
1040 rb_listen(rb_fde_t
*F
, int backlog
, int defer_accept
)
1044 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| (F
->type
& RB_FD_INHERIT_TYPES
);
1045 result
= listen(F
->fd
, backlog
);
1047 #ifdef TCP_DEFER_ACCEPT
1048 if (defer_accept
&& !result
)
1050 (void)setsockopt(F
->fd
, IPPROTO_TCP
, TCP_DEFER_ACCEPT
, &backlog
, sizeof(int));
1053 #ifdef SO_ACCEPTFILTER
1054 if (defer_accept
&& !result
)
1056 struct accept_filter_arg afa
;
1058 memset(&afa
, '\0', sizeof afa
);
1059 rb_strlcpy(afa
.af_name
, "dataready", sizeof afa
.af_name
);
1060 (void)setsockopt(F
->fd
, SOL_SOCKET
, SO_ACCEPTFILTER
, &afa
,
1069 rb_fdlist_init(int closeall
, int maxfds
, size_t heapsize
)
1071 static int initialized
= 0;
1075 int vers
= MAKEWORD(2, 0);
1077 err
= WSAStartup(vers
, &wsaData
);
1080 rb_lib_die("WSAStartup failed");
1086 rb_maxconnections
= maxfds
;
1089 /* Since we're doing this once .. */
1092 fd_heap
= rb_bh_create(sizeof(rb_fde_t
), heapsize
, "librb_fd_heap");
1097 /* Called to open a given filedescriptor */
1099 rb_open(rb_platform_fd_t fd
, uint8_t type
, const char *desc
)
1102 lrb_assert(fd
>= 0);
1106 lrb_assert(!IsFDOpen(F
));
1107 if(rb_unlikely(IsFDOpen(F
)))
1110 if(F
!= NULL
&& F
->desc
!= NULL
)
1114 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd
, fdesc
);
1122 F
->desc
= rb_strndup(desc
, FD_DESC_SZ
);
1128 /* Called to close a given filedescriptor */
1130 rb_close(rb_fde_t
*F
)
1139 lrb_assert(IsFDOpen(F
));
1141 lrb_assert(!(type
& RB_FD_FILE
));
1142 if(rb_unlikely(type
& RB_FD_FILE
))
1144 lrb_assert(F
->read_handler
== NULL
);
1145 lrb_assert(F
->write_handler
== NULL
);
1148 if (type
& RB_FD_LISTEN
) {
1152 rb_setselect(F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
1153 rb_settimeout(F
, 0, NULL
, NULL
);
1155 rb_free(F
->connect
);
1158 if(type
& RB_FD_SSL
)
1162 #endif /* HAVE_SSL */
1169 if(type
& RB_FD_LISTEN
)
1170 shutdown(fd
, SHUT_RDWR
);
1175 * rb_dump_fd() - dump the list of active filedescriptors
1178 rb_dump_fd(DUMPCB
* cb
, void *data
)
1180 static const char *empty
= "";
1182 rb_dlink_list
*bucket
;
1186 for(i
= 0; i
< RB_FD_HASH_SIZE
; i
++)
1188 bucket
= &rb_fd_table
[i
];
1190 if(rb_dlink_list_length(bucket
) <= 0)
1193 RB_DLINK_FOREACH(ptr
, bucket
->head
)
1196 if(F
== NULL
|| !IsFDOpen(F
))
1199 cb(F
->fd
, F
->desc
? F
->desc
: empty
, data
);
1205 * rb_note() - set the fd note
1207 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1211 rb_note(rb_fde_t
*F
, const char *string
)
1217 F
->desc
= rb_strndup(string
, FD_DESC_SZ
);
1221 rb_set_type(rb_fde_t
*F
, uint8_t type
)
1223 /* if the caller is calling this, lets assume they have a clue */
1229 rb_get_type(rb_fde_t
*F
)
1235 rb_fd_ssl(rb_fde_t
*F
)
1239 if(F
->type
& RB_FD_SSL
)
1245 rb_get_fd(rb_fde_t
*F
)
1253 rb_get_fde(rb_platform_fd_t fd
)
1255 return rb_find_fd(fd
);
1259 rb_read(rb_fde_t
*F
, void *buf
, int count
)
1265 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1266 * an SSL socket as a regular socket
1269 if(F
->type
& RB_FD_SSL
)
1271 return rb_ssl_read(F
, buf
, count
);
1274 if(F
->type
& RB_FD_SOCKET
)
1276 ret
= recv(F
->fd
, buf
, count
, 0);
1286 return read(F
->fd
, buf
, count
);
1291 rb_write(rb_fde_t
*F
, const void *buf
, int count
)
1298 if(F
->type
& RB_FD_SSL
)
1300 return rb_ssl_write(F
, buf
, count
);
1303 if(F
->type
& RB_FD_SOCKET
)
1305 ret
= send(F
->fd
, buf
, count
, MSG_NOSIGNAL
);
1313 return write(F
->fd
, buf
, count
);
1316 #if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1318 rb_fake_writev(rb_fde_t
*F
, const struct rb_iovec
*vp
, size_t vpcount
)
1322 while(vpcount
-- > 0)
1324 ssize_t written
= rb_write(F
, vp
->iov_base
, vp
->iov_len
);
1340 #if defined(WIN32) || !defined(HAVE_WRITEV)
1342 rb_writev(rb_fde_t
*F
, struct rb_iovec
* vecount
, int count
)
1344 return rb_fake_writev(F
, vecount
, count
);
1349 rb_writev(rb_fde_t
*F
, struct rb_iovec
* vector
, int count
)
1357 if(F
->type
& RB_FD_SSL
)
1359 return rb_fake_writev(F
, vector
, count
);
1361 #endif /* HAVE_SSL */
1363 if(F
->type
& RB_FD_SOCKET
)
1366 memset(&msg
, 0, sizeof(msg
));
1367 msg
.msg_iov
= (struct iovec
*)vector
;
1368 msg
.msg_iovlen
= count
;
1369 return sendmsg(F
->fd
, &msg
, MSG_NOSIGNAL
);
1371 #endif /* HAVE_SENDMSG */
1372 return writev(F
->fd
, (struct iovec
*)vector
, count
);
1379 * From: Thomas Helvey <tomh@inxpress.net>
1381 static const char *IpQuadTab
[] = {
1382 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1383 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1384 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1385 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1386 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1387 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1388 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1389 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1390 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1391 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1392 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1393 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1394 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1395 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1396 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1397 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1398 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1399 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1400 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1401 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1402 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1403 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1404 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1405 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1406 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1407 "250", "251", "252", "253", "254", "255"
1411 * inetntoa - in_addr to string
1412 * changed name to remove collision possibility and
1413 * so behaviour is guaranteed to take a pointer arg.
1415 * inet_ntoa -- returned the dotted notation of a given
1418 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1422 inetntoa(const char *in
)
1424 static char buf
[16];
1426 const unsigned char *a
= (const unsigned char *)in
;
1429 n
= IpQuadTab
[*a
++];
1433 n
= IpQuadTab
[*a
++];
1437 n
= IpQuadTab
[*a
++];
1449 * WARNING: Don't even consider trying to compile this on a system where
1450 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1453 static const char *inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
);
1454 static const char *inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
);
1457 * inet_ntop4(src, dst, size)
1458 * format an IPv4 address
1460 * `dst' (as a const)
1462 * (1) uses no statics
1463 * (2) takes a unsigned char* not an in_addr as input
1468 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
1472 return strcpy(dst
, inetntoa((const char *)src
));
1476 * inet_ntop6(src, dst, size)
1477 * convert IPv6 binary address into presentation (printable) format
1482 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
1485 * Note that int32_t and int16_t need only be "at least" large enough
1486 * to contain a value of the specified size. On some systems, like
1487 * Crays, there is no such thing as an integer variable with 16 bits.
1488 * Keep this in mind if you think this function should have been coded
1489 * to use pointer overlays. All the world's not a VAX.
1491 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
1497 unsigned int words
[IN6ADDRSZ
/ INT16SZ
];
1502 * Copy the input (bytewise) array into a wordwise array.
1503 * Find the longest run of 0x00's in src[] for :: shorthanding.
1505 memset(words
, '\0', sizeof words
);
1506 for(i
= 0; i
< IN6ADDRSZ
; i
+= 2)
1507 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
1512 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1517 cur
.base
= i
, cur
.len
= 1;
1525 if(best
.base
== -1 || cur
.len
> best
.len
)
1533 if(best
.base
== -1 || cur
.len
> best
.len
)
1536 if(best
.base
!= -1 && best
.len
< 2)
1540 * Format the result.
1543 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1545 /* Are we inside the best run of 0x00's? */
1546 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
1556 /* Are we following an initial run of 0x00s or any real hex? */
1559 /* Is this address an encapsulated IPv4? */
1560 if(i
== 6 && best
.base
== 0 &&
1561 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
1563 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
1568 tp
+= sprintf(tp
, "%x", words
[i
]);
1570 /* Was it a trailing run of 0x00's? */
1571 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
1576 * Check for overflow, copy, and we're done.
1579 if((unsigned int)(tp
- tmp
) > size
)
1583 return memcpy(dst
, tmp
, tp
- tmp
);
1587 rb_inet_pton_sock(const char *src
, struct sockaddr_storage
*dst
)
1589 memset(dst
, 0, sizeof(*dst
));
1590 if(rb_inet_pton(AF_INET
, src
, &((struct sockaddr_in
*)dst
)->sin_addr
))
1592 SET_SS_FAMILY(dst
, AF_INET
);
1593 SET_SS_PORT(dst
, 0);
1594 SET_SS_LEN(dst
, sizeof(struct sockaddr_in
));
1597 else if(rb_inet_pton(AF_INET6
, src
, &((struct sockaddr_in6
*)dst
)->sin6_addr
))
1599 SET_SS_FAMILY(dst
, AF_INET6
);
1600 SET_SS_PORT(dst
, 0);
1601 SET_SS_LEN(dst
, sizeof(struct sockaddr_in6
));
1608 rb_inet_ntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
1610 switch (src
->sa_family
)
1613 return (rb_inet_ntop(AF_INET
, &((struct sockaddr_in
*)src
)->sin_addr
, dst
, size
));
1615 return (rb_inet_ntop
1616 (AF_INET6
, &((struct sockaddr_in6
*)src
)->sin6_addr
, dst
, size
));
1623 * rb_inet_ntop(af, src, dst, size)
1624 * convert a network format address to presentation format.
1626 * pointer to presentation format address (`dst'), or NULL (see errno).
1631 rb_inet_ntop(int af
, const void *src
, char *dst
, unsigned int size
)
1636 return (inet_ntop4(src
, dst
, size
));
1638 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*)src
) ||
1639 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*)src
))
1641 ((const unsigned char *)&((const struct in6_addr
*)src
)->
1642 s6_addr
[12], dst
, size
));
1644 return (inet_ntop6(src
, dst
, size
));
1652 * WARNING: Don't even consider trying to compile this on a system where
1653 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1657 * rb_inet_pton(af, src, dst)
1658 * convert from presentation format (which usually means ASCII printable)
1659 * to network format (which is usually some kind of binary format).
1661 * 1 if the address was valid for the specified address family
1662 * 0 if the address wasn't valid (`dst' is untouched in this case)
1663 * -1 if some other error occurred (`dst' is untouched in this case, too)
1669 * inet_pton4(src, dst)
1670 * like inet_aton() but without all the hexadecimal and shorthand.
1672 * 1 if `src' is a valid dotted quad, else 0.
1674 * does not touch `dst' unless it's returning 1.
1679 inet_pton4(const char *src
, unsigned char *dst
)
1681 int saw_digit
, octets
, ch
;
1682 unsigned char tmp
[INADDRSZ
], *tp
;
1687 while((ch
= *src
++) != '\0')
1690 if(ch
>= '0' && ch
<= '9')
1692 unsigned int new = *tp
* 10 + (ch
- '0');
1704 else if(ch
== '.' && saw_digit
)
1716 memcpy(dst
, tmp
, INADDRSZ
);
1721 * inet_pton6(src, dst)
1722 * convert presentation level address to network order binary form.
1724 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1726 * (1) does not touch `dst' unless it's returning 1.
1727 * (2) :: in a full address is silently ignored.
1729 * inspired by Mark Andrews.
1735 inet_pton6(const char *src
, unsigned char *dst
)
1737 static const char xdigits
[] = "0123456789abcdef";
1738 unsigned char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
1743 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
1744 endp
= tp
+ IN6ADDRSZ
;
1746 /* Leading :: requires some special handling. */
1753 while((ch
= tolower((unsigned char)*src
++)) != '\0')
1757 pch
= strchr(xdigits
, ch
);
1761 val
|= (pch
- xdigits
);
1777 else if(*src
== '\0')
1781 if(tp
+ INT16SZ
> endp
)
1783 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1784 *tp
++ = (unsigned char)val
& 0xff;
1789 if(*src
!= '\0' && ch
== '.')
1791 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
1795 break; /* '\0' was seen by inet_pton4(). */
1804 if(tp
+ INT16SZ
> endp
)
1806 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1807 *tp
++ = (unsigned char)val
& 0xff;
1812 * Since some memmove()'s erroneously fail to handle
1813 * overlapping regions, we'll do the shift by hand.
1815 const int n
= tp
- colonp
;
1820 for(i
= 1; i
<= n
; i
++)
1822 endp
[-i
] = colonp
[n
- i
];
1829 memcpy(dst
, tmp
, IN6ADDRSZ
);
1834 rb_inet_pton(int af
, const char *src
, void *dst
)
1839 return (inet_pton4(src
, dst
));
1841 /* Somebody might have passed as an IPv4 address this is sick but it works */
1842 if(inet_pton4(src
, dst
))
1844 char tmp
[HOSTIPLEN
];
1845 sprintf(tmp
, "::ffff:%s", src
);
1846 return (inet_pton6(tmp
, dst
));
1849 return (inet_pton6(src
, dst
));
1857 #ifndef HAVE_SOCKETPAIR
1859 /* mostly based on perl's emulation of socketpair udp */
1861 rb_inet_socketpair_udp(rb_fde_t
**newF1
, rb_fde_t
**newF2
)
1863 struct sockaddr_in addr
[2];
1864 rb_socklen_t size
= sizeof(struct sockaddr_in
);
1866 rb_platform_fd_t fd
[2];
1868 unsigned short port
;
1869 struct timeval wait
= { 0, 100000 };
1872 struct sockaddr_in readfrom
;
1873 unsigned short buf
[2];
1876 memset(&addr
, 0, sizeof(addr
));
1878 for(i
= 0; i
< 2; i
++)
1880 F
[i
] = rb_socket(AF_INET
, SOCK_DGRAM
, 0, "udp socketpair");
1883 addr
[i
].sin_family
= AF_INET
;
1884 addr
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1885 addr
[i
].sin_port
= 0;
1886 if(bind(rb_get_fd(F
[i
]), (struct sockaddr
*)&addr
[i
], sizeof(struct sockaddr_in
)))
1888 fd
[i
] = rb_get_fd(F
[i
]);
1891 for(i
= 0; i
< 2; i
++)
1893 if(getsockname(fd
[i
], (struct sockaddr
*)&addr
[i
], &size
))
1895 if(size
!= sizeof(struct sockaddr_in
))
1897 if(connect(fd
[!i
], (struct sockaddr
*)&addr
[i
], sizeof(struct sockaddr_in
)) == -1)
1901 for(i
= 0; i
< 2; i
++)
1903 port
= addr
[i
].sin_port
;
1904 got
= rb_write(F
[i
], &port
, sizeof(port
));
1905 if(got
!= sizeof(port
))
1913 max
= fd
[1] > fd
[0] ? fd
[1] : fd
[0];
1915 FD_SET(fd
[0], &rset
);
1916 FD_SET(fd
[1], &rset
);
1917 got
= select(max
+ 1, &rset
, NULL
, NULL
, &wait
);
1918 if(got
!= 2 || !FD_ISSET(fd
[0], &rset
) || !FD_ISSET(fd
[1], &rset
))
1925 for(i
= 0; i
< 2; i
++)
1928 int flag
= MSG_DONTWAIT
1932 got
= recvfrom(rb_get_fd(F
[i
]), (char *)&buf
, sizeof(buf
), flag
,
1933 (struct sockaddr
*)&readfrom
, &size
);
1936 if(got
!= sizeof(port
)
1937 || size
!= sizeof(struct sockaddr_in
)
1938 || buf
[0] != (unsigned short)addr
[!i
].sin_port
1939 || readfrom
.sin_family
!= addr
[!i
].sin_family
1940 || readfrom
.sin_addr
.s_addr
!= addr
[!i
].sin_addr
.s_addr
1941 || readfrom
.sin_port
!= addr
[!i
].sin_port
)
1950 #ifndef ECONNABORTED
1951 #define ECONNABORTED WSAECONNABORTED
1957 errno
= ECONNABORTED
;
1959 if(errno
!= ECONNABORTED
)
1972 rb_inet_socketpair(int family
, int type
, int protocol
, rb_platform_fd_t fd
[2])
1977 struct sockaddr_in listen_addr
;
1978 struct sockaddr_in connect_addr
;
1981 if(protocol
|| family
!= AF_INET
)
1983 errno
= EAFNOSUPPORT
;
1992 listener
= socket(AF_INET
, type
, 0);
1995 memset(&listen_addr
, 0, sizeof(listen_addr
));
1996 listen_addr
.sin_family
= AF_INET
;
1997 listen_addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1998 listen_addr
.sin_port
= 0; /* kernel choses port. */
1999 if(bind(listener
, (struct sockaddr
*)&listen_addr
, sizeof(listen_addr
)) == -1)
2000 goto tidy_up_and_fail
;
2001 if(listen(listener
, 1) == -1)
2002 goto tidy_up_and_fail
;
2004 connector
= socket(AF_INET
, type
, 0);
2006 goto tidy_up_and_fail
;
2007 /* We want to find out the port number to connect to. */
2008 size
= sizeof(connect_addr
);
2009 if(getsockname(listener
, (struct sockaddr
*)&connect_addr
, &size
) == -1)
2010 goto tidy_up_and_fail
;
2011 if(size
!= sizeof(connect_addr
))
2012 goto abort_tidy_up_and_fail
;
2013 if(connect(connector
, (struct sockaddr
*)&connect_addr
, sizeof(connect_addr
)) == -1)
2014 goto tidy_up_and_fail
;
2016 size
= sizeof(listen_addr
);
2017 acceptor
= accept(listener
, (struct sockaddr
*)&listen_addr
, &size
);
2019 goto tidy_up_and_fail
;
2020 if(size
!= sizeof(listen_addr
))
2021 goto abort_tidy_up_and_fail
;
2023 /* Now check we are talking to ourself by matching port and host on the
2025 if(getsockname(connector
, (struct sockaddr
*)&connect_addr
, &size
) == -1)
2026 goto tidy_up_and_fail
;
2027 if(size
!= sizeof(connect_addr
)
2028 || listen_addr
.sin_family
!= connect_addr
.sin_family
2029 || listen_addr
.sin_addr
.s_addr
!= connect_addr
.sin_addr
.s_addr
2030 || listen_addr
.sin_port
!= connect_addr
.sin_port
)
2032 goto abort_tidy_up_and_fail
;
2038 abort_tidy_up_and_fail
:
2039 errno
= EINVAL
; /* I hope this is portable and appropriate. */
2043 int save_errno
= errno
;
2058 static void (*setselect_handler
) (rb_fde_t
*, unsigned int, PF
*, void *);
2059 static int (*select_handler
) (long);
2060 static int (*setup_fd_handler
) (rb_fde_t
*);
2061 static int (*io_sched_event
) (struct ev_entry
*, int);
2062 static void (*io_unsched_event
) (struct ev_entry
*);
2063 static int (*io_supports_event
) (void);
2064 static void (*io_init_event
) (void);
2065 static char iotype
[25];
2074 rb_unsupported_event(void)
2082 if(!rb_init_netio_kqueue())
2084 setselect_handler
= rb_setselect_kqueue
;
2085 select_handler
= rb_select_kqueue
;
2086 setup_fd_handler
= rb_setup_fd_kqueue
;
2087 io_sched_event
= rb_kqueue_sched_event
;
2088 io_unsched_event
= rb_kqueue_unsched_event
;
2089 io_init_event
= rb_kqueue_init_event
;
2090 io_supports_event
= rb_kqueue_supports_event
;
2091 rb_strlcpy(iotype
, "kqueue", sizeof(iotype
));
2100 if(!rb_init_netio_epoll())
2102 setselect_handler
= rb_setselect_epoll
;
2103 select_handler
= rb_select_epoll
;
2104 setup_fd_handler
= rb_setup_fd_epoll
;
2105 io_sched_event
= rb_epoll_sched_event
;
2106 io_unsched_event
= rb_epoll_unsched_event
;
2107 io_supports_event
= rb_epoll_supports_event
;
2108 io_init_event
= rb_epoll_init_event
;
2109 rb_strlcpy(iotype
, "epoll", sizeof(iotype
));
2118 if(!rb_init_netio_ports())
2120 setselect_handler
= rb_setselect_ports
;
2121 select_handler
= rb_select_ports
;
2122 setup_fd_handler
= rb_setup_fd_ports
;
2123 io_sched_event
= rb_ports_sched_event
;
2124 io_unsched_event
= rb_ports_unsched_event
;
2125 io_init_event
= rb_ports_init_event
;
2126 io_supports_event
= rb_ports_supports_event
;
2127 rb_strlcpy(iotype
, "ports", sizeof(iotype
));
2136 if(!rb_init_netio_devpoll())
2138 setselect_handler
= rb_setselect_devpoll
;
2139 select_handler
= rb_select_devpoll
;
2140 setup_fd_handler
= rb_setup_fd_devpoll
;
2141 io_sched_event
= NULL
;
2142 io_unsched_event
= NULL
;
2143 io_init_event
= NULL
;
2144 io_supports_event
= rb_unsupported_event
;
2145 rb_strlcpy(iotype
, "devpoll", sizeof(iotype
));
2154 if(!rb_init_netio_sigio())
2156 setselect_handler
= rb_setselect_sigio
;
2157 select_handler
= rb_select_sigio
;
2158 setup_fd_handler
= rb_setup_fd_sigio
;
2159 io_sched_event
= rb_sigio_sched_event
;
2160 io_unsched_event
= rb_sigio_unsched_event
;
2161 io_supports_event
= rb_sigio_supports_event
;
2162 io_init_event
= rb_sigio_init_event
;
2164 rb_strlcpy(iotype
, "sigio", sizeof(iotype
));
2173 if(!rb_init_netio_poll())
2175 setselect_handler
= rb_setselect_poll
;
2176 select_handler
= rb_select_poll
;
2177 setup_fd_handler
= rb_setup_fd_poll
;
2178 io_sched_event
= NULL
;
2179 io_unsched_event
= NULL
;
2180 io_init_event
= NULL
;
2181 io_supports_event
= rb_unsupported_event
;
2182 rb_strlcpy(iotype
, "poll", sizeof(iotype
));
2191 if(!rb_init_netio_win32())
2193 setselect_handler
= rb_setselect_win32
;
2194 select_handler
= rb_select_win32
;
2195 setup_fd_handler
= rb_setup_fd_win32
;
2196 io_sched_event
= NULL
;
2197 io_unsched_event
= NULL
;
2198 io_init_event
= NULL
;
2199 io_supports_event
= rb_unsupported_event
;
2200 rb_strlcpy(iotype
, "win32", sizeof(iotype
));
2209 if(!rb_init_netio_select())
2211 setselect_handler
= rb_setselect_select
;
2212 select_handler
= rb_select_select
;
2213 setup_fd_handler
= rb_setup_fd_select
;
2214 io_sched_event
= NULL
;
2215 io_unsched_event
= NULL
;
2216 io_init_event
= NULL
;
2217 io_supports_event
= rb_unsupported_event
;
2218 rb_strlcpy(iotype
, "select", sizeof(iotype
));
2226 rb_io_sched_event(struct ev_entry
*ev
, int when
)
2228 if(ev
== NULL
|| io_supports_event
== NULL
|| io_sched_event
== NULL
2229 || !io_supports_event())
2231 return io_sched_event(ev
, when
);
2235 rb_io_unsched_event(struct ev_entry
*ev
)
2237 if(ev
== NULL
|| io_supports_event
== NULL
|| io_unsched_event
== NULL
2238 || !io_supports_event())
2240 io_unsched_event(ev
);
2244 rb_io_supports_event(void)
2246 if(io_supports_event
== NULL
)
2248 return io_supports_event();
2252 rb_io_init_event(void)
2255 rb_event_io_register_all();
2261 char *ioenv
= getenv("LIBRB_USE_IOTYPE");
2262 rb_fd_table
= rb_malloc(RB_FD_HASH_SIZE
* sizeof(rb_dlink_list
));
2267 if(!strcmp("epoll", ioenv
))
2272 else if(!strcmp("kqueue", ioenv
))
2277 else if(!strcmp("ports", ioenv
))
2282 else if(!strcmp("poll", ioenv
))
2287 else if(!strcmp("devpoll", ioenv
))
2292 else if(!strcmp("sigio", ioenv
))
2297 else if(!strcmp("select", ioenv
))
2302 if(!strcmp("win32", ioenv
))
2327 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2333 rb_setselect(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
2335 setselect_handler(F
, type
, handler
, client_data
);
2339 rb_select(unsigned long timeout
)
2341 int ret
= select_handler(timeout
);
2347 rb_setup_fd(rb_fde_t
*F
)
2349 return setup_fd_handler(F
);
2354 rb_ignore_errno(int error
)
2361 #if defined EWOULDBLOCK
2364 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
2384 #if defined(HAVE_SENDMSG) && !defined(WIN32)
2386 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2389 struct cmsghdr
*cmsg
;
2390 struct iovec iov
[1];
2392 uint8_t stype
= RB_FD_UNKNOWN
;
2394 rb_platform_fd_t fd
, len
, x
, rfds
;
2396 int control_len
= CMSG_SPACE(sizeof(int) * nfds
);
2398 iov
[0].iov_base
= data
;
2399 iov
[0].iov_len
= datasize
;
2401 msg
.msg_name
= NULL
;
2402 msg
.msg_namelen
= 0;
2406 cmsg
= alloca(control_len
);
2407 msg
.msg_control
= cmsg
;
2408 msg
.msg_controllen
= control_len
;
2410 if((len
= recvmsg(rb_get_fd(F
), &msg
, 0)) <= 0)
2413 if(msg
.msg_controllen
> 0 && msg
.msg_control
!= NULL
2414 && (cmsg
= CMSG_FIRSTHDR(&msg
)) != NULL
)
2416 rfds
= ((unsigned char *)cmsg
+ cmsg
->cmsg_len
- CMSG_DATA(cmsg
)) / sizeof(int);
2418 for(x
= 0; x
< nfds
&& x
< rfds
; x
++)
2420 fd
= ((int *)CMSG_DATA(cmsg
))[x
];
2421 stype
= RB_FD_UNKNOWN
;
2422 desc
= "remote unknown";
2425 if(S_ISSOCK(st
.st_mode
))
2427 stype
= RB_FD_SOCKET
;
2428 desc
= "remote socket";
2430 else if(S_ISFIFO(st
.st_mode
))
2433 desc
= "remote pipe";
2435 else if(S_ISREG(st
.st_mode
))
2438 desc
= "remote file";
2441 xF
[x
] = rb_open(fd
, stype
, desc
);
2451 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
, pid_t pid
__attribute__((unused
)))
2454 struct cmsghdr
*cmsg
;
2455 struct iovec iov
[1];
2458 memset(&msg
, 0, sizeof(msg
));
2461 iov
[0].iov_base
= &empty
;
2466 iov
[0].iov_base
= data
;
2467 iov
[0].iov_len
= datasize
;
2471 msg
.msg_name
= NULL
;
2472 msg
.msg_namelen
= 0;
2474 msg
.msg_control
= NULL
;
2475 msg
.msg_controllen
= 0;
2479 size_t ucount
= (size_t)count
;
2480 int len
= CMSG_SPACE(sizeof(int) * count
);
2483 msg
.msg_control
= buf
;
2484 msg
.msg_controllen
= len
;
2485 cmsg
= CMSG_FIRSTHDR(&msg
);
2486 cmsg
->cmsg_level
= SOL_SOCKET
;
2487 cmsg
->cmsg_type
= SCM_RIGHTS
;
2488 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * count
);
2490 for(size_t i
= 0; i
< ucount
; i
++)
2492 ((int *)CMSG_DATA(cmsg
))[i
] = rb_get_fd(F
[i
]);
2494 msg
.msg_controllen
= cmsg
->cmsg_len
;
2495 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2497 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2499 #else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2502 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2509 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
, pid_t pid
)
2515 #endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2518 rb_ipv4_from_ipv6(const struct sockaddr_in6
*restrict ip6
, struct sockaddr_in
*restrict ip4
)
2522 if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x02", 2))
2524 /* 6to4 and similar */
2525 memcpy(&ip4
->sin_addr
, ip6
->sin6_addr
.s6_addr
+ 2, 4);
2527 else if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x01\x00\x00", 4))
2530 for (i
= 0; i
< 4; i
++)
2531 ((uint8_t *)&ip4
->sin_addr
)[i
] = 0xFF ^
2532 ip6
->sin6_addr
.s6_addr
[12 + i
];
2536 SET_SS_LEN(ip4
, sizeof(struct sockaddr_in
));
2537 ip4
->sin_family
= AF_INET
;