]> jfr.im git - solanum.git/blame - librb/src/commio.c
librb/helper: call rb_clear_cloexec on child fds
[solanum.git] / librb / src / commio.c
CommitLineData
db137867
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * commio.c: Network/file related functions
4 *
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
8 *
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.
13 *
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.
18 *
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
22 * USA
23 *
db137867 24 */
c056dba2 25
fe037171
EM
26#include <librb_config.h>
27#include <rb_lib.h>
db137867
AC
28#include <commio-int.h>
29#include <commio-ssl.h>
30#include <event-int.h>
31#ifdef HAVE_SYS_UIO_H
32#include <sys/uio.h>
33#endif
34#define HAVE_SSL 1
35
36#ifndef MSG_NOSIGNAL
37#define MSG_NOSIGNAL 0
38#endif
39
40
41struct timeout_data
42{
43 rb_fde_t *F;
44 rb_dlink_node node;
45 time_t timeout;
46 PF *timeout_handler;
47 void *timeout_data;
48};
49
50rb_dlink_list *rb_fd_table;
51static rb_bh *fd_heap;
52
53static rb_dlink_list timeout_list;
54static rb_dlink_list closed_list;
55
56static struct ev_entry *rb_timeout_ev;
57
58
59static const char *rb_err_str[] = { "Comm OK", "Error during bind()",
60 "Error during DNS lookup", "connect timeout",
61 "Error during connect()",
3cbcc111
JT
62 "Comm Error",
63 "Error with SSL"
db137867
AC
64};
65
66/* Highest FD and number of open FDs .. */
67static int number_fd = 0;
3202e249 68int rb_maxconnections = 0;
db137867
AC
69
70static PF rb_connect_timeout;
589dbf4d 71static PF rb_connect_outcome;
db137867 72static void mangle_mapped_sockaddr(struct sockaddr *in);
db137867
AC
73
74#ifndef HAVE_SOCKETPAIR
339150ec 75static int rb_inet_socketpair(int d, int type, int protocol, rb_platform_fd_t sv[2]);
3202e249 76static int rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2);
db137867
AC
77#endif
78
79static inline rb_fde_t *
dc7e6b42 80add_fd(rb_platform_fd_t fd)
db137867
AC
81{
82 rb_fde_t *F = rb_find_fd(fd);
db137867
AC
83
84 /* look up to see if we have it already */
85 if(F != NULL)
3202e249
VY
86 return F;
87
db137867
AC
88 F = rb_bh_alloc(fd_heap);
89 F->fd = fd;
a9fb3ed0 90 rb_dlinkAdd(F, &F->node, &rb_fd_table[rb_hash_fd(fd)]);
3202e249 91 return (F);
db137867
AC
92}
93
94static inline void
95remove_fd(rb_fde_t *F)
96{
db137867
AC
97 if(F == NULL || !IsFDOpen(F))
98 return;
3202e249 99
a9fb3ed0 100 rb_dlinkMoveNode(&F->node, &rb_fd_table[rb_hash_fd(F->fd)], &closed_list);
db137867
AC
101}
102
3202e249 103static void
db137867
AC
104free_fds(void)
105{
106 rb_fde_t *F;
107 rb_dlink_node *ptr, *next;
108 RB_DLINK_FOREACH_SAFE(ptr, next, closed_list.head)
109 {
110 F = ptr->data;
ff0414c8
SA
111
112 number_fd--;
113
114#ifdef _WIN32
115 if(F->type & (RB_FD_SOCKET | RB_FD_PIPE))
116 closesocket(F->fd);
117 else
118#endif
119 close(F->fd);
120
db137867
AC
121 rb_dlinkDelete(ptr, &closed_list);
122 rb_bh_free(fd_heap, F);
123 }
124}
125
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)
129 */
130
131#if defined (__SVR4) && defined (__sun)
132static void
133rb_fd_hack(int *fd)
134{
135 int newfd;
136 if(*fd > 256 || *fd < 0)
137 return;
138 if((newfd = fcntl(*fd, F_DUPFD, 256)) != -1)
139 {
140 close(*fd);
141 *fd = newfd;
142 }
143 return;
144}
145#else
146#define rb_fd_hack(fd)
147#endif
148
149
150/* close_all_connections() can be used *before* the system come up! */
151
152static void
153rb_close_all(void)
154{
3202e249 155#ifndef _WIN32
db137867 156 int i;
db137867
AC
157
158 /* XXX someone tell me why we care about 4 fd's ? */
159 /* XXX btw, fd 3 is used for profiler ! */
3202e249 160 for(i = 3; i < rb_maxconnections; ++i)
db137867
AC
161 {
162 close(i);
163 }
db137867
AC
164#endif
165}
166
167/*
168 * get_sockerr - get the error value from the socket or the current errno
169 *
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
172 * gamble anyway.
173 */
174int
175rb_get_sockerr(rb_fde_t *F)
176{
177 int errtmp;
178 int err = 0;
179 rb_socklen_t len = sizeof(err);
180
181 if(!(F->type & RB_FD_SOCKET))
182 return errno;
183
184 rb_get_errno();
185 errtmp = errno;
186
187#ifdef SO_ERROR
3202e249
VY
188 if(F != NULL
189 && !getsockopt(rb_get_fd(F), SOL_SOCKET, SO_ERROR, (char *)&err, (rb_socklen_t *) & len))
db137867
AC
190 {
191 if(err)
192 errtmp = err;
193 }
194 errno = errtmp;
195#endif
196 return errtmp;
197}
198
199/*
200 * rb_getmaxconnect - return the max number of connections allowed
201 */
202int
203rb_getmaxconnect(void)
204{
3202e249 205 return (rb_maxconnections);
db137867
AC
206}
207
208/*
209 * set_sock_buffers - set send and receive buffers for socket
55abcbb2 210 *
db137867
AC
211 * inputs - fd file descriptor
212 * - size to set
213 * output - returns true (1) if successful, false (0) otherwise
214 * side effects -
215 */
216int
217rb_set_buffers(rb_fde_t *F, int size)
218{
219 if(F == NULL)
220 return 0;
221 if(setsockopt
3202e249
VY
222 (F->fd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
223 || setsockopt(F->fd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
db137867
AC
224 return 0;
225 return 1;
226}
227
228/*
55abcbb2 229 * set_non_blocking - Set the client connection into non-blocking mode.
db137867
AC
230 *
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
234 * be done with it.
235 */
236int
237rb_set_nb(rb_fde_t *F)
238{
239 int nonb = 0;
240 int res;
dc7e6b42 241 rb_platform_fd_t fd;
db137867
AC
242 if(F == NULL)
243 return 0;
244 fd = F->fd;
3202e249 245
db137867
AC
246 if((res = rb_setup_fd(F)))
247 return res;
248#ifdef O_NONBLOCK
249 nonb |= O_NONBLOCK;
250 res = fcntl(fd, F_GETFL, 0);
251 if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
252 return 0;
253#else
254 nonb = 1;
255 res = 0;
256 if(ioctl(fd, FIONBIO, (char *)&nonb) == -1)
257 return 0;
258#endif
259
260 return 1;
261}
262
34a2afbc
DF
263int
264rb_set_cloexec(rb_fde_t *F)
265{
266#ifdef _WIN32
267 SetHandleInformation((HANDLE) F->fd, HANDLE_FLAG_INHERIT, 0);
268#else
269 int res;
270 rb_platform_fd_t fd;
271 if(F == NULL)
272 return 0;
273 fd = F->fd;
274
275 res = fcntl(fd, F_GETFD, NULL);
276 if(res == -1)
277 return 0;
278 if(fcntl(fd, F_SETFD, res | FD_CLOEXEC) == -1)
279 return 0;
280
281 return 1;
282#endif
283}
284
285int
286rb_clear_cloexec(rb_fde_t *F)
287{
288#ifdef _WIN32
289 SetHandleInformation((HANDLE) F->fd, HANDLE_FLAG_INHERIT, 1);
290#else
291 int res;
292 rb_platform_fd_t fd;
293 if(F == NULL)
294 return 0;
295 fd = F->fd;
296
297 res = fcntl(fd, F_GETFD, NULL);
298 if(res == -1)
299 return 0;
300 if(fcntl(fd, F_SETFD, res & ~FD_CLOEXEC) == -1)
301 return 0;
302
303 return 1;
304#endif
305}
306
db137867
AC
307/*
308 * rb_settimeout() - set the socket timeout
309 *
310 * Set the timeout for the fd
311 */
312void
313rb_settimeout(rb_fde_t *F, time_t timeout, PF * callback, void *cbdata)
314{
315 struct timeout_data *td;
316
317 if(F == NULL)
318 return;
319
320 lrb_assert(IsFDOpen(F));
321 td = F->timeout;
3202e249 322 if(callback == NULL) /* user wants to remove */
db137867
AC
323 {
324 if(td == NULL)
325 return;
326 rb_dlinkDelete(&td->node, &timeout_list);
327 rb_free(td);
328 F->timeout = NULL;
3202e249 329 if(rb_dlink_list_length(&timeout_list) == 0)
db137867
AC
330 {
331 rb_event_delete(rb_timeout_ev);
332 rb_timeout_ev = NULL;
333 }
334 return;
335 }
336
337 if(F->timeout == NULL)
3202e249
VY
338 td = F->timeout = rb_malloc(sizeof(struct timeout_data));
339
db137867
AC
340 td->F = F;
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)
346 {
3202e249 347 rb_timeout_ev = rb_event_add("rb_checktimeouts", rb_checktimeouts, NULL, 5);
db137867
AC
348 }
349}
350
351/*
352 * rb_checktimeouts() - check the socket timeouts
353 *
354 * All this routine does is call the given callback/cbdata, without closing
355 * down the file descriptor. When close handlers have been implemented,
356 * this will happen.
357 */
358void
8679c0fe 359rb_checktimeouts(void *notused __attribute__((unused)))
db137867
AC
360{
361 rb_dlink_node *ptr, *next;
362 struct timeout_data *td;
363 rb_fde_t *F;
364 PF *hdl;
365 void *data;
366
367 RB_DLINK_FOREACH_SAFE(ptr, next, timeout_list.head)
368 {
369 td = ptr->data;
370 F = td->F;
371 if(F == NULL || !IsFDOpen(F))
372 continue;
373
374 if(td->timeout < rb_current_time())
375 {
376 hdl = td->timeout_handler;
377 data = td->timeout_data;
378 rb_dlinkDelete(&td->node, &timeout_list);
379 F->timeout = NULL;
380 rb_free(td);
381 hdl(F, data);
3202e249 382 }
db137867
AC
383 }
384}
385
c6ad9b0c
SA
386static int
387rb_setsockopt_reuseaddr(rb_fde_t *F)
388{
389 int opt_one = 1;
390 int ret;
391
392 ret = setsockopt(F->fd, SOL_SOCKET, SO_REUSEADDR, &opt_one, sizeof(opt_one));
393 if (ret) {
394 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
395 F->fd, strerror(rb_get_sockerr(F)));
396 return ret;
397 }
398
399 return 0;
400}
401
402#ifdef HAVE_LIBSCTP
403static int
404rb_setsockopt_sctp(rb_fde_t *F)
405{
406 int opt_zero = 0;
407 int opt_one = 1;
268044ea
SA
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;
c6ad9b0c
SA
411 int ret;
412 struct sctp_initmsg initmsg;
413 struct sctp_rtoinfo rtoinfo;
414 struct sctp_paddrparams paddrparams;
415 struct sctp_assocparams assocparams;
416
417 ret = setsockopt(F->fd, SOL_SCTP, SCTP_NODELAY, &opt_one, sizeof(opt_one));
418 if (ret) {
419 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
420 F->fd, strerror(rb_get_sockerr(F)));
421 return ret;
422 }
423
268044ea 424 ret = setsockopt(F->fd, SOL_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &opt_mapped, sizeof(opt_mapped));
c6ad9b0c
SA
425 if (ret) {
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)));
428 return ret;
429 }
430
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;
435
436 ret = setsockopt(F->fd, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
437 if (ret) {
438 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
439 F->fd, strerror(rb_get_sockerr(F)));
440 return ret;
441 }
442
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;
448
449 ret = setsockopt(F->fd, SOL_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo));
450 if (ret) {
451 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
452 F->fd, strerror(rb_get_sockerr(F)));
453 return ret;
454 }
455
456 /*
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.
460 *
461 * Each peer address will timeout reachability in about 750s.
462 */
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;
469
470 ret = setsockopt(F->fd, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams));
471 if (ret) {
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)));
474 return ret;
475 }
476
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;
481
482 ret = setsockopt(F->fd, SOL_SCTP, SCTP_ASSOCINFO, &assocparams, sizeof(assocparams));
483 if (ret) {
484 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
485 F->fd, strerror(rb_get_sockerr(F)));
486 return ret;
487 }
488
489 return 0;
490}
491#endif
492
493int
494rb_bind(rb_fde_t *F, struct sockaddr *addr)
495{
496 int ret;
497
498 ret = rb_setsockopt_reuseaddr(F);
499 if (ret)
500 return ret;
501
502 ret = bind(F->fd, addr, GET_SS_LEN(addr));
503 if (ret)
504 return ret;
505
506 return 0;
507}
508
6003ce76
SA
509#ifdef HAVE_LIBSCTP
510static int
511rb_sctp_bindx_only(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
512{
513 int ret;
514
515 for (size_t i = 0; i < len; i++) {
516 if (GET_SS_FAMILY(&addrs[i]) == AF_UNSPEC)
517 continue;
518
519 ret = sctp_bindx(F->fd, (struct sockaddr *)&addrs[i], 1, SCTP_BINDX_ADD_ADDR);
520 if (ret)
521 return ret;
522 }
523
524 return 0;
525}
526#endif
527
c6ad9b0c
SA
528int
529rb_sctp_bindx(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
530{
531#ifdef HAVE_LIBSCTP
532 int ret;
533
534 if ((F->type & RB_FD_SCTP) == 0)
535 return -1;
536
537 ret = rb_setsockopt_reuseaddr(F);
538 if (ret)
539 return ret;
540
6003ce76
SA
541 ret = rb_sctp_bindx_only(F, addrs, len);
542 if (ret)
543 return ret;
c6ad9b0c
SA
544
545 return 0;
546#else
547 return -1;
548#endif
549}
550
551int
552rb_inet_get_proto(rb_fde_t *F)
db137867 553{
c6ad9b0c
SA
554#ifdef HAVE_LIBSCTP
555 if (F->type & RB_FD_SCTP)
556 return IPPROTO_SCTP;
557#endif
558 return IPPROTO_TCP;
559}
560
8679c0fe 561static void rb_accept_tryaccept(rb_fde_t *F, void *data __attribute__((unused))) {
db137867
AC
562 struct rb_sockaddr_storage st;
563 rb_fde_t *new_F;
b0adc7bf 564 rb_socklen_t addrlen;
db137867
AC
565 int new_fd;
566
567 while(1)
568 {
b0adc7bf
SA
569 memset(&st, 0, sizeof(st));
570 addrlen = sizeof(st);
571
db137867
AC
572 new_fd = accept(F->fd, (struct sockaddr *)&st, &addrlen);
573 rb_get_errno();
574 if(new_fd < 0)
575 {
576 rb_setselect(F, RB_SELECT_ACCEPT, rb_accept_tryaccept, NULL);
577 return;
578 }
579
580 rb_fd_hack(&new_fd);
581
c6ad9b0c 582 new_F = rb_open(new_fd, RB_FD_SOCKET | (F->type & RB_FD_INHERIT_TYPES), "Incoming Connection");
db137867 583
a9fb3ed0
VY
584 if(new_F == NULL)
585 {
3202e249 586 rb_lib_log
c6ad9b0c 587 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
3202e249 588 new_fd);
a9fb3ed0
VY
589 close(new_fd);
590 continue;
591 }
592
c2ac22cc 593 if(rb_unlikely(!rb_set_nb(new_F)))
db137867
AC
594 {
595 rb_get_errno();
596 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F->fd);
597 rb_close(new_F);
598 }
599
db137867 600 mangle_mapped_sockaddr((struct sockaddr *)&st);
3202e249 601
db137867
AC
602 if(F->accept->precb != NULL)
603 {
3202e249 604 if(!F->accept->precb(new_F, (struct sockaddr *)&st, addrlen, F->accept->data)) /* pre-callback decided to drop it */
db137867
AC
605 continue;
606 }
607#ifdef HAVE_SSL
608 if(F->type & RB_FD_SSL)
609 {
a9fb3ed0 610 rb_ssl_accept_setup(F, new_F, (struct sockaddr *)&st, addrlen);
3202e249 611 }
db137867 612 else
3202e249 613#endif /* HAVE_SSL */
db137867 614 {
3202e249
VY
615 F->accept->callback(new_F, RB_OK, (struct sockaddr *)&st, addrlen,
616 F->accept->data);
db137867
AC
617 }
618 }
619
620}
621
622/* try to accept a TCP connection */
623void
3202e249 624rb_accept_tcp(rb_fde_t *F, ACPRE * precb, ACCB * callback, void *data)
db137867
AC
625{
626 if(F == NULL)
627 return;
628 lrb_assert(callback);
629
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);
635}
636
637/*
dc7e6b42 638 * void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
5ad62c80 639 * struct sockaddr *clocal,
db137867
AC
640 * CNCB *callback, void *data, int timeout)
641 * Input: An fd to connect with, a host and port to connect to,
5ad62c80 642 * a local sockaddr to connect from (or NULL to use the
db137867
AC
643 * default), a callback, the data to pass into the callback, the
644 * address family.
645 * Output: None.
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.
649 */
650void
651rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
5ad62c80 652 struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
db137867 653{
589dbf4d
SA
654 int retval;
655
656 if (F == NULL)
db137867 657 return;
3202e249 658
db137867
AC
659 lrb_assert(callback);
660 F->connect = rb_malloc(sizeof(struct conndata));
661 F->connect->callback = callback;
662 F->connect->data = data;
663
664 memcpy(&F->connect->hostaddr, dest, sizeof(F->connect->hostaddr));
665
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.
671 * -- adrian
672 */
5ad62c80 673 if((clocal != NULL) && (bind(F->fd, clocal, GET_SS_LEN(clocal)) < 0))
db137867
AC
674 {
675 /* Failure, call the callback with RB_ERR_BIND */
676 rb_connect_callback(F, RB_ERR_BIND);
677 /* ... and quit */
678 return;
679 }
680
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);
db137867 684
589dbf4d
SA
685 retval = connect(F->fd,
686 (struct sockaddr *)&F->connect->hostaddr,
687 GET_SS_LEN(&F->connect->hostaddr));
688 /* Error? */
689 if (retval < 0) {
690 /*
691 * If we get EISCONN, then we've already connect()ed the socket,
692 * which is a good thing.
693 * -- adrian
694 */
695 rb_get_errno();
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);
701 } else {
702 /* Error? Fail with RB_ERR_CONNECT */
703 rb_connect_callback(F, RB_ERR_CONNECT);
704 }
705 return;
706 }
707 /* If we get here, we've succeeded, so call with RB_OK */
708 rb_connect_callback(F, RB_OK);
709}
db137867 710
6003ce76
SA
711void
712rb_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)
715{
716#ifdef HAVE_LIBSCTP
717 uint8_t packed_dest[sizeof(struct sockaddr_storage) * dest_len];
718 uint8_t *p = &packed_dest[0];
719 size_t n = 0;
720 int retval;
721
722 if (F == NULL)
723 return;
724
725 lrb_assert(callback);
726 F->connect = rb_malloc(sizeof(struct conndata));
727 F->connect->callback = callback;
728 F->connect->data = data;
729
730 if ((F->type & RB_FD_SCTP) == 0) {
731 rb_connect_callback(F, RB_ERR_CONNECT);
732 return;
733 }
734
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));
738 n++;
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));
742 n++;
743 p += sizeof(struct sockaddr_in);
744 }
745 }
746 dest_len = n;
747
748 memcpy(&F->connect->hostaddr, &dest[0], sizeof(F->connect->hostaddr));
749
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);
753 /* ... and quit */
754 return;
755 }
756
757 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
758
759 retval = sctp_connectx(F->fd, (struct sockaddr *)packed_dest, dest_len, NULL);
760 /* Error? */
761 if (retval < 0) {
762 /*
763 * If we get EISCONN, then we've already connect()ed the socket,
764 * which is a good thing.
765 * -- adrian
766 */
767 rb_get_errno();
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);
773 } else {
774 /* Error? Fail with RB_ERR_CONNECT */
775 rb_connect_callback(F, RB_ERR_CONNECT);
776 }
777 return;
778 }
779 /* If we get here, we've succeeded, so call with RB_OK */
780 rb_connect_callback(F, RB_OK);
781#else
782 rb_connect_callback(F, RB_ERR_CONNECT);
783#endif
784}
785
db137867
AC
786/*
787 * rb_connect_callback() - call the callback, and continue with life
788 */
789void
790rb_connect_callback(rb_fde_t *F, int status)
791{
792 CNCB *hdl;
793 void *data;
3202e249 794 int errtmp = errno; /* save errno as rb_settimeout clobbers it sometimes */
db137867
AC
795
796 /* This check is gross..but probably necessary */
797 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
798 return;
799 /* Clear the connect flag + handler */
800 hdl = F->connect->callback;
801 data = F->connect->data;
802 F->connect->callback = NULL;
803
aec4c3cb 804
db137867
AC
805 /* Clear the timeout handler */
806 rb_settimeout(F, 0, NULL, NULL);
3202e249 807 errno = errtmp;
db137867
AC
808 /* Call the handler */
809 hdl(F, status, data);
810}
811
812
813/*
814 * rb_connect_timeout() - this gets called when the socket connection
815 * times out. This *only* can be called once connect() is initially
816 * called ..
817 */
818static void
8679c0fe 819rb_connect_timeout(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
820{
821 /* error! */
822 rb_connect_callback(F, RB_ERR_TIMEOUT);
823}
824
db137867 825static void
8679c0fe 826rb_connect_outcome(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
827{
828 int retval;
589dbf4d
SA
829 int err = 0;
830 socklen_t len = sizeof(err);
db137867
AC
831
832 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
833 return;
589dbf4d
SA
834 retval = getsockopt(F->fd, SOL_SOCKET, SO_ERROR, &err, &len);
835 if (retval < 0) {
db137867 836 rb_get_errno();
589dbf4d
SA
837 } else if (err != 0) {
838 errno = err;
839 retval = -1;
840 }
841 if (retval < 0) {
842 /* Error? Fail with RB_ERR_CONNECT */
843 rb_connect_callback(F, RB_ERR_CONNECT);
db137867
AC
844 return;
845 }
589dbf4d 846 /* If we get here, we've succeeded, so call with RB_OK */
db137867
AC
847 rb_connect_callback(F, RB_OK);
848}
849
850
851int
852rb_connect_sockaddr(rb_fde_t *F, struct sockaddr *addr, int len)
853{
854 if(F == NULL)
855 return 0;
856
857 memcpy(addr, &F->connect->hostaddr, len);
858 return 1;
859}
860
861/*
862 * rb_error_str() - return an error string for the given error condition
863 */
864const char *
865rb_errstr(int error)
866{
867 if(error < 0 || error >= RB_ERR_MAX)
868 return "Invalid error number!";
869 return rb_err_str[error];
870}
871
872
873int
874rb_socketpair(int family, int sock_type, int proto, rb_fde_t **F1, rb_fde_t **F2, const char *note)
875{
e49147e5 876 rb_platform_fd_t nfd[2];
db137867
AC
877 if(number_fd >= rb_maxconnections)
878 {
879 errno = ENFILE;
880 return -1;
881 }
882
3202e249 883#ifdef HAVE_SOCKETPAIR
db137867
AC
884 if(socketpair(family, sock_type, proto, nfd))
885#else
3202e249
VY
886 if(sock_type == SOCK_DGRAM)
887 {
888 return rb_inet_socketpair_udp(F1, F2);
889 }
890
891 if(rb_inet_socketpair(AF_INET, sock_type, proto, nfd))
db137867
AC
892#endif
893 return -1;
894
895 rb_fd_hack(&nfd[0]);
896 rb_fd_hack(&nfd[1]);
897
898 *F1 = rb_open(nfd[0], RB_FD_SOCKET, note);
899 *F2 = rb_open(nfd[1], RB_FD_SOCKET, note);
900
901 if(*F1 == NULL)
902 {
903 if(*F2 != NULL)
904 rb_close(*F2);
905 return -1;
906 }
907
908 if(*F2 == NULL)
909 {
910 rb_close(*F1);
911 return -1;
912 }
913
914 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 915 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
916 {
917 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[0], strerror(errno));
918 rb_close(*F1);
919 rb_close(*F2);
920 return -1;
921 }
922
c2ac22cc 923 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
924 {
925 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[1], strerror(errno));
926 rb_close(*F1);
927 rb_close(*F2);
928 return -1;
929 }
930
931 return 0;
932}
933
934
935int
936rb_pipe(rb_fde_t **F1, rb_fde_t **F2, const char *desc)
937{
3202e249 938#ifndef _WIN32
dc7e6b42 939 rb_platform_fd_t fd[2];
db137867
AC
940 if(number_fd >= rb_maxconnections)
941 {
942 errno = ENFILE;
943 return -1;
944 }
945 if(pipe(fd) == -1)
946 return -1;
947 rb_fd_hack(&fd[0]);
948 rb_fd_hack(&fd[1]);
949 *F1 = rb_open(fd[0], RB_FD_PIPE, desc);
950 *F2 = rb_open(fd[1], RB_FD_PIPE, desc);
951
c2ac22cc 952 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
953 {
954 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[0], strerror(errno));
955 rb_close(*F1);
956 rb_close(*F2);
957 return -1;
958 }
959
c2ac22cc 960 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
961 {
962 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[1], strerror(errno));
963 rb_close(*F1);
964 rb_close(*F2);
965 return -1;
966 }
967
968
969 return 0;
970#else
971 /* Its not a pipe..but its selectable. I'll take dirty hacks
972 * for $500 Alex.
973 */
3202e249 974 return rb_socketpair(AF_INET, SOCK_STREAM, 0, F1, F2, desc);
db137867
AC
975#endif
976}
977
978/*
979 * rb_socket() - open a socket
980 *
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.
984 */
985rb_fde_t *
986rb_socket(int family, int sock_type, int proto, const char *note)
987{
988 rb_fde_t *F;
dc7e6b42 989 rb_platform_fd_t fd;
db137867 990 /* First, make sure we aren't going to run out of file descriptors */
c2ac22cc 991 if(rb_unlikely(number_fd >= rb_maxconnections))
db137867
AC
992 {
993 errno = ENFILE;
994 return NULL;
995 }
996
997 /*
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.
1000 * XXX !!! -- adrian
1001 */
1002 fd = socket(family, sock_type, proto);
1003 rb_fd_hack(&fd);
c2ac22cc 1004 if(rb_unlikely(fd < 0))
db137867
AC
1005 return NULL; /* errno will be passed through, yay.. */
1006
55abcbb2 1007 /*
db137867 1008 * Make sure we can take both IPv4 and IPv6 connections
c6ad9b0c 1009 * on an AF_INET6 SCTP socket, otherwise keep them separate
db137867
AC
1010 */
1011 if(family == AF_INET6)
1012 {
c6ad9b0c
SA
1013#ifdef HAVE_LIBSCTP
1014 int v6only = (proto == IPPROTO_SCTP) ? 0 : 1;
1015#else
1016 int v6only = 1;
1017#endif
1018 if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)) == -1)
db137867 1019 {
c6ad9b0c
SA
1020 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
1021 v6only, fd, strerror(errno));
db137867
AC
1022 close(fd);
1023 return NULL;
1024 }
1025 }
db137867
AC
1026
1027 F = rb_open(fd, RB_FD_SOCKET, note);
1028 if(F == NULL)
a9fb3ed0 1029 {
3202e249
VY
1030 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd,
1031 strerror(errno));
a9fb3ed0 1032 close(fd);
db137867 1033 return NULL;
a9fb3ed0 1034 }
c6ad9b0c
SA
1035
1036#ifdef HAVE_LIBSCTP
1037 if (proto == IPPROTO_SCTP) {
1038 F->type |= RB_FD_SCTP;
1039
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));
1043 close(fd);
1044 return NULL;
1045 }
1046 }
1047#endif
1048
db137867 1049 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 1050 if(rb_unlikely(!rb_set_nb(F)))
db137867
AC
1051 {
1052 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
1053 rb_close(F);
1054 return NULL;
1055 }
1056
1057 return F;
1058}
1059
1060/*
1061 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
1062 * socket manged the sockaddr.
1063 */
db137867
AC
1064static void
1065mangle_mapped_sockaddr(struct sockaddr *in)
1066{
3202e249 1067 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
db137867 1068
db137867
AC
1069 if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
1070 {
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;
3202e249 1075 in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
db137867
AC
1076 memcpy(in, &in4, sizeof(struct sockaddr_in));
1077 }
db137867 1078}
db137867
AC
1079
1080/*
1081 * rb_listen() - listen on a port
1082 */
1083int
aa4737a0 1084rb_listen(rb_fde_t *F, int backlog, int defer_accept)
db137867 1085{
77cb59b3
AC
1086 int result;
1087
c6ad9b0c 1088 F->type = RB_FD_SOCKET | RB_FD_LISTEN | (F->type & RB_FD_INHERIT_TYPES);
77cb59b3
AC
1089 result = listen(F->fd, backlog);
1090
1091#ifdef TCP_DEFER_ACCEPT
aa4737a0 1092 if (defer_accept && !result)
77cb59b3 1093 {
e053adc8 1094 (void)setsockopt(F->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(int));
77cb59b3
AC
1095 }
1096#endif
797a29f3
JT
1097#ifdef SO_ACCEPTFILTER
1098 if (defer_accept && !result)
1099 {
1100 struct accept_filter_arg afa;
1101
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,
1105 sizeof afa);
1106 }
1107#endif
77cb59b3
AC
1108
1109 return result;
db137867
AC
1110}
1111
1112void
1113rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
1114{
1115 static int initialized = 0;
3202e249 1116#ifdef _WIN32
db137867
AC
1117 WSADATA wsaData;
1118 int err;
1119 int vers = MAKEWORD(2, 0);
3202e249 1120
db137867
AC
1121 err = WSAStartup(vers, &wsaData);
1122 if(err != 0)
1123 {
1124 rb_lib_die("WSAStartup failed");
1125 }
1126
1127#endif
1128 if(!initialized)
1129 {
1130 rb_maxconnections = maxfds;
1131 if(closeall)
1132 rb_close_all();
1133 /* Since we're doing this once .. */
1134 initialized = 1;
1135 }
1136 fd_heap = rb_bh_create(sizeof(rb_fde_t), heapsize, "librb_fd_heap");
1137
1138}
1139
1140
1141/* Called to open a given filedescriptor */
1142rb_fde_t *
dc7e6b42 1143rb_open(rb_platform_fd_t fd, uint8_t type, const char *desc)
db137867 1144{
a9fb3ed0 1145 rb_fde_t *F;
db137867
AC
1146 lrb_assert(fd >= 0);
1147
a9fb3ed0
VY
1148 F = add_fd(fd);
1149
1150 lrb_assert(!IsFDOpen(F));
c2ac22cc 1151 if(rb_unlikely(IsFDOpen(F)))
db137867 1152 {
a9fb3ed0
VY
1153 const char *fdesc;
1154 if(F != NULL && F->desc != NULL)
1155 fdesc = F->desc;
1156 else
1157 fdesc = "NULL";
3202e249 1158 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd, fdesc);
db137867
AC
1159 return NULL;
1160 }
db137867
AC
1161 F->fd = fd;
1162 F->type = type;
1163 SetFDOpen(F);
1164
1165 if(desc != NULL)
1166 F->desc = rb_strndup(desc, FD_DESC_SZ);
1167 number_fd++;
1168 return F;
1169}
1170
1171
1172/* Called to close a given filedescriptor */
1173void
1174rb_close(rb_fde_t *F)
1175{
1176 int type, fd;
3202e249 1177
db137867
AC
1178 if(F == NULL)
1179 return;
1180
1181 fd = F->fd;
3202e249 1182 type = F->type;
db137867
AC
1183 lrb_assert(IsFDOpen(F));
1184
1185 lrb_assert(!(type & RB_FD_FILE));
c2ac22cc 1186 if(rb_unlikely(type & RB_FD_FILE))
db137867
AC
1187 {
1188 lrb_assert(F->read_handler == NULL);
1189 lrb_assert(F->write_handler == NULL);
1190 }
c6ad9b0c
SA
1191
1192 if (type & RB_FD_LISTEN) {
1193 listen(F->fd, 0);
1194 }
1195
db137867
AC
1196 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
1197 rb_settimeout(F, 0, NULL, NULL);
1198 rb_free(F->accept);
1199 rb_free(F->connect);
1200 rb_free(F->desc);
1201#ifdef HAVE_SSL
1202 if(type & RB_FD_SSL)
1203 {
1204 rb_ssl_shutdown(F);
1205 }
1206#endif /* HAVE_SSL */
1207 if(IsFDOpen(F))
1208 {
1209 remove_fd(F);
1210 ClearFDOpen(F);
1211 }
8a29e7cd
SA
1212
1213 if(type & RB_FD_LISTEN)
1214 shutdown(fd, SHUT_RDWR);
db137867
AC
1215}
1216
1217
1218/*
1219 * rb_dump_fd() - dump the list of active filedescriptors
1220 */
1221void
1222rb_dump_fd(DUMPCB * cb, void *data)
1223{
1224 static const char *empty = "";
1225 rb_dlink_node *ptr;
1226 rb_dlink_list *bucket;
1227 rb_fde_t *F;
1228 unsigned int i;
1229
1230 for(i = 0; i < RB_FD_HASH_SIZE; i++)
1231 {
1232 bucket = &rb_fd_table[i];
1233
1234 if(rb_dlink_list_length(bucket) <= 0)
1235 continue;
1236
1237 RB_DLINK_FOREACH(ptr, bucket->head)
1238 {
1239 F = ptr->data;
1240 if(F == NULL || !IsFDOpen(F))
1241 continue;
1242
1243 cb(F->fd, F->desc ? F->desc : empty, data);
1244 }
1245 }
1246}
1247
1248/*
1249 * rb_note() - set the fd note
1250 *
1251 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1252 * calling.
1253 */
1254void
1255rb_note(rb_fde_t *F, const char *string)
1256{
1257 if(F == NULL)
1258 return;
1259
1260 rb_free(F->desc);
1261 F->desc = rb_strndup(string, FD_DESC_SZ);
1262}
1263
1264void
a9fb3ed0 1265rb_set_type(rb_fde_t *F, uint8_t type)
db137867
AC
1266{
1267 /* if the caller is calling this, lets assume they have a clue */
1268 F->type = type;
1269 return;
1270}
1271
a9fb3ed0 1272uint8_t
db137867
AC
1273rb_get_type(rb_fde_t *F)
1274{
1275 return F->type;
1276}
1277
3202e249 1278int
db137867
AC
1279rb_fd_ssl(rb_fde_t *F)
1280{
1281 if(F == NULL)
1282 return 0;
1283 if(F->type & RB_FD_SSL)
1284 return 1;
1285 return 0;
1286}
1287
b1f7e409 1288rb_platform_fd_t
db137867
AC
1289rb_get_fd(rb_fde_t *F)
1290{
1291 if(F == NULL)
1292 return -1;
3202e249 1293 return (F->fd);
db137867
AC
1294}
1295
1296rb_fde_t *
dc7e6b42 1297rb_get_fde(rb_platform_fd_t fd)
db137867
AC
1298{
1299 return rb_find_fd(fd);
1300}
1301
1302ssize_t
1303rb_read(rb_fde_t *F, void *buf, int count)
1304{
ba1721d1 1305 ssize_t ret;
db137867
AC
1306 if(F == NULL)
1307 return 0;
3202e249 1308
55abcbb2
KB
1309 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1310 * an SSL socket as a regular socket
db137867
AC
1311 */
1312#ifdef HAVE_SSL
1313 if(F->type & RB_FD_SSL)
1314 {
1315 return rb_ssl_read(F, buf, count);
3202e249 1316 }
db137867
AC
1317#endif
1318 if(F->type & RB_FD_SOCKET)
1319 {
1320 ret = recv(F->fd, buf, count, 0);
1321 if(ret < 0)
1322 {
1323 rb_get_errno();
1324 }
1325 return ret;
1326 }
1327
1328
1329 /* default case */
1330 return read(F->fd, buf, count);
1331}
1332
1333
1334ssize_t
1335rb_write(rb_fde_t *F, const void *buf, int count)
1336{
ba1721d1 1337 ssize_t ret;
db137867
AC
1338 if(F == NULL)
1339 return 0;
1340
1341#ifdef HAVE_SSL
1342 if(F->type & RB_FD_SSL)
1343 {
1344 return rb_ssl_write(F, buf, count);
3202e249 1345 }
db137867
AC
1346#endif
1347 if(F->type & RB_FD_SOCKET)
1348 {
1349 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
3202e249
VY
1350 if(ret < 0)
1351 {
db137867
AC
1352 rb_get_errno();
1353 }
1354 return ret;
1355 }
1356
1357 return write(F->fd, buf, count);
1358}
1359
1360#if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1361static ssize_t
1362rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1363{
ba1721d1 1364 ssize_t count = 0;
db137867 1365
3202e249 1366 while(vpcount-- > 0)
db137867 1367 {
ba1721d1 1368 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
db137867 1369
3202e249 1370 if(written <= 0)
db137867
AC
1371 {
1372 if(count > 0)
1373 return count;
1374 else
1375 return written;
1376 }
1377 count += written;
1378 vp++;
1379 }
1380 return (count);
1381}
1382#endif
1383
1384#if defined(WIN32) || !defined(HAVE_WRITEV)
1385ssize_t
3202e249 1386rb_writev(rb_fde_t *F, struct rb_iovec * vecount, int count)
db137867
AC
1387{
1388 return rb_fake_writev(F, vecount, count);
1389}
1390
1391#else
1392ssize_t
3202e249 1393rb_writev(rb_fde_t *F, struct rb_iovec * vector, int count)
db137867 1394{
3202e249
VY
1395 if(F == NULL)
1396 {
db137867
AC
1397 errno = EBADF;
1398 return -1;
1399 }
1400#ifdef HAVE_SSL
1401 if(F->type & RB_FD_SSL)
1402 {
3202e249 1403 return rb_fake_writev(F, vector, count);
db137867
AC
1404 }
1405#endif /* HAVE_SSL */
1406#ifdef HAVE_SENDMSG
1407 if(F->type & RB_FD_SOCKET)
1408 {
1409 struct msghdr msg;
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);
3202e249 1414 }
db137867
AC
1415#endif /* HAVE_SENDMSG */
1416 return writev(F->fd, (struct iovec *)vector, count);
1417
1418}
3202e249 1419#endif
db137867
AC
1420
1421
55abcbb2 1422/*
db137867
AC
1423 * From: Thomas Helvey <tomh@inxpress.net>
1424 */
1425static 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"
1452};
1453
1454/*
1455 * inetntoa - in_addr to string
1456 * changed name to remove collision possibility and
1457 * so behaviour is guaranteed to take a pointer arg.
1458 * -avalon 23/11/92
1459 * inet_ntoa -- returned the dotted notation of a given
1460 * internet number
1461 * argv 11/90).
1462 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1463 */
1464
1465static const char *
1466inetntoa(const char *in)
1467{
1468 static char buf[16];
1469 char *bufptr = buf;
3202e249 1470 const unsigned char *a = (const unsigned char *)in;
db137867
AC
1471 const char *n;
1472
1473 n = IpQuadTab[*a++];
3202e249 1474 while(*n)
db137867
AC
1475 *bufptr++ = *n++;
1476 *bufptr++ = '.';
1477 n = IpQuadTab[*a++];
3202e249 1478 while(*n)
db137867
AC
1479 *bufptr++ = *n++;
1480 *bufptr++ = '.';
1481 n = IpQuadTab[*a++];
3202e249 1482 while(*n)
db137867
AC
1483 *bufptr++ = *n++;
1484 *bufptr++ = '.';
1485 n = IpQuadTab[*a];
3202e249 1486 while(*n)
db137867
AC
1487 *bufptr++ = *n++;
1488 *bufptr = '\0';
1489 return buf;
1490}
1491
db137867
AC
1492/*
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.
1495 */
1496
3202e249 1497static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
3202e249 1498static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
db137867
AC
1499
1500/* const char *
1501 * inet_ntop4(src, dst, size)
1502 * format an IPv4 address
1503 * return:
1504 * `dst' (as a const)
1505 * notes:
1506 * (1) uses no statics
1507 * (2) takes a unsigned char* not an in_addr as input
1508 * author:
1509 * Paul Vixie, 1996.
1510 */
1511static const char *
1512inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1513{
1514 if(size < 16)
1515 return NULL;
86510a73 1516 return strcpy(dst, inetntoa((const char *)src));
db137867
AC
1517}
1518
1519/* const char *
1520 * inet_ntop6(src, dst, size)
1521 * convert IPv6 binary address into presentation (printable) format
1522 * author:
1523 * Paul Vixie, 1996.
1524 */
db137867
AC
1525static const char *
1526inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
1527{
1528 /*
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.
1534 */
1535 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
1536 struct
1537 {
1538 int base, len;
1539 }
1540 best, cur;
1541 unsigned int words[IN6ADDRSZ / INT16SZ];
1542 int i;
1543
1544 /*
1545 * Preprocess:
1546 * Copy the input (bytewise) array into a wordwise array.
1547 * Find the longest run of 0x00's in src[] for :: shorthanding.
1548 */
1549 memset(words, '\0', sizeof words);
3202e249 1550 for(i = 0; i < IN6ADDRSZ; i += 2)
db137867
AC
1551 words[i / 2] = (src[i] << 8) | src[i + 1];
1552 best.base = -1;
1553 best.len = 0;
1554 cur.base = -1;
1555 cur.len = 0;
3202e249 1556 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1557 {
1558 if(words[i] == 0)
1559 {
1560 if(cur.base == -1)
1561 cur.base = i, cur.len = 1;
1562 else
1563 cur.len++;
1564 }
1565 else
1566 {
1567 if(cur.base != -1)
1568 {
1569 if(best.base == -1 || cur.len > best.len)
1570 best = cur;
1571 cur.base = -1;
1572 }
1573 }
1574 }
1575 if(cur.base != -1)
1576 {
1577 if(best.base == -1 || cur.len > best.len)
1578 best = cur;
1579 }
1580 if(best.base != -1 && best.len < 2)
1581 best.base = -1;
1582
1583 /*
1584 * Format the result.
1585 */
1586 tp = tmp;
3202e249 1587 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1588 {
1589 /* Are we inside the best run of 0x00's? */
1590 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
1591 {
1592 if(i == best.base)
1593 {
1594 if(i == 0)
1595 *tp++ = '0';
1596 *tp++ = ':';
1597 }
1598 continue;
1599 }
1600 /* Are we following an initial run of 0x00s or any real hex? */
1601 if(i != 0)
1602 *tp++ = ':';
1603 /* Is this address an encapsulated IPv4? */
1604 if(i == 6 && best.base == 0 &&
1605 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
1606 {
1607 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
1608 return (NULL);
1609 tp += strlen(tp);
1610 break;
1611 }
5203cba5 1612 tp += sprintf(tp, "%x", words[i]);
db137867
AC
1613 }
1614 /* Was it a trailing run of 0x00's? */
1615 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
1616 *tp++ = ':';
1617 *tp++ = '\0';
1618
1619 /*
1620 * Check for overflow, copy, and we're done.
1621 */
1622
3202e249 1623 if((unsigned int)(tp - tmp) > size)
db137867
AC
1624 {
1625 return (NULL);
1626 }
86510a73 1627 return memcpy(dst, tmp, tp - tmp);
db137867 1628}
db137867
AC
1629
1630int
17809d2d 1631rb_inet_pton_sock(const char *src, struct sockaddr_storage *dst)
db137867 1632{
9caecc93 1633 memset(dst, 0, sizeof(*dst));
3202e249 1634 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
db137867 1635 {
d86692fa 1636 SET_SS_FAMILY(dst, AF_INET);
1315fd59 1637 SET_SS_PORT(dst, 0);
db137867
AC
1638 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1639 return 1;
1640 }
3202e249 1641 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
db137867 1642 {
d86692fa 1643 SET_SS_FAMILY(dst, AF_INET6);
1315fd59 1644 SET_SS_PORT(dst, 0);
db137867
AC
1645 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1646 return 1;
1647 }
db137867
AC
1648 return 0;
1649}
1650
1651const char *
1652rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1653{
1654 switch (src->sa_family)
1655 {
1656 case AF_INET:
3202e249 1657 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
db137867 1658 case AF_INET6:
3202e249
VY
1659 return (rb_inet_ntop
1660 (AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
db137867
AC
1661 default:
1662 return NULL;
db137867
AC
1663 }
1664}
1665
1666/* char *
1667 * rb_inet_ntop(af, src, dst, size)
1668 * convert a network format address to presentation format.
1669 * return:
1670 * pointer to presentation format address (`dst'), or NULL (see errno).
1671 * author:
1672 * Paul Vixie, 1996.
1673 */
1674const char *
1675rb_inet_ntop(int af, const void *src, char *dst, unsigned int size)
1676{
1677 switch (af)
1678 {
1679 case AF_INET:
1680 return (inet_ntop4(src, dst, size));
db137867 1681 case AF_INET6:
3202e249
VY
1682 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
1683 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
db137867 1684 return (inet_ntop4
3202e249
VY
1685 ((const unsigned char *)&((const struct in6_addr *)src)->
1686 s6_addr[12], dst, size));
db137867
AC
1687 else
1688 return (inet_ntop6(src, dst, size));
db137867
AC
1689 default:
1690 return (NULL);
1691 }
1692 /* NOTREACHED */
1693}
1694
1695/*
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.
1698 */
1699
1700/* int
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).
1704 * return:
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)
1708 * author:
1709 * Paul Vixie, 1996.
1710 */
1711
1712/* int
1713 * inet_pton4(src, dst)
1714 * like inet_aton() but without all the hexadecimal and shorthand.
1715 * return:
1716 * 1 if `src' is a valid dotted quad, else 0.
1717 * notice:
1718 * does not touch `dst' unless it's returning 1.
1719 * author:
1720 * Paul Vixie, 1996.
1721 */
1722static int
1723inet_pton4(const char *src, unsigned char *dst)
1724{
1725 int saw_digit, octets, ch;
1726 unsigned char tmp[INADDRSZ], *tp;
1727
1728 saw_digit = 0;
1729 octets = 0;
1730 *(tp = tmp) = 0;
3202e249 1731 while((ch = *src++) != '\0')
db137867
AC
1732 {
1733
1734 if(ch >= '0' && ch <= '9')
1735 {
1736 unsigned int new = *tp * 10 + (ch - '0');
1737
1738 if(new > 255)
1739 return (0);
1740 *tp = new;
1741 if(!saw_digit)
1742 {
1743 if(++octets > 4)
1744 return (0);
1745 saw_digit = 1;
1746 }
1747 }
1748 else if(ch == '.' && saw_digit)
1749 {
1750 if(octets == 4)
1751 return (0);
1752 *++tp = 0;
1753 saw_digit = 0;
1754 }
1755 else
1756 return (0);
1757 }
1758 if(octets < 4)
1759 return (0);
1760 memcpy(dst, tmp, INADDRSZ);
1761 return (1);
1762}
1763
db137867
AC
1764/* int
1765 * inet_pton6(src, dst)
1766 * convert presentation level address to network order binary form.
1767 * return:
1768 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1769 * notice:
1770 * (1) does not touch `dst' unless it's returning 1.
1771 * (2) :: in a full address is silently ignored.
1772 * credit:
1773 * inspired by Mark Andrews.
1774 * author:
1775 * Paul Vixie, 1996.
1776 */
1777
1778static int
1779inet_pton6(const char *src, unsigned char *dst)
1780{
1781 static const char xdigits[] = "0123456789abcdef";
1782 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
1783 const char *curtok;
1784 int ch, saw_xdigit;
1785 unsigned int val;
1786
1787 tp = memset(tmp, '\0', IN6ADDRSZ);
1788 endp = tp + IN6ADDRSZ;
1789 colonp = NULL;
1790 /* Leading :: requires some special handling. */
1791 if(*src == ':')
1792 if(*++src != ':')
1793 return (0);
1794 curtok = src;
1795 saw_xdigit = 0;
1796 val = 0;
29c92cf9 1797 while((ch = tolower((unsigned char)*src++)) != '\0')
db137867
AC
1798 {
1799 const char *pch;
1800
1801 pch = strchr(xdigits, ch);
1802 if(pch != NULL)
1803 {
1804 val <<= 4;
1805 val |= (pch - xdigits);
1806 if(val > 0xffff)
1807 return (0);
1808 saw_xdigit = 1;
1809 continue;
1810 }
1811 if(ch == ':')
1812 {
1813 curtok = src;
1814 if(!saw_xdigit)
1815 {
1816 if(colonp)
1817 return (0);
1818 colonp = tp;
1819 continue;
1820 }
1821 else if(*src == '\0')
1822 {
1823 return (0);
1824 }
1825 if(tp + INT16SZ > endp)
1826 return (0);
3202e249
VY
1827 *tp++ = (unsigned char)(val >> 8) & 0xff;
1828 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1829 saw_xdigit = 0;
1830 val = 0;
1831 continue;
1832 }
1833 if(*src != '\0' && ch == '.')
1834 {
1835 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
1836 {
1837 tp += INADDRSZ;
1838 saw_xdigit = 0;
1839 break; /* '\0' was seen by inet_pton4(). */
1840 }
1841 }
1842 else
1843 continue;
1844 return (0);
1845 }
1846 if(saw_xdigit)
1847 {
1848 if(tp + INT16SZ > endp)
1849 return (0);
3202e249
VY
1850 *tp++ = (unsigned char)(val >> 8) & 0xff;
1851 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1852 }
1853 if(colonp != NULL)
1854 {
1855 /*
1856 * Since some memmove()'s erroneously fail to handle
1857 * overlapping regions, we'll do the shift by hand.
1858 */
1859 const int n = tp - colonp;
1860 int i;
1861
1862 if(tp == endp)
1863 return (0);
3202e249 1864 for(i = 1; i <= n; i++)
db137867
AC
1865 {
1866 endp[-i] = colonp[n - i];
1867 colonp[n - i] = 0;
1868 }
1869 tp = endp;
1870 }
1871 if(tp != endp)
1872 return (0);
1873 memcpy(dst, tmp, IN6ADDRSZ);
1874 return (1);
1875}
de293496 1876
db137867
AC
1877int
1878rb_inet_pton(int af, const char *src, void *dst)
1879{
1880 switch (af)
1881 {
1882 case AF_INET:
1883 return (inet_pton4(src, dst));
db137867
AC
1884 case AF_INET6:
1885 /* Somebody might have passed as an IPv4 address this is sick but it works */
1886 if(inet_pton4(src, dst))
1887 {
1888 char tmp[HOSTIPLEN];
5203cba5 1889 sprintf(tmp, "::ffff:%s", src);
db137867
AC
1890 return (inet_pton6(tmp, dst));
1891 }
1892 else
1893 return (inet_pton6(src, dst));
db137867
AC
1894 default:
1895 return (-1);
1896 }
1897 /* NOTREACHED */
1898}
1899
1900
1901#ifndef HAVE_SOCKETPAIR
3202e249
VY
1902
1903/* mostly based on perl's emulation of socketpair udp */
1904static int
1905rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2)
1906{
1907 struct sockaddr_in addr[2];
1908 rb_socklen_t size = sizeof(struct sockaddr_in);
1909 rb_fde_t *F[2];
7dbf237f 1910 rb_platform_fd_t fd[2];
3202e249
VY
1911 int i, got;
1912 unsigned short port;
030272f3
VY
1913 struct timeval wait = { 0, 100000 };
1914 int max;
1915 fd_set rset;
1916 struct sockaddr_in readfrom;
1917 unsigned short buf[2];
1918 int o_errno;
3202e249
VY
1919
1920 memset(&addr, 0, sizeof(addr));
1921
1922 for(i = 0; i < 2; i++)
1923 {
1924 F[i] = rb_socket(AF_INET, SOCK_DGRAM, 0, "udp socketpair");
1925 if(F[i] == NULL)
1926 goto failed;
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)))
1931 goto failed;
1932 fd[i] = rb_get_fd(F[i]);
1933 }
1934
1935 for(i = 0; i < 2; i++)
1936 {
1937 if(getsockname(fd[i], (struct sockaddr *)&addr[i], &size))
1938 goto failed;
1939 if(size != sizeof(struct sockaddr_in))
1940 goto failed;
1941 if(connect(fd[!i], (struct sockaddr *)&addr[i], sizeof(struct sockaddr_in)) == -1)
1942 goto failed;
1943 }
1944
1945 for(i = 0; i < 2; i++)
1946 {
1947 port = addr[i].sin_port;
1948 got = rb_write(F[i], &port, sizeof(port));
1949 if(got != sizeof(port))
1950 {
1951 if(got == -1)
1952 goto failed;
1953 goto abort_failed;
1954 }
1955 }
1956
030272f3 1957 max = fd[1] > fd[0] ? fd[1] : fd[0];
3202e249
VY
1958 FD_ZERO(&rset);
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))
1963 {
1964 if(got == -1)
1965 goto failed;
1966 goto abort_failed;
1967 }
1968
3202e249
VY
1969 for(i = 0; i < 2; i++)
1970 {
1971#ifdef MSG_DONTWAIT
1972 int flag = MSG_DONTWAIT
1973#else
1974 int flag = 0;
1975#endif
1976 got = recvfrom(rb_get_fd(F[i]), (char *)&buf, sizeof(buf), flag,
1977 (struct sockaddr *)&readfrom, &size);
1978 if(got == -1)
1979 goto failed;
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)
1986 goto abort_failed;
1987 }
1988
1989 *newF1 = F[0];
1990 *newF2 = F[1];
1991 return 0;
1992
1993#ifdef _WIN32
7dbf237f 1994#ifndef ECONNABORTED
3202e249 1995#define ECONNABORTED WSAECONNABORTED
7dbf237f 1996#endif
3202e249
VY
1997#endif
1998
1999 abort_failed:
2000 rb_get_errno();
2001 errno = ECONNABORTED;
2002 failed:
2003 if(errno != ECONNABORTED)
2004 rb_get_errno();
030272f3 2005 o_errno = errno;
3202e249
VY
2006 if(F[0] != NULL)
2007 rb_close(F[0]);
2008 if(F[1] != NULL)
2009 rb_close(F[1]);
2010 errno = o_errno;
2011 return -1;
2012}
2013
2014
db137867 2015int
dc7e6b42 2016rb_inet_socketpair(int family, int type, int protocol, rb_platform_fd_t fd[2])
db137867
AC
2017{
2018 int listener = -1;
2019 int connector = -1;
2020 int acceptor = -1;
2021 struct sockaddr_in listen_addr;
2022 struct sockaddr_in connect_addr;
3202e249 2023 rb_socklen_t size;
db137867
AC
2024
2025 if(protocol || family != AF_INET)
2026 {
2027 errno = EAFNOSUPPORT;
2028 return -1;
2029 }
2030 if(!fd)
2031 {
2032 errno = EINVAL;
2033 return -1;
2034 }
2035
2036 listener = socket(AF_INET, type, 0);
2037 if(listener == -1)
2038 return -1;
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. */
3202e249 2043 if(bind(listener, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) == -1)
db137867
AC
2044 goto tidy_up_and_fail;
2045 if(listen(listener, 1) == -1)
2046 goto tidy_up_and_fail;
2047
2048 connector = socket(AF_INET, type, 0);
2049 if(connector == -1)
2050 goto tidy_up_and_fail;
2051 /* We want to find out the port number to connect to. */
2052 size = sizeof(connect_addr);
3202e249 2053 if(getsockname(listener, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
2054 goto tidy_up_and_fail;
2055 if(size != sizeof(connect_addr))
2056 goto abort_tidy_up_and_fail;
3202e249 2057 if(connect(connector, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) == -1)
db137867
AC
2058 goto tidy_up_and_fail;
2059
2060 size = sizeof(listen_addr);
3202e249 2061 acceptor = accept(listener, (struct sockaddr *)&listen_addr, &size);
db137867
AC
2062 if(acceptor == -1)
2063 goto tidy_up_and_fail;
2064 if(size != sizeof(listen_addr))
2065 goto abort_tidy_up_and_fail;
2066 close(listener);
2067 /* Now check we are talking to ourself by matching port and host on the
2068 two sockets. */
3202e249 2069 if(getsockname(connector, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
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)
2075 {
2076 goto abort_tidy_up_and_fail;
2077 }
2078 fd[0] = connector;
2079 fd[1] = acceptor;
2080 return 0;
2081
2082 abort_tidy_up_and_fail:
2083 errno = EINVAL; /* I hope this is portable and appropriate. */
2084
2085 tidy_up_and_fail:
2086 {
2087 int save_errno = errno;
2088 if(listener != -1)
2089 close(listener);
2090 if(connector != -1)
2091 close(connector);
2092 if(acceptor != -1)
2093 close(acceptor);
2094 errno = save_errno;
2095 return -1;
2096 }
2097}
2098
2099#endif
2100
2101
2102static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
2103static int (*select_handler) (long);
2104static int (*setup_fd_handler) (rb_fde_t *);
2105static int (*io_sched_event) (struct ev_entry *, int);
2106static void (*io_unsched_event) (struct ev_entry *);
2107static int (*io_supports_event) (void);
2108static void (*io_init_event) (void);
2109static char iotype[25];
2110
2111const char *
2112rb_get_iotype(void)
2113{
2114 return iotype;
2115}
2116
2117static int
2118rb_unsupported_event(void)
2119{
2120 return 0;
2121}
2122
2123static int
2124try_kqueue(void)
2125{
2126 if(!rb_init_netio_kqueue())
2127 {
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));
2136 return 0;
2137 }
3202e249 2138 return -1;
db137867
AC
2139}
2140
2141static int
2142try_epoll(void)
2143{
2144 if(!rb_init_netio_epoll())
2145 {
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));
2154 return 0;
2155 }
2156 return -1;
2157}
2158
2159static int
2160try_ports(void)
2161{
2162 if(!rb_init_netio_ports())
2163 {
2164 setselect_handler = rb_setselect_ports;
2165 select_handler = rb_select_ports;
3202e249 2166 setup_fd_handler = rb_setup_fd_ports;
030272f3
VY
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;
db137867
AC
2171 rb_strlcpy(iotype, "ports", sizeof(iotype));
2172 return 0;
2173 }
2174 return -1;
2175}
2176
2177static int
2178try_devpoll(void)
2179{
2180 if(!rb_init_netio_devpoll())
2181 {
2182 setselect_handler = rb_setselect_devpoll;
2183 select_handler = rb_select_devpoll;
3202e249 2184 setup_fd_handler = rb_setup_fd_devpoll;
db137867
AC
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));
2190 return 0;
2191 }
2192 return -1;
2193}
2194
2195static int
2196try_sigio(void)
2197{
2198 if(!rb_init_netio_sigio())
2199 {
2200 setselect_handler = rb_setselect_sigio;
2201 select_handler = rb_select_sigio;
3202e249 2202 setup_fd_handler = rb_setup_fd_sigio;
db137867 2203 io_sched_event = rb_sigio_sched_event;
3202e249
VY
2204 io_unsched_event = rb_sigio_unsched_event;
2205 io_supports_event = rb_sigio_supports_event;
2206 io_init_event = rb_sigio_init_event;
2207
db137867
AC
2208 rb_strlcpy(iotype, "sigio", sizeof(iotype));
2209 return 0;
2210 }
2211 return -1;
2212}
2213
3202e249 2214static int
db137867
AC
2215try_poll(void)
2216{
2217 if(!rb_init_netio_poll())
2218 {
2219 setselect_handler = rb_setselect_poll;
2220 select_handler = rb_select_poll;
3202e249 2221 setup_fd_handler = rb_setup_fd_poll;
db137867
AC
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));
2227 return 0;
2228 }
2229 return -1;
2230}
2231
2232static int
2233try_win32(void)
2234{
2235 if(!rb_init_netio_win32())
2236 {
2237 setselect_handler = rb_setselect_win32;
2238 select_handler = rb_select_win32;
3202e249 2239 setup_fd_handler = rb_setup_fd_win32;
db137867
AC
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));
2245 return 0;
2246 }
2247 return -1;
2248}
2249
2250static int
2251try_select(void)
3202e249 2252{
db137867
AC
2253 if(!rb_init_netio_select())
2254 {
2255 setselect_handler = rb_setselect_select;
2256 select_handler = rb_select_select;
3202e249 2257 setup_fd_handler = rb_setup_fd_select;
db137867
AC
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));
2263 return 0;
2264 }
2265 return -1;
2266}
2267
2268
2269int
2270rb_io_sched_event(struct ev_entry *ev, int when)
2271{
3202e249
VY
2272 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL
2273 || !io_supports_event())
db137867
AC
2274 return 0;
2275 return io_sched_event(ev, when);
2276}
2277
2278void
2279rb_io_unsched_event(struct ev_entry *ev)
2280{
3202e249
VY
2281 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL
2282 || !io_supports_event())
db137867 2283 return;
3202e249 2284 io_unsched_event(ev);
db137867 2285}
3202e249 2286
db137867
AC
2287int
2288rb_io_supports_event(void)
2289{
2290 if(io_supports_event == NULL)
2291 return 0;
2292 return io_supports_event();
2293}
2294
2295void
2296rb_io_init_event(void)
2297{
2298 io_init_event();
2299 rb_event_io_register_all();
2300}
2301
2302void
2303rb_init_netio(void)
2304{
2305 char *ioenv = getenv("LIBRB_USE_IOTYPE");
2306 rb_fd_table = rb_malloc(RB_FD_HASH_SIZE * sizeof(rb_dlink_list));
2307 rb_init_ssl();
3202e249 2308
db137867
AC
2309 if(ioenv != NULL)
2310 {
2311 if(!strcmp("epoll", ioenv))
2312 {
2313 if(!try_epoll())
2314 return;
3202e249
VY
2315 }
2316 else if(!strcmp("kqueue", ioenv))
db137867
AC
2317 {
2318 if(!try_kqueue())
2319 return;
3202e249
VY
2320 }
2321 else if(!strcmp("ports", ioenv))
db137867
AC
2322 {
2323 if(!try_ports())
2324 return;
3202e249
VY
2325 }
2326 else if(!strcmp("poll", ioenv))
db137867
AC
2327 {
2328 if(!try_poll())
2329 return;
3202e249
VY
2330 }
2331 else if(!strcmp("devpoll", ioenv))
db137867
AC
2332 {
2333 if(!try_devpoll())
2334 return;
3202e249
VY
2335 }
2336 else if(!strcmp("sigio", ioenv))
db137867
AC
2337 {
2338 if(!try_sigio())
2339 return;
3202e249
VY
2340 }
2341 else if(!strcmp("select", ioenv))
db137867 2342 {
3202e249 2343 if(!try_select())
db137867
AC
2344 return;
2345 }
3202e249 2346 if(!strcmp("win32", ioenv))
db137867 2347 {
3202e249 2348 if(!try_win32())
db137867
AC
2349 return;
2350 }
3202e249 2351
db137867
AC
2352 }
2353
2354 if(!try_kqueue())
2355 return;
2356 if(!try_epoll())
2357 return;
2358 if(!try_ports())
2359 return;
2360 if(!try_devpoll())
2361 return;
2362 if(!try_sigio())
2363 return;
2364 if(!try_poll())
2365 return;
2366 if(!try_win32())
2367 return;
2368 if(!try_select())
2369 return;
2370
2371 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2372
2373 abort();
2374}
2375
3202e249 2376void
db137867
AC
2377rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
2378{
2379 setselect_handler(F, type, handler, client_data);
2380}
2381
3202e249 2382int
db137867
AC
2383rb_select(unsigned long timeout)
2384{
2385 int ret = select_handler(timeout);
2386 free_fds();
2387 return ret;
2388}
2389
3202e249 2390int
db137867
AC
2391rb_setup_fd(rb_fde_t *F)
2392{
1cad0654 2393 rb_set_cloexec(F);
db137867
AC
2394 return setup_fd_handler(F);
2395}
2396
2397
db137867
AC
2398int
2399rb_ignore_errno(int error)
2400{
3202e249 2401 switch (error)
db137867
AC
2402 {
2403#ifdef EINPROGRESS
3202e249 2404 case EINPROGRESS:
db137867
AC
2405#endif
2406#if defined EWOULDBLOCK
3202e249 2407 case EWOULDBLOCK:
db137867
AC
2408#endif
2409#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
3202e249 2410 case EAGAIN:
db137867
AC
2411#endif
2412#ifdef EINTR
3202e249 2413 case EINTR:
db137867
AC
2414#endif
2415#ifdef ERESTART
3202e249 2416 case ERESTART:
db137867
AC
2417#endif
2418#ifdef ENOBUFS
3202e249
VY
2419 case ENOBUFS:
2420#endif
2421 return 1;
2422 default:
2423 break;
2424 }
db137867
AC
2425 return 0;
2426}
2427
2428
3202e249 2429#if defined(HAVE_SENDMSG) && !defined(WIN32)
db137867
AC
2430int
2431rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2432{
2433 struct msghdr msg;
2434 struct cmsghdr *cmsg;
2435 struct iovec iov[1];
2436 struct stat st;
a9fb3ed0 2437 uint8_t stype = RB_FD_UNKNOWN;
db137867 2438 const char *desc;
dc7e6b42 2439 rb_platform_fd_t fd, len, x, rfds;
db137867
AC
2440
2441 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2442
2443 iov[0].iov_base = data;
2444 iov[0].iov_len = datasize;
3202e249 2445
db137867
AC
2446 msg.msg_name = NULL;
2447 msg.msg_namelen = 0;
2448 msg.msg_iov = iov;
2449 msg.msg_iovlen = 1;
2450 msg.msg_flags = 0;
2451 cmsg = alloca(control_len);
2452 msg.msg_control = cmsg;
2453 msg.msg_controllen = control_len;
2454
2455 if((len = recvmsg(rb_get_fd(F), &msg, 0)) <= 0)
2456 return len;
2457
3202e249
VY
2458 if(msg.msg_controllen > 0 && msg.msg_control != NULL
2459 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
db137867 2460 {
90e960f0 2461 rfds = ((unsigned char *)cmsg + cmsg->cmsg_len - CMSG_DATA(cmsg)) / sizeof(int);
db137867
AC
2462
2463 for(x = 0; x < nfds && x < rfds; x++)
2464 {
2465 fd = ((int *)CMSG_DATA(cmsg))[x];
2466 stype = RB_FD_UNKNOWN;
2467 desc = "remote unknown";
2468 if(!fstat(fd, &st))
2469 {
2470 if(S_ISSOCK(st.st_mode))
2471 {
2472 stype = RB_FD_SOCKET;
2473 desc = "remote socket";
2474 }
2475 else if(S_ISFIFO(st.st_mode))
2476 {
2477 stype = RB_FD_PIPE;
2478 desc = "remote pipe";
2479 }
2480 else if(S_ISREG(st.st_mode))
2481 {
2482 stype = RB_FD_FILE;
2483 desc = "remote file";
2484 }
2485 }
2486 xF[x] = rb_open(fd, stype, desc);
2487 }
3202e249
VY
2488 }
2489 else
db137867 2490 *xF = NULL;
3202e249 2491 return len;
db137867
AC
2492}
2493
2494
2495int
8679c0fe 2496rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid __attribute__((unused)))
db137867 2497{
db137867
AC
2498 struct msghdr msg;
2499 struct cmsghdr *cmsg;
2500 struct iovec iov[1];
2501 char empty = '0';
db137867 2502
5cc7ba25 2503 memset(&msg, 0, sizeof(msg));
db137867
AC
2504 if(datasize == 0)
2505 {
2506 iov[0].iov_base = &empty;
3202e249
VY
2507 iov[0].iov_len = 1;
2508 }
2509 else
2510 {
db137867
AC
2511 iov[0].iov_base = data;
2512 iov[0].iov_len = datasize;
2513 }
2514 msg.msg_iov = iov;
2515 msg.msg_iovlen = 1;
2516 msg.msg_name = NULL;
2517 msg.msg_namelen = 0;
2518 msg.msg_flags = 0;
2519 msg.msg_control = NULL;
2520 msg.msg_controllen = 0;
2521
2522 if(count > 0)
2523 {
e23126c8 2524 size_t ucount = (size_t)count;
db137867 2525 int len = CMSG_SPACE(sizeof(int) * count);
5cc7ba25 2526 char buf[len];
db137867
AC
2527
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);
2534
e23126c8 2535 for(size_t i = 0; i < ucount; i++)
3202e249
VY
2536 {
2537 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
db137867
AC
2538 }
2539 msg.msg_controllen = cmsg->cmsg_len;
5cc7ba25 2540 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2541 }
5cc7ba25 2542 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2543}
4eafa9e6 2544#else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
3202e249
VY
2545#ifndef _WIN32
2546int
2547rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2548{
2549 errno = ENOSYS;
2550 return -1;
2551}
db137867 2552
3202e249
VY
2553int
2554rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
2555{
2556 errno = ENOSYS;
2557 return -1;
2558}
4eafa9e6
EM
2559#endif /* _WIN32 */
2560#endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2561
4eafa9e6
EM
2562int
2563rb_ipv4_from_ipv6(const struct sockaddr_in6 *restrict ip6, struct sockaddr_in *restrict ip4)
2564{
2565 int i;
2566
2567 if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x02", 2))
2568 {
2569 /* 6to4 and similar */
2570 memcpy(&ip4->sin_addr, ip6->sin6_addr.s6_addr + 2, 4);
2571 }
2572 else if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x01\x00\x00", 4))
2573 {
2574 /* Teredo */
2575 for (i = 0; i < 4; i++)
2576 ((uint8_t *)&ip4->sin_addr)[i] = 0xFF ^
2577 ip6->sin6_addr.s6_addr[12 + i];
2578 }
2579 else
2580 return 0;
2581 SET_SS_LEN(ip4, sizeof(struct sockaddr_in));
2582 ip4->sin_family = AF_INET;
2583 ip4->sin_port = 0;
2584 return 1;
2585}