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_set_cloexec(rb_fde_t
*F
)
267 SetHandleInformation((HANDLE
) F
->fd
, HANDLE_FLAG_INHERIT
, 0);
275 res
= fcntl(fd
, F_GETFD
, NULL
);
278 if(fcntl(fd
, F_SETFD
, res
| FD_CLOEXEC
) == -1)
286 rb_clear_cloexec(rb_fde_t
*F
)
289 SetHandleInformation((HANDLE
) F
->fd
, HANDLE_FLAG_INHERIT
, 1);
297 res
= fcntl(fd
, F_GETFD
, NULL
);
300 if(fcntl(fd
, F_SETFD
, res
& ~FD_CLOEXEC
) == -1)
308 * rb_settimeout() - set the socket timeout
310 * Set the timeout for the fd
313 rb_settimeout(rb_fde_t
*F
, time_t timeout
, PF
* callback
, void *cbdata
)
315 struct timeout_data
*td
;
320 lrb_assert(IsFDOpen(F
));
322 if(callback
== NULL
) /* user wants to remove */
326 rb_dlinkDelete(&td
->node
, &timeout_list
);
329 if(rb_dlink_list_length(&timeout_list
) == 0)
331 rb_event_delete(rb_timeout_ev
);
332 rb_timeout_ev
= NULL
;
337 if(F
->timeout
== NULL
)
338 td
= F
->timeout
= rb_malloc(sizeof(struct timeout_data
));
341 td
->timeout
= rb_current_time() + timeout
;
342 td
->timeout_handler
= callback
;
343 td
->timeout_data
= cbdata
;
344 rb_dlinkAdd(td
, &td
->node
, &timeout_list
);
345 if(rb_timeout_ev
== NULL
)
347 rb_timeout_ev
= rb_event_add("rb_checktimeouts", rb_checktimeouts
, NULL
, 5);
352 * rb_checktimeouts() - check the socket timeouts
354 * All this routine does is call the given callback/cbdata, without closing
355 * down the file descriptor. When close handlers have been implemented,
359 rb_checktimeouts(void *notused
__attribute__((unused
)))
361 rb_dlink_node
*ptr
, *next
;
362 struct timeout_data
*td
;
367 RB_DLINK_FOREACH_SAFE(ptr
, next
, timeout_list
.head
)
371 if(F
== NULL
|| !IsFDOpen(F
))
374 if(td
->timeout
< rb_current_time())
376 hdl
= td
->timeout_handler
;
377 data
= td
->timeout_data
;
378 rb_dlinkDelete(&td
->node
, &timeout_list
);
387 rb_setsockopt_reuseaddr(rb_fde_t
*F
)
392 ret
= setsockopt(F
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt_one
, sizeof(opt_one
));
394 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
395 F
->fd
, strerror(rb_get_sockerr(F
)));
404 rb_setsockopt_sctp(rb_fde_t
*F
)
408 /* workaround for https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sctp?id=299ee123e19889d511092347f5fc14db0f10e3a6 */
409 char *env_mapped
= getenv("SCTP_I_WANT_MAPPED_V4_ADDR");
410 int opt_mapped
= env_mapped
!= NULL
? atoi(env_mapped
) : opt_zero
;
412 struct sctp_initmsg initmsg
;
413 struct sctp_rtoinfo rtoinfo
;
414 struct sctp_paddrparams paddrparams
;
415 struct sctp_assocparams assocparams
;
417 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_NODELAY
, &opt_one
, sizeof(opt_one
));
419 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
420 F
->fd
, strerror(rb_get_sockerr(F
)));
424 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_I_WANT_MAPPED_V4_ADDR
, &opt_mapped
, sizeof(opt_mapped
));
426 rb_lib_log("rb_setsockopt_sctp: Cannot unset SCTP_I_WANT_MAPPED_V4_ADDR for fd %d: %s",
427 F
->fd
, strerror(rb_get_sockerr(F
)));
431 /* Configure INIT message to specify that we only want one stream */
432 memset(&initmsg
, 0, sizeof(initmsg
));
433 initmsg
.sinit_num_ostreams
= 1;
434 initmsg
.sinit_max_instreams
= 1;
436 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_INITMSG
, &initmsg
, sizeof(initmsg
));
438 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
439 F
->fd
, strerror(rb_get_sockerr(F
)));
443 /* Configure RTO values to reduce the maximum timeout */
444 memset(&rtoinfo
, 0, sizeof(rtoinfo
));
445 rtoinfo
.srto_initial
= 3000;
446 rtoinfo
.srto_min
= 1000;
447 rtoinfo
.srto_max
= 10000;
449 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_RTOINFO
, &rtoinfo
, sizeof(rtoinfo
));
451 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
452 F
->fd
, strerror(rb_get_sockerr(F
)));
457 * Configure peer address parameters to ensure that we monitor the connection
458 * more often than the default and don't timeout retransmit attempts before
459 * the ping timeout does.
461 * Each peer address will timeout reachability in about 750s.
463 memset(&paddrparams
, 0, sizeof(paddrparams
));
464 paddrparams
.spp_assoc_id
= 0;
465 memcpy(&paddrparams
.spp_address
, &in6addr_any
, sizeof(in6addr_any
));
466 paddrparams
.spp_pathmaxrxt
= 50;
467 paddrparams
.spp_hbinterval
= 5000;
468 paddrparams
.spp_flags
|= SPP_HB_ENABLE
;
470 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_PEER_ADDR_PARAMS
, &paddrparams
, sizeof(paddrparams
));
472 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_PEER_ADDR_PARAMS for fd %d: %s",
473 F
->fd
, strerror(rb_get_sockerr(F
)));
477 /* Configure association parameters for retransmit attempts as above */
478 memset(&assocparams
, 0, sizeof(assocparams
));
479 assocparams
.sasoc_assoc_id
= 0;
480 assocparams
.sasoc_asocmaxrxt
= 50;
482 ret
= setsockopt(F
->fd
, SOL_SCTP
, SCTP_ASSOCINFO
, &assocparams
, sizeof(assocparams
));
484 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
485 F
->fd
, strerror(rb_get_sockerr(F
)));
494 rb_bind(rb_fde_t
*F
, struct sockaddr
*addr
)
498 ret
= rb_setsockopt_reuseaddr(F
);
502 ret
= bind(F
->fd
, addr
, GET_SS_LEN(addr
));
511 rb_sctp_bindx_only(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
515 for (size_t i
= 0; i
< len
; i
++) {
516 if (GET_SS_FAMILY(&addrs
[i
]) == AF_UNSPEC
)
519 ret
= sctp_bindx(F
->fd
, (struct sockaddr
*)&addrs
[i
], 1, SCTP_BINDX_ADD_ADDR
);
529 rb_sctp_bindx(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
534 if ((F
->type
& RB_FD_SCTP
) == 0)
537 ret
= rb_setsockopt_reuseaddr(F
);
541 ret
= rb_sctp_bindx_only(F
, addrs
, len
);
552 rb_inet_get_proto(rb_fde_t
*F
)
555 if (F
->type
& RB_FD_SCTP
)
561 static void rb_accept_tryaccept(rb_fde_t
*F
, void *data
__attribute__((unused
))) {
562 struct rb_sockaddr_storage st
;
564 rb_socklen_t addrlen
;
569 memset(&st
, 0, sizeof(st
));
570 addrlen
= sizeof(st
);
572 new_fd
= accept(F
->fd
, (struct sockaddr
*)&st
, &addrlen
);
576 rb_setselect(F
, RB_SELECT_ACCEPT
, rb_accept_tryaccept
, NULL
);
582 new_F
= rb_open(new_fd
, RB_FD_SOCKET
| (F
->type
& RB_FD_INHERIT_TYPES
), "Incoming Connection");
587 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
593 if(rb_unlikely(!rb_set_nb(new_F
)))
596 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F
->fd
);
600 mangle_mapped_sockaddr((struct sockaddr
*)&st
);
602 if(F
->accept
->precb
!= NULL
)
604 if(!F
->accept
->precb(new_F
, (struct sockaddr
*)&st
, addrlen
, F
->accept
->data
)) /* pre-callback decided to drop it */
608 if(F
->type
& RB_FD_SSL
)
610 rb_ssl_accept_setup(F
, new_F
, (struct sockaddr
*)&st
, addrlen
);
613 #endif /* HAVE_SSL */
615 F
->accept
->callback(new_F
, RB_OK
, (struct sockaddr
*)&st
, addrlen
,
622 /* try to accept a TCP connection */
624 rb_accept_tcp(rb_fde_t
*F
, ACPRE
* precb
, ACCB
* callback
, void *data
)
628 lrb_assert(callback
);
630 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
631 F
->accept
->callback
= callback
;
632 F
->accept
->data
= data
;
633 F
->accept
->precb
= precb
;
634 rb_accept_tryaccept(F
, NULL
);
638 * void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
639 * struct sockaddr *clocal,
640 * CNCB *callback, void *data, int timeout)
641 * Input: An fd to connect with, a host and port to connect to,
642 * a local sockaddr to connect from (or NULL to use the
643 * default), a callback, the data to pass into the callback, the
646 * Side-effects: A non-blocking connection to the host is started, and
647 * if necessary, set up for selection. The callback given
648 * may be called now, or it may be called later.
651 rb_connect_tcp(rb_fde_t
*F
, struct sockaddr
*dest
,
652 struct sockaddr
*clocal
, CNCB
* callback
, void *data
, int timeout
)
659 lrb_assert(callback
);
660 F
->connect
= rb_malloc(sizeof(struct conndata
));
661 F
->connect
->callback
= callback
;
662 F
->connect
->data
= data
;
664 memcpy(&F
->connect
->hostaddr
, dest
, sizeof(F
->connect
->hostaddr
));
666 /* Note that we're using a passed sockaddr here. This is because
667 * generally you'll be bind()ing to a sockaddr grabbed from
668 * getsockname(), so this makes things easier.
669 * XXX If NULL is passed as local, we should later on bind() to the
670 * virtual host IP, for completeness.
673 if((clocal
!= NULL
) && (bind(F
->fd
, clocal
, GET_SS_LEN(clocal
)) < 0))
675 /* Failure, call the callback with RB_ERR_BIND */
676 rb_connect_callback(F
, RB_ERR_BIND
);
681 /* We have a valid IP, so we just call tryconnect */
682 /* Make sure we actually set the timeout here .. */
683 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
685 retval
= connect(F
->fd
,
686 (struct sockaddr
*)&F
->connect
->hostaddr
,
687 GET_SS_LEN(&F
->connect
->hostaddr
));
691 * If we get EISCONN, then we've already connect()ed the socket,
692 * which is a good thing.
696 if (errno
== EISCONN
) {
697 rb_connect_callback(F
, RB_OK
);
698 } else if (rb_ignore_errno(errno
)) {
699 /* Ignore error? Reschedule */
700 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
702 /* Error? Fail with RB_ERR_CONNECT */
703 rb_connect_callback(F
, RB_ERR_CONNECT
);
707 /* If we get here, we've succeeded, so call with RB_OK */
708 rb_connect_callback(F
, RB_OK
);
712 rb_connect_sctp(rb_fde_t
*F
, struct sockaddr_storage
*dest
, size_t dest_len
,
713 struct sockaddr_storage
*clocal
, size_t clocal_len
,
714 CNCB
*callback
, void *data
, int timeout
)
717 uint8_t packed_dest
[sizeof(struct sockaddr_storage
) * dest_len
];
718 uint8_t *p
= &packed_dest
[0];
725 lrb_assert(callback
);
726 F
->connect
= rb_malloc(sizeof(struct conndata
));
727 F
->connect
->callback
= callback
;
728 F
->connect
->data
= data
;
730 if ((F
->type
& RB_FD_SCTP
) == 0) {
731 rb_connect_callback(F
, RB_ERR_CONNECT
);
735 for (size_t i
= 0; i
< dest_len
; i
++) {
736 if (GET_SS_FAMILY(&dest
[i
]) == AF_INET6
) {
737 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in6
));
739 p
+= sizeof(struct sockaddr_in6
);
740 } else if (GET_SS_FAMILY(&dest
[i
]) == AF_INET
) {
741 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in
));
743 p
+= sizeof(struct sockaddr_in
);
748 memcpy(&F
->connect
->hostaddr
, &dest
[0], sizeof(F
->connect
->hostaddr
));
750 if ((clocal_len
> 0) && (rb_sctp_bindx_only(F
, clocal
, clocal_len
) < 0)) {
751 /* Failure, call the callback with RB_ERR_BIND */
752 rb_connect_callback(F
, RB_ERR_BIND
);
757 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
759 retval
= sctp_connectx(F
->fd
, (struct sockaddr
*)packed_dest
, dest_len
, NULL
);
763 * If we get EISCONN, then we've already connect()ed the socket,
764 * which is a good thing.
768 if (errno
== EISCONN
) {
769 rb_connect_callback(F
, RB_OK
);
770 } else if (rb_ignore_errno(errno
)) {
771 /* Ignore error? Reschedule */
772 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
774 /* Error? Fail with RB_ERR_CONNECT */
775 rb_connect_callback(F
, RB_ERR_CONNECT
);
779 /* If we get here, we've succeeded, so call with RB_OK */
780 rb_connect_callback(F
, RB_OK
);
782 rb_connect_callback(F
, RB_ERR_CONNECT
);
787 * rb_connect_callback() - call the callback, and continue with life
790 rb_connect_callback(rb_fde_t
*F
, int status
)
794 int errtmp
= errno
; /* save errno as rb_settimeout clobbers it sometimes */
796 /* This check is gross..but probably necessary */
797 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
799 /* Clear the connect flag + handler */
800 hdl
= F
->connect
->callback
;
801 data
= F
->connect
->data
;
802 F
->connect
->callback
= NULL
;
805 /* Clear the timeout handler */
806 rb_settimeout(F
, 0, NULL
, NULL
);
808 /* Call the handler */
809 hdl(F
, status
, data
);
814 * rb_connect_timeout() - this gets called when the socket connection
815 * times out. This *only* can be called once connect() is initially
819 rb_connect_timeout(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
822 rb_connect_callback(F
, RB_ERR_TIMEOUT
);
826 rb_connect_outcome(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
830 socklen_t len
= sizeof(err
);
832 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
834 retval
= getsockopt(F
->fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
837 } else if (err
!= 0) {
842 /* Error? Fail with RB_ERR_CONNECT */
843 rb_connect_callback(F
, RB_ERR_CONNECT
);
846 /* If we get here, we've succeeded, so call with RB_OK */
847 rb_connect_callback(F
, RB_OK
);
852 rb_connect_sockaddr(rb_fde_t
*F
, struct sockaddr
*addr
, int len
)
857 memcpy(addr
, &F
->connect
->hostaddr
, len
);
862 * rb_error_str() - return an error string for the given error condition
867 if(error
< 0 || error
>= RB_ERR_MAX
)
868 return "Invalid error number!";
869 return rb_err_str
[error
];
874 rb_socketpair(int family
, int sock_type
, int proto
, rb_fde_t
**F1
, rb_fde_t
**F2
, const char *note
)
876 rb_platform_fd_t nfd
[2];
877 if(number_fd
>= rb_maxconnections
)
883 #ifdef HAVE_SOCKETPAIR
884 if(socketpair(family
, sock_type
, proto
, nfd
))
886 if(sock_type
== SOCK_DGRAM
)
888 return rb_inet_socketpair_udp(F1
, F2
);
891 if(rb_inet_socketpair(AF_INET
, sock_type
, proto
, nfd
))
898 *F1
= rb_open(nfd
[0], RB_FD_SOCKET
, note
);
899 *F2
= rb_open(nfd
[1], RB_FD_SOCKET
, note
);
914 /* Set the socket non-blocking, and other wonderful bits */
915 if(rb_unlikely(!rb_set_nb(*F1
)))
917 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[0], strerror(errno
));
923 if(rb_unlikely(!rb_set_nb(*F2
)))
925 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[1], strerror(errno
));
936 rb_pipe(rb_fde_t
**F1
, rb_fde_t
**F2
, const char *desc
)
939 rb_platform_fd_t fd
[2];
940 if(number_fd
>= rb_maxconnections
)
949 *F1
= rb_open(fd
[0], RB_FD_PIPE
, desc
);
950 *F2
= rb_open(fd
[1], RB_FD_PIPE
, desc
);
952 if(rb_unlikely(!rb_set_nb(*F1
)))
954 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[0], strerror(errno
));
960 if(rb_unlikely(!rb_set_nb(*F2
)))
962 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[1], strerror(errno
));
971 /* Its not a pipe..but its selectable. I'll take dirty hacks
974 return rb_socketpair(AF_INET
, SOCK_STREAM
, 0, F1
, F2
, desc
);
979 * rb_socket() - open a socket
981 * This is a highly highly cut down version of squid's rb_open() which
982 * for the most part emulates socket(), *EXCEPT* it fails if we're about
983 * to run out of file descriptors.
986 rb_socket(int family
, int sock_type
, int proto
, const char *note
)
990 /* First, make sure we aren't going to run out of file descriptors */
991 if(rb_unlikely(number_fd
>= rb_maxconnections
))
998 * Next, we try to open the socket. We *should* drop the reserved FD
999 * limit if/when we get an error, but we can deal with that later.
1002 fd
= socket(family
, sock_type
, proto
);
1004 if(rb_unlikely(fd
< 0))
1005 return NULL
; /* errno will be passed through, yay.. */
1008 * Make sure we can take both IPv4 and IPv6 connections
1009 * on an AF_INET6 SCTP socket, otherwise keep them separate
1011 if(family
== AF_INET6
)
1014 int v6only
= (proto
== IPPROTO_SCTP
) ? 0 : 1;
1018 if(setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (void *) &v6only
, sizeof(v6only
)) == -1)
1020 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
1021 v6only
, fd
, strerror(errno
));
1027 F
= rb_open(fd
, RB_FD_SOCKET
, note
);
1030 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd
,
1037 if (proto
== IPPROTO_SCTP
) {
1038 F
->type
|= RB_FD_SCTP
;
1040 if (rb_setsockopt_sctp(F
)) {
1041 rb_lib_log("rb_socket: Could not set SCTP socket options on FD %d: %s",
1042 fd
, strerror(errno
));
1049 /* Set the socket non-blocking, and other wonderful bits */
1050 if(rb_unlikely(!rb_set_nb(F
)))
1052 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
, strerror(errno
));
1061 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
1062 * socket manged the sockaddr.
1065 mangle_mapped_sockaddr(struct sockaddr
*in
)
1067 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)in
;
1069 if(in
->sa_family
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&in6
->sin6_addr
))
1071 struct sockaddr_in in4
;
1072 memset(&in4
, 0, sizeof(struct sockaddr_in
));
1073 in4
.sin_family
= AF_INET
;
1074 in4
.sin_port
= in6
->sin6_port
;
1075 in4
.sin_addr
.s_addr
= ((uint32_t *)&in6
->sin6_addr
)[3];
1076 memcpy(in
, &in4
, sizeof(struct sockaddr_in
));
1081 * rb_listen() - listen on a port
1084 rb_listen(rb_fde_t
*F
, int backlog
, int defer_accept
)
1088 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| (F
->type
& RB_FD_INHERIT_TYPES
);
1089 result
= listen(F
->fd
, backlog
);
1091 #ifdef TCP_DEFER_ACCEPT
1092 if (defer_accept
&& !result
)
1094 (void)setsockopt(F
->fd
, IPPROTO_TCP
, TCP_DEFER_ACCEPT
, &backlog
, sizeof(int));
1097 #ifdef SO_ACCEPTFILTER
1098 if (defer_accept
&& !result
)
1100 struct accept_filter_arg afa
;
1102 memset(&afa
, '\0', sizeof afa
);
1103 rb_strlcpy(afa
.af_name
, "dataready", sizeof afa
.af_name
);
1104 (void)setsockopt(F
->fd
, SOL_SOCKET
, SO_ACCEPTFILTER
, &afa
,
1113 rb_fdlist_init(int closeall
, int maxfds
, size_t heapsize
)
1115 static int initialized
= 0;
1119 int vers
= MAKEWORD(2, 0);
1121 err
= WSAStartup(vers
, &wsaData
);
1124 rb_lib_die("WSAStartup failed");
1130 rb_maxconnections
= maxfds
;
1133 /* Since we're doing this once .. */
1136 fd_heap
= rb_bh_create(sizeof(rb_fde_t
), heapsize
, "librb_fd_heap");
1141 /* Called to open a given filedescriptor */
1143 rb_open(rb_platform_fd_t fd
, uint8_t type
, const char *desc
)
1146 lrb_assert(fd
>= 0);
1150 lrb_assert(!IsFDOpen(F
));
1151 if(rb_unlikely(IsFDOpen(F
)))
1154 if(F
!= NULL
&& F
->desc
!= NULL
)
1158 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd
, fdesc
);
1166 F
->desc
= rb_strndup(desc
, FD_DESC_SZ
);
1172 /* Called to close a given filedescriptor */
1174 rb_close(rb_fde_t
*F
)
1183 lrb_assert(IsFDOpen(F
));
1185 lrb_assert(!(type
& RB_FD_FILE
));
1186 if(rb_unlikely(type
& RB_FD_FILE
))
1188 lrb_assert(F
->read_handler
== NULL
);
1189 lrb_assert(F
->write_handler
== NULL
);
1192 if (type
& RB_FD_LISTEN
) {
1196 rb_setselect(F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
1197 rb_settimeout(F
, 0, NULL
, NULL
);
1199 rb_free(F
->connect
);
1202 if(type
& RB_FD_SSL
)
1206 #endif /* HAVE_SSL */
1213 if(type
& RB_FD_LISTEN
)
1214 shutdown(fd
, SHUT_RDWR
);
1219 * rb_dump_fd() - dump the list of active filedescriptors
1222 rb_dump_fd(DUMPCB
* cb
, void *data
)
1224 static const char *empty
= "";
1226 rb_dlink_list
*bucket
;
1230 for(i
= 0; i
< RB_FD_HASH_SIZE
; i
++)
1232 bucket
= &rb_fd_table
[i
];
1234 if(rb_dlink_list_length(bucket
) <= 0)
1237 RB_DLINK_FOREACH(ptr
, bucket
->head
)
1240 if(F
== NULL
|| !IsFDOpen(F
))
1243 cb(F
->fd
, F
->desc
? F
->desc
: empty
, data
);
1249 * rb_note() - set the fd note
1251 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1255 rb_note(rb_fde_t
*F
, const char *string
)
1261 F
->desc
= rb_strndup(string
, FD_DESC_SZ
);
1265 rb_set_type(rb_fde_t
*F
, uint8_t type
)
1267 /* if the caller is calling this, lets assume they have a clue */
1273 rb_get_type(rb_fde_t
*F
)
1279 rb_fd_ssl(rb_fde_t
*F
)
1283 if(F
->type
& RB_FD_SSL
)
1289 rb_get_fd(rb_fde_t
*F
)
1297 rb_get_fde(rb_platform_fd_t fd
)
1299 return rb_find_fd(fd
);
1303 rb_read(rb_fde_t
*F
, void *buf
, int count
)
1309 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1310 * an SSL socket as a regular socket
1313 if(F
->type
& RB_FD_SSL
)
1315 return rb_ssl_read(F
, buf
, count
);
1318 if(F
->type
& RB_FD_SOCKET
)
1320 ret
= recv(F
->fd
, buf
, count
, 0);
1330 return read(F
->fd
, buf
, count
);
1335 rb_write(rb_fde_t
*F
, const void *buf
, int count
)
1342 if(F
->type
& RB_FD_SSL
)
1344 return rb_ssl_write(F
, buf
, count
);
1347 if(F
->type
& RB_FD_SOCKET
)
1349 ret
= send(F
->fd
, buf
, count
, MSG_NOSIGNAL
);
1357 return write(F
->fd
, buf
, count
);
1360 #if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1362 rb_fake_writev(rb_fde_t
*F
, const struct rb_iovec
*vp
, size_t vpcount
)
1366 while(vpcount
-- > 0)
1368 ssize_t written
= rb_write(F
, vp
->iov_base
, vp
->iov_len
);
1384 #if defined(WIN32) || !defined(HAVE_WRITEV)
1386 rb_writev(rb_fde_t
*F
, struct rb_iovec
* vecount
, int count
)
1388 return rb_fake_writev(F
, vecount
, count
);
1393 rb_writev(rb_fde_t
*F
, struct rb_iovec
* vector
, int count
)
1401 if(F
->type
& RB_FD_SSL
)
1403 return rb_fake_writev(F
, vector
, count
);
1405 #endif /* HAVE_SSL */
1407 if(F
->type
& RB_FD_SOCKET
)
1410 memset(&msg
, 0, sizeof(msg
));
1411 msg
.msg_iov
= (struct iovec
*)vector
;
1412 msg
.msg_iovlen
= count
;
1413 return sendmsg(F
->fd
, &msg
, MSG_NOSIGNAL
);
1415 #endif /* HAVE_SENDMSG */
1416 return writev(F
->fd
, (struct iovec
*)vector
, count
);
1423 * From: Thomas Helvey <tomh@inxpress.net>
1425 static const char *IpQuadTab
[] = {
1426 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1427 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1428 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1429 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1430 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1431 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1432 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1433 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1434 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1435 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1436 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1437 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1438 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1439 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1440 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1441 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1442 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1443 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1444 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1445 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1446 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1447 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1448 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1449 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1450 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1451 "250", "251", "252", "253", "254", "255"
1455 * inetntoa - in_addr to string
1456 * changed name to remove collision possibility and
1457 * so behaviour is guaranteed to take a pointer arg.
1459 * inet_ntoa -- returned the dotted notation of a given
1462 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1466 inetntoa(const char *in
)
1468 static char buf
[16];
1470 const unsigned char *a
= (const unsigned char *)in
;
1473 n
= IpQuadTab
[*a
++];
1477 n
= IpQuadTab
[*a
++];
1481 n
= IpQuadTab
[*a
++];
1493 * WARNING: Don't even consider trying to compile this on a system where
1494 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1497 static const char *inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
);
1498 static const char *inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
);
1501 * inet_ntop4(src, dst, size)
1502 * format an IPv4 address
1504 * `dst' (as a const)
1506 * (1) uses no statics
1507 * (2) takes a unsigned char* not an in_addr as input
1512 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
1516 return strcpy(dst
, inetntoa((const char *)src
));
1520 * inet_ntop6(src, dst, size)
1521 * convert IPv6 binary address into presentation (printable) format
1526 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
1529 * Note that int32_t and int16_t need only be "at least" large enough
1530 * to contain a value of the specified size. On some systems, like
1531 * Crays, there is no such thing as an integer variable with 16 bits.
1532 * Keep this in mind if you think this function should have been coded
1533 * to use pointer overlays. All the world's not a VAX.
1535 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
1541 unsigned int words
[IN6ADDRSZ
/ INT16SZ
];
1546 * Copy the input (bytewise) array into a wordwise array.
1547 * Find the longest run of 0x00's in src[] for :: shorthanding.
1549 memset(words
, '\0', sizeof words
);
1550 for(i
= 0; i
< IN6ADDRSZ
; i
+= 2)
1551 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
1556 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1561 cur
.base
= i
, cur
.len
= 1;
1569 if(best
.base
== -1 || cur
.len
> best
.len
)
1577 if(best
.base
== -1 || cur
.len
> best
.len
)
1580 if(best
.base
!= -1 && best
.len
< 2)
1584 * Format the result.
1587 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1589 /* Are we inside the best run of 0x00's? */
1590 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
1600 /* Are we following an initial run of 0x00s or any real hex? */
1603 /* Is this address an encapsulated IPv4? */
1604 if(i
== 6 && best
.base
== 0 &&
1605 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
1607 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
1612 tp
+= sprintf(tp
, "%x", words
[i
]);
1614 /* Was it a trailing run of 0x00's? */
1615 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
1620 * Check for overflow, copy, and we're done.
1623 if((unsigned int)(tp
- tmp
) > size
)
1627 return memcpy(dst
, tmp
, tp
- tmp
);
1631 rb_inet_pton_sock(const char *src
, struct sockaddr_storage
*dst
)
1633 memset(dst
, 0, sizeof(*dst
));
1634 if(rb_inet_pton(AF_INET
, src
, &((struct sockaddr_in
*)dst
)->sin_addr
))
1636 SET_SS_FAMILY(dst
, AF_INET
);
1637 SET_SS_PORT(dst
, 0);
1638 SET_SS_LEN(dst
, sizeof(struct sockaddr_in
));
1641 else if(rb_inet_pton(AF_INET6
, src
, &((struct sockaddr_in6
*)dst
)->sin6_addr
))
1643 SET_SS_FAMILY(dst
, AF_INET6
);
1644 SET_SS_PORT(dst
, 0);
1645 SET_SS_LEN(dst
, sizeof(struct sockaddr_in6
));
1652 rb_inet_ntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
1654 switch (src
->sa_family
)
1657 return (rb_inet_ntop(AF_INET
, &((struct sockaddr_in
*)src
)->sin_addr
, dst
, size
));
1659 return (rb_inet_ntop
1660 (AF_INET6
, &((struct sockaddr_in6
*)src
)->sin6_addr
, dst
, size
));
1667 * rb_inet_ntop(af, src, dst, size)
1668 * convert a network format address to presentation format.
1670 * pointer to presentation format address (`dst'), or NULL (see errno).
1675 rb_inet_ntop(int af
, const void *src
, char *dst
, unsigned int size
)
1680 return (inet_ntop4(src
, dst
, size
));
1682 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*)src
) ||
1683 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*)src
))
1685 ((const unsigned char *)&((const struct in6_addr
*)src
)->
1686 s6_addr
[12], dst
, size
));
1688 return (inet_ntop6(src
, dst
, size
));
1696 * WARNING: Don't even consider trying to compile this on a system where
1697 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1701 * rb_inet_pton(af, src, dst)
1702 * convert from presentation format (which usually means ASCII printable)
1703 * to network format (which is usually some kind of binary format).
1705 * 1 if the address was valid for the specified address family
1706 * 0 if the address wasn't valid (`dst' is untouched in this case)
1707 * -1 if some other error occurred (`dst' is untouched in this case, too)
1713 * inet_pton4(src, dst)
1714 * like inet_aton() but without all the hexadecimal and shorthand.
1716 * 1 if `src' is a valid dotted quad, else 0.
1718 * does not touch `dst' unless it's returning 1.
1723 inet_pton4(const char *src
, unsigned char *dst
)
1725 int saw_digit
, octets
, ch
;
1726 unsigned char tmp
[INADDRSZ
], *tp
;
1731 while((ch
= *src
++) != '\0')
1734 if(ch
>= '0' && ch
<= '9')
1736 unsigned int new = *tp
* 10 + (ch
- '0');
1748 else if(ch
== '.' && saw_digit
)
1760 memcpy(dst
, tmp
, INADDRSZ
);
1765 * inet_pton6(src, dst)
1766 * convert presentation level address to network order binary form.
1768 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1770 * (1) does not touch `dst' unless it's returning 1.
1771 * (2) :: in a full address is silently ignored.
1773 * inspired by Mark Andrews.
1779 inet_pton6(const char *src
, unsigned char *dst
)
1781 static const char xdigits
[] = "0123456789abcdef";
1782 unsigned char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
1787 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
1788 endp
= tp
+ IN6ADDRSZ
;
1790 /* Leading :: requires some special handling. */
1797 while((ch
= tolower((unsigned char)*src
++)) != '\0')
1801 pch
= strchr(xdigits
, ch
);
1805 val
|= (pch
- xdigits
);
1821 else if(*src
== '\0')
1825 if(tp
+ INT16SZ
> endp
)
1827 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1828 *tp
++ = (unsigned char)val
& 0xff;
1833 if(*src
!= '\0' && ch
== '.')
1835 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
1839 break; /* '\0' was seen by inet_pton4(). */
1848 if(tp
+ INT16SZ
> endp
)
1850 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1851 *tp
++ = (unsigned char)val
& 0xff;
1856 * Since some memmove()'s erroneously fail to handle
1857 * overlapping regions, we'll do the shift by hand.
1859 const int n
= tp
- colonp
;
1864 for(i
= 1; i
<= n
; i
++)
1866 endp
[-i
] = colonp
[n
- i
];
1873 memcpy(dst
, tmp
, IN6ADDRSZ
);
1878 rb_inet_pton(int af
, const char *src
, void *dst
)
1883 return (inet_pton4(src
, dst
));
1885 /* Somebody might have passed as an IPv4 address this is sick but it works */
1886 if(inet_pton4(src
, dst
))
1888 char tmp
[HOSTIPLEN
];
1889 sprintf(tmp
, "::ffff:%s", src
);
1890 return (inet_pton6(tmp
, dst
));
1893 return (inet_pton6(src
, dst
));
1901 #ifndef HAVE_SOCKETPAIR
1903 /* mostly based on perl's emulation of socketpair udp */
1905 rb_inet_socketpair_udp(rb_fde_t
**newF1
, rb_fde_t
**newF2
)
1907 struct sockaddr_in addr
[2];
1908 rb_socklen_t size
= sizeof(struct sockaddr_in
);
1910 rb_platform_fd_t fd
[2];
1912 unsigned short port
;
1913 struct timeval wait
= { 0, 100000 };
1916 struct sockaddr_in readfrom
;
1917 unsigned short buf
[2];
1920 memset(&addr
, 0, sizeof(addr
));
1922 for(i
= 0; i
< 2; i
++)
1924 F
[i
] = rb_socket(AF_INET
, SOCK_DGRAM
, 0, "udp socketpair");
1927 addr
[i
].sin_family
= AF_INET
;
1928 addr
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1929 addr
[i
].sin_port
= 0;
1930 if(bind(rb_get_fd(F
[i
]), (struct sockaddr
*)&addr
[i
], sizeof(struct sockaddr_in
)))
1932 fd
[i
] = rb_get_fd(F
[i
]);
1935 for(i
= 0; i
< 2; i
++)
1937 if(getsockname(fd
[i
], (struct sockaddr
*)&addr
[i
], &size
))
1939 if(size
!= sizeof(struct sockaddr_in
))
1941 if(connect(fd
[!i
], (struct sockaddr
*)&addr
[i
], sizeof(struct sockaddr_in
)) == -1)
1945 for(i
= 0; i
< 2; i
++)
1947 port
= addr
[i
].sin_port
;
1948 got
= rb_write(F
[i
], &port
, sizeof(port
));
1949 if(got
!= sizeof(port
))
1957 max
= fd
[1] > fd
[0] ? fd
[1] : fd
[0];
1959 FD_SET(fd
[0], &rset
);
1960 FD_SET(fd
[1], &rset
);
1961 got
= select(max
+ 1, &rset
, NULL
, NULL
, &wait
);
1962 if(got
!= 2 || !FD_ISSET(fd
[0], &rset
) || !FD_ISSET(fd
[1], &rset
))
1969 for(i
= 0; i
< 2; i
++)
1972 int flag
= MSG_DONTWAIT
1976 got
= recvfrom(rb_get_fd(F
[i
]), (char *)&buf
, sizeof(buf
), flag
,
1977 (struct sockaddr
*)&readfrom
, &size
);
1980 if(got
!= sizeof(port
)
1981 || size
!= sizeof(struct sockaddr_in
)
1982 || buf
[0] != (unsigned short)addr
[!i
].sin_port
1983 || readfrom
.sin_family
!= addr
[!i
].sin_family
1984 || readfrom
.sin_addr
.s_addr
!= addr
[!i
].sin_addr
.s_addr
1985 || readfrom
.sin_port
!= addr
[!i
].sin_port
)
1994 #ifndef ECONNABORTED
1995 #define ECONNABORTED WSAECONNABORTED
2001 errno
= ECONNABORTED
;
2003 if(errno
!= ECONNABORTED
)
2016 rb_inet_socketpair(int family
, int type
, int protocol
, rb_platform_fd_t fd
[2])
2021 struct sockaddr_in listen_addr
;
2022 struct sockaddr_in connect_addr
;
2025 if(protocol
|| family
!= AF_INET
)
2027 errno
= EAFNOSUPPORT
;
2036 listener
= socket(AF_INET
, type
, 0);
2039 memset(&listen_addr
, 0, sizeof(listen_addr
));
2040 listen_addr
.sin_family
= AF_INET
;
2041 listen_addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2042 listen_addr
.sin_port
= 0; /* kernel choses port. */
2043 if(bind(listener
, (struct sockaddr
*)&listen_addr
, sizeof(listen_addr
)) == -1)
2044 goto tidy_up_and_fail
;
2045 if(listen(listener
, 1) == -1)
2046 goto tidy_up_and_fail
;
2048 connector
= socket(AF_INET
, type
, 0);
2050 goto tidy_up_and_fail
;
2051 /* We want to find out the port number to connect to. */
2052 size
= sizeof(connect_addr
);
2053 if(getsockname(listener
, (struct sockaddr
*)&connect_addr
, &size
) == -1)
2054 goto tidy_up_and_fail
;
2055 if(size
!= sizeof(connect_addr
))
2056 goto abort_tidy_up_and_fail
;
2057 if(connect(connector
, (struct sockaddr
*)&connect_addr
, sizeof(connect_addr
)) == -1)
2058 goto tidy_up_and_fail
;
2060 size
= sizeof(listen_addr
);
2061 acceptor
= accept(listener
, (struct sockaddr
*)&listen_addr
, &size
);
2063 goto tidy_up_and_fail
;
2064 if(size
!= sizeof(listen_addr
))
2065 goto abort_tidy_up_and_fail
;
2067 /* Now check we are talking to ourself by matching port and host on the
2069 if(getsockname(connector
, (struct sockaddr
*)&connect_addr
, &size
) == -1)
2070 goto tidy_up_and_fail
;
2071 if(size
!= sizeof(connect_addr
)
2072 || listen_addr
.sin_family
!= connect_addr
.sin_family
2073 || listen_addr
.sin_addr
.s_addr
!= connect_addr
.sin_addr
.s_addr
2074 || listen_addr
.sin_port
!= connect_addr
.sin_port
)
2076 goto abort_tidy_up_and_fail
;
2082 abort_tidy_up_and_fail
:
2083 errno
= EINVAL
; /* I hope this is portable and appropriate. */
2087 int save_errno
= errno
;
2102 static void (*setselect_handler
) (rb_fde_t
*, unsigned int, PF
*, void *);
2103 static int (*select_handler
) (long);
2104 static int (*setup_fd_handler
) (rb_fde_t
*);
2105 static int (*io_sched_event
) (struct ev_entry
*, int);
2106 static void (*io_unsched_event
) (struct ev_entry
*);
2107 static int (*io_supports_event
) (void);
2108 static void (*io_init_event
) (void);
2109 static char iotype
[25];
2118 rb_unsupported_event(void)
2126 if(!rb_init_netio_kqueue())
2128 setselect_handler
= rb_setselect_kqueue
;
2129 select_handler
= rb_select_kqueue
;
2130 setup_fd_handler
= rb_setup_fd_kqueue
;
2131 io_sched_event
= rb_kqueue_sched_event
;
2132 io_unsched_event
= rb_kqueue_unsched_event
;
2133 io_init_event
= rb_kqueue_init_event
;
2134 io_supports_event
= rb_kqueue_supports_event
;
2135 rb_strlcpy(iotype
, "kqueue", sizeof(iotype
));
2144 if(!rb_init_netio_epoll())
2146 setselect_handler
= rb_setselect_epoll
;
2147 select_handler
= rb_select_epoll
;
2148 setup_fd_handler
= rb_setup_fd_epoll
;
2149 io_sched_event
= rb_epoll_sched_event
;
2150 io_unsched_event
= rb_epoll_unsched_event
;
2151 io_supports_event
= rb_epoll_supports_event
;
2152 io_init_event
= rb_epoll_init_event
;
2153 rb_strlcpy(iotype
, "epoll", sizeof(iotype
));
2162 if(!rb_init_netio_ports())
2164 setselect_handler
= rb_setselect_ports
;
2165 select_handler
= rb_select_ports
;
2166 setup_fd_handler
= rb_setup_fd_ports
;
2167 io_sched_event
= rb_ports_sched_event
;
2168 io_unsched_event
= rb_ports_unsched_event
;
2169 io_init_event
= rb_ports_init_event
;
2170 io_supports_event
= rb_ports_supports_event
;
2171 rb_strlcpy(iotype
, "ports", sizeof(iotype
));
2180 if(!rb_init_netio_devpoll())
2182 setselect_handler
= rb_setselect_devpoll
;
2183 select_handler
= rb_select_devpoll
;
2184 setup_fd_handler
= rb_setup_fd_devpoll
;
2185 io_sched_event
= NULL
;
2186 io_unsched_event
= NULL
;
2187 io_init_event
= NULL
;
2188 io_supports_event
= rb_unsupported_event
;
2189 rb_strlcpy(iotype
, "devpoll", sizeof(iotype
));
2198 if(!rb_init_netio_sigio())
2200 setselect_handler
= rb_setselect_sigio
;
2201 select_handler
= rb_select_sigio
;
2202 setup_fd_handler
= rb_setup_fd_sigio
;
2203 io_sched_event
= rb_sigio_sched_event
;
2204 io_unsched_event
= rb_sigio_unsched_event
;
2205 io_supports_event
= rb_sigio_supports_event
;
2206 io_init_event
= rb_sigio_init_event
;
2208 rb_strlcpy(iotype
, "sigio", sizeof(iotype
));
2217 if(!rb_init_netio_poll())
2219 setselect_handler
= rb_setselect_poll
;
2220 select_handler
= rb_select_poll
;
2221 setup_fd_handler
= rb_setup_fd_poll
;
2222 io_sched_event
= NULL
;
2223 io_unsched_event
= NULL
;
2224 io_init_event
= NULL
;
2225 io_supports_event
= rb_unsupported_event
;
2226 rb_strlcpy(iotype
, "poll", sizeof(iotype
));
2235 if(!rb_init_netio_win32())
2237 setselect_handler
= rb_setselect_win32
;
2238 select_handler
= rb_select_win32
;
2239 setup_fd_handler
= rb_setup_fd_win32
;
2240 io_sched_event
= NULL
;
2241 io_unsched_event
= NULL
;
2242 io_init_event
= NULL
;
2243 io_supports_event
= rb_unsupported_event
;
2244 rb_strlcpy(iotype
, "win32", sizeof(iotype
));
2253 if(!rb_init_netio_select())
2255 setselect_handler
= rb_setselect_select
;
2256 select_handler
= rb_select_select
;
2257 setup_fd_handler
= rb_setup_fd_select
;
2258 io_sched_event
= NULL
;
2259 io_unsched_event
= NULL
;
2260 io_init_event
= NULL
;
2261 io_supports_event
= rb_unsupported_event
;
2262 rb_strlcpy(iotype
, "select", sizeof(iotype
));
2270 rb_io_sched_event(struct ev_entry
*ev
, int when
)
2272 if(ev
== NULL
|| io_supports_event
== NULL
|| io_sched_event
== NULL
2273 || !io_supports_event())
2275 return io_sched_event(ev
, when
);
2279 rb_io_unsched_event(struct ev_entry
*ev
)
2281 if(ev
== NULL
|| io_supports_event
== NULL
|| io_unsched_event
== NULL
2282 || !io_supports_event())
2284 io_unsched_event(ev
);
2288 rb_io_supports_event(void)
2290 if(io_supports_event
== NULL
)
2292 return io_supports_event();
2296 rb_io_init_event(void)
2299 rb_event_io_register_all();
2305 char *ioenv
= getenv("LIBRB_USE_IOTYPE");
2306 rb_fd_table
= rb_malloc(RB_FD_HASH_SIZE
* sizeof(rb_dlink_list
));
2311 if(!strcmp("epoll", ioenv
))
2316 else if(!strcmp("kqueue", ioenv
))
2321 else if(!strcmp("ports", ioenv
))
2326 else if(!strcmp("poll", ioenv
))
2331 else if(!strcmp("devpoll", ioenv
))
2336 else if(!strcmp("sigio", ioenv
))
2341 else if(!strcmp("select", ioenv
))
2346 if(!strcmp("win32", ioenv
))
2371 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2377 rb_setselect(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
2379 setselect_handler(F
, type
, handler
, client_data
);
2383 rb_select(unsigned long timeout
)
2385 int ret
= select_handler(timeout
);
2391 rb_setup_fd(rb_fde_t
*F
)
2394 return setup_fd_handler(F
);
2399 rb_ignore_errno(int error
)
2406 #if defined EWOULDBLOCK
2409 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
2429 #if defined(HAVE_SENDMSG) && !defined(WIN32)
2431 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2434 struct cmsghdr
*cmsg
;
2435 struct iovec iov
[1];
2437 uint8_t stype
= RB_FD_UNKNOWN
;
2439 rb_platform_fd_t fd
, len
, x
, rfds
;
2441 int control_len
= CMSG_SPACE(sizeof(int) * nfds
);
2443 iov
[0].iov_base
= data
;
2444 iov
[0].iov_len
= datasize
;
2446 msg
.msg_name
= NULL
;
2447 msg
.msg_namelen
= 0;
2451 cmsg
= alloca(control_len
);
2452 msg
.msg_control
= cmsg
;
2453 msg
.msg_controllen
= control_len
;
2455 if((len
= recvmsg(rb_get_fd(F
), &msg
, 0)) <= 0)
2458 if(msg
.msg_controllen
> 0 && msg
.msg_control
!= NULL
2459 && (cmsg
= CMSG_FIRSTHDR(&msg
)) != NULL
)
2461 rfds
= ((unsigned char *)cmsg
+ cmsg
->cmsg_len
- CMSG_DATA(cmsg
)) / sizeof(int);
2463 for(x
= 0; x
< nfds
&& x
< rfds
; x
++)
2465 fd
= ((int *)CMSG_DATA(cmsg
))[x
];
2466 stype
= RB_FD_UNKNOWN
;
2467 desc
= "remote unknown";
2470 if(S_ISSOCK(st
.st_mode
))
2472 stype
= RB_FD_SOCKET
;
2473 desc
= "remote socket";
2475 else if(S_ISFIFO(st
.st_mode
))
2478 desc
= "remote pipe";
2480 else if(S_ISREG(st
.st_mode
))
2483 desc
= "remote file";
2486 xF
[x
] = rb_open(fd
, stype
, desc
);
2496 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
, pid_t pid
__attribute__((unused
)))
2499 struct cmsghdr
*cmsg
;
2500 struct iovec iov
[1];
2503 memset(&msg
, 0, sizeof(msg
));
2506 iov
[0].iov_base
= &empty
;
2511 iov
[0].iov_base
= data
;
2512 iov
[0].iov_len
= datasize
;
2516 msg
.msg_name
= NULL
;
2517 msg
.msg_namelen
= 0;
2519 msg
.msg_control
= NULL
;
2520 msg
.msg_controllen
= 0;
2524 size_t ucount
= (size_t)count
;
2525 int len
= CMSG_SPACE(sizeof(int) * count
);
2528 msg
.msg_control
= buf
;
2529 msg
.msg_controllen
= len
;
2530 cmsg
= CMSG_FIRSTHDR(&msg
);
2531 cmsg
->cmsg_level
= SOL_SOCKET
;
2532 cmsg
->cmsg_type
= SCM_RIGHTS
;
2533 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * count
);
2535 for(size_t i
= 0; i
< ucount
; i
++)
2537 ((int *)CMSG_DATA(cmsg
))[i
] = rb_get_fd(F
[i
]);
2539 msg
.msg_controllen
= cmsg
->cmsg_len
;
2540 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2542 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2544 #else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2547 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2554 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
, pid_t pid
)
2560 #endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2563 rb_ipv4_from_ipv6(const struct sockaddr_in6
*restrict ip6
, struct sockaddr_in
*restrict ip4
)
2567 if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x02", 2))
2569 /* 6to4 and similar */
2570 memcpy(&ip4
->sin_addr
, ip6
->sin6_addr
.s6_addr
+ 2, 4);
2572 else if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x01\x00\x00", 4))
2575 for (i
= 0; i
< 4; i
++)
2576 ((uint8_t *)&ip4
->sin_addr
)[i
] = 0xFF ^
2577 ip6
->sin6_addr
.s6_addr
[12 + i
];
2581 SET_SS_LEN(ip4
, sizeof(struct sockaddr_in
));
2582 ip4
->sin_family
= AF_INET
;