]> jfr.im git - solanum.git/blame - librb/src/commio.c
Revert "Accept expired certificates"
[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>
db137867 31#include <sys/uio.h>
db137867
AC
32#define HAVE_SSL 1
33
34#ifndef MSG_NOSIGNAL
35#define MSG_NOSIGNAL 0
36#endif
37
38
39struct timeout_data
40{
41 rb_fde_t *F;
42 rb_dlink_node node;
43 time_t timeout;
44 PF *timeout_handler;
45 void *timeout_data;
46};
47
48rb_dlink_list *rb_fd_table;
49static rb_bh *fd_heap;
50
51static rb_dlink_list timeout_list;
52static rb_dlink_list closed_list;
53
59ea3c67
EK
54struct defer
55{
56 rb_dlink_node node;
57 void (*fn)(void *);
58 void *data;
59};
60static rb_dlink_list defer_list;
61
db137867
AC
62static struct ev_entry *rb_timeout_ev;
63
64
65static const char *rb_err_str[] = { "Comm OK", "Error during bind()",
66 "Error during DNS lookup", "connect timeout",
67 "Error during connect()",
3cbcc111
JT
68 "Comm Error",
69 "Error with SSL"
db137867
AC
70};
71
72/* Highest FD and number of open FDs .. */
73static int number_fd = 0;
3202e249 74int rb_maxconnections = 0;
db137867
AC
75
76static PF rb_connect_timeout;
589dbf4d 77static PF rb_connect_outcome;
db137867 78static void mangle_mapped_sockaddr(struct sockaddr *in);
db137867 79
db137867 80static inline rb_fde_t *
8f0c3422 81add_fd(int fd)
db137867
AC
82{
83 rb_fde_t *F = rb_find_fd(fd);
db137867
AC
84
85 /* look up to see if we have it already */
86 if(F != NULL)
3202e249
VY
87 return F;
88
db137867
AC
89 F = rb_bh_alloc(fd_heap);
90 F->fd = fd;
a9fb3ed0 91 rb_dlinkAdd(F, &F->node, &rb_fd_table[rb_hash_fd(fd)]);
3202e249 92 return (F);
db137867
AC
93}
94
95static inline void
96remove_fd(rb_fde_t *F)
97{
db137867
AC
98 if(F == NULL || !IsFDOpen(F))
99 return;
3202e249 100
a9fb3ed0 101 rb_dlinkMoveNode(&F->node, &rb_fd_table[rb_hash_fd(F->fd)], &closed_list);
db137867
AC
102}
103
ad2421c7
AC
104void
105rb_close_pending_fds(void)
db137867
AC
106{
107 rb_fde_t *F;
108 rb_dlink_node *ptr, *next;
109 RB_DLINK_FOREACH_SAFE(ptr, next, closed_list.head)
110 {
111 F = ptr->data;
ff0414c8
SA
112
113 number_fd--;
8f0c3422 114 close(F->fd);
db137867
AC
115 rb_dlinkDelete(ptr, &closed_list);
116 rb_bh_free(fd_heap, F);
117 }
118}
119
db137867
AC
120/* close_all_connections() can be used *before* the system come up! */
121
122static void
123rb_close_all(void)
124{
125 int i;
db137867
AC
126
127 /* XXX someone tell me why we care about 4 fd's ? */
128 /* XXX btw, fd 3 is used for profiler ! */
3202e249 129 for(i = 3; i < rb_maxconnections; ++i)
db137867
AC
130 {
131 close(i);
132 }
db137867
AC
133}
134
135/*
136 * get_sockerr - get the error value from the socket or the current errno
137 *
138 * Get the *real* error from the socket (well try to anyway..).
139 * This may only work when SO_DEBUG is enabled but its worth the
140 * gamble anyway.
141 */
142int
143rb_get_sockerr(rb_fde_t *F)
144{
145 int errtmp;
146 int err = 0;
147 rb_socklen_t len = sizeof(err);
148
149 if(!(F->type & RB_FD_SOCKET))
150 return errno;
db137867
AC
151 errtmp = errno;
152
153#ifdef SO_ERROR
3202e249
VY
154 if(F != NULL
155 && !getsockopt(rb_get_fd(F), SOL_SOCKET, SO_ERROR, (char *)&err, (rb_socklen_t *) & len))
db137867
AC
156 {
157 if(err)
158 errtmp = err;
159 }
160 errno = errtmp;
161#endif
162 return errtmp;
163}
164
165/*
166 * rb_getmaxconnect - return the max number of connections allowed
167 */
168int
169rb_getmaxconnect(void)
170{
3202e249 171 return (rb_maxconnections);
db137867
AC
172}
173
174/*
175 * set_sock_buffers - set send and receive buffers for socket
55abcbb2 176 *
db137867
AC
177 * inputs - fd file descriptor
178 * - size to set
179 * output - returns true (1) if successful, false (0) otherwise
180 * side effects -
181 */
182int
183rb_set_buffers(rb_fde_t *F, int size)
184{
185 if(F == NULL)
186 return 0;
187 if(setsockopt
3202e249
VY
188 (F->fd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
189 || setsockopt(F->fd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
db137867
AC
190 return 0;
191 return 1;
192}
193
194/*
55abcbb2 195 * set_non_blocking - Set the client connection into non-blocking mode.
db137867
AC
196 *
197 * inputs - fd to set into non blocking mode
198 * output - 1 if successful 0 if not
199 * side effects - use POSIX compliant non blocking and
200 * be done with it.
201 */
202int
203rb_set_nb(rb_fde_t *F)
204{
205 int nonb = 0;
206 int res;
8f0c3422 207 int fd;
db137867
AC
208 if(F == NULL)
209 return 0;
210 fd = F->fd;
3202e249 211
db137867
AC
212 if((res = rb_setup_fd(F)))
213 return res;
214#ifdef O_NONBLOCK
215 nonb |= O_NONBLOCK;
216 res = fcntl(fd, F_GETFL, 0);
217 if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
218 return 0;
219#else
220 nonb = 1;
221 res = 0;
222 if(ioctl(fd, FIONBIO, (char *)&nonb) == -1)
223 return 0;
224#endif
225
226 return 1;
227}
228
34a2afbc
DF
229int
230rb_set_cloexec(rb_fde_t *F)
231{
34a2afbc 232 int res;
8f0c3422 233 int fd;
34a2afbc
DF
234 if(F == NULL)
235 return 0;
236 fd = F->fd;
237
238 res = fcntl(fd, F_GETFD, NULL);
239 if(res == -1)
240 return 0;
241 if(fcntl(fd, F_SETFD, res | FD_CLOEXEC) == -1)
242 return 0;
243
244 return 1;
34a2afbc
DF
245}
246
247int
248rb_clear_cloexec(rb_fde_t *F)
249{
34a2afbc 250 int res;
8f0c3422 251 int fd;
34a2afbc
DF
252 if(F == NULL)
253 return 0;
254 fd = F->fd;
255
256 res = fcntl(fd, F_GETFD, NULL);
257 if(res == -1)
258 return 0;
259 if(fcntl(fd, F_SETFD, res & ~FD_CLOEXEC) == -1)
260 return 0;
261
262 return 1;
34a2afbc
DF
263}
264
db137867
AC
265/*
266 * rb_settimeout() - set the socket timeout
267 *
268 * Set the timeout for the fd
269 */
270void
271rb_settimeout(rb_fde_t *F, time_t timeout, PF * callback, void *cbdata)
272{
273 struct timeout_data *td;
274
275 if(F == NULL)
276 return;
277
278 lrb_assert(IsFDOpen(F));
279 td = F->timeout;
3202e249 280 if(callback == NULL) /* user wants to remove */
db137867
AC
281 {
282 if(td == NULL)
283 return;
284 rb_dlinkDelete(&td->node, &timeout_list);
285 rb_free(td);
286 F->timeout = NULL;
3202e249 287 if(rb_dlink_list_length(&timeout_list) == 0)
db137867
AC
288 {
289 rb_event_delete(rb_timeout_ev);
290 rb_timeout_ev = NULL;
291 }
292 return;
293 }
294
295 if(F->timeout == NULL)
3202e249
VY
296 td = F->timeout = rb_malloc(sizeof(struct timeout_data));
297
db137867
AC
298 td->F = F;
299 td->timeout = rb_current_time() + timeout;
300 td->timeout_handler = callback;
301 td->timeout_data = cbdata;
302 rb_dlinkAdd(td, &td->node, &timeout_list);
303 if(rb_timeout_ev == NULL)
304 {
3202e249 305 rb_timeout_ev = rb_event_add("rb_checktimeouts", rb_checktimeouts, NULL, 5);
db137867
AC
306 }
307}
308
309/*
310 * rb_checktimeouts() - check the socket timeouts
311 *
312 * All this routine does is call the given callback/cbdata, without closing
313 * down the file descriptor. When close handlers have been implemented,
314 * this will happen.
315 */
316void
8679c0fe 317rb_checktimeouts(void *notused __attribute__((unused)))
db137867
AC
318{
319 rb_dlink_node *ptr, *next;
320 struct timeout_data *td;
321 rb_fde_t *F;
322 PF *hdl;
323 void *data;
324
325 RB_DLINK_FOREACH_SAFE(ptr, next, timeout_list.head)
326 {
327 td = ptr->data;
328 F = td->F;
329 if(F == NULL || !IsFDOpen(F))
330 continue;
331
332 if(td->timeout < rb_current_time())
333 {
334 hdl = td->timeout_handler;
335 data = td->timeout_data;
336 rb_dlinkDelete(&td->node, &timeout_list);
337 F->timeout = NULL;
338 rb_free(td);
339 hdl(F, data);
3202e249 340 }
db137867
AC
341 }
342}
343
c6ad9b0c
SA
344static int
345rb_setsockopt_reuseaddr(rb_fde_t *F)
346{
347 int opt_one = 1;
348 int ret;
349
350 ret = setsockopt(F->fd, SOL_SOCKET, SO_REUSEADDR, &opt_one, sizeof(opt_one));
351 if (ret) {
352 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
353 F->fd, strerror(rb_get_sockerr(F)));
354 return ret;
355 }
356
357 return 0;
358}
359
360#ifdef HAVE_LIBSCTP
361static int
362rb_setsockopt_sctp(rb_fde_t *F)
363{
364 int opt_zero = 0;
365 int opt_one = 1;
268044ea
SA
366 /* workaround for https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sctp?id=299ee123e19889d511092347f5fc14db0f10e3a6 */
367 char *env_mapped = getenv("SCTP_I_WANT_MAPPED_V4_ADDR");
368 int opt_mapped = env_mapped != NULL ? atoi(env_mapped) : opt_zero;
c6ad9b0c
SA
369 int ret;
370 struct sctp_initmsg initmsg;
371 struct sctp_rtoinfo rtoinfo;
372 struct sctp_paddrparams paddrparams;
373 struct sctp_assocparams assocparams;
374
1b64bfa0 375 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_NODELAY, &opt_one, sizeof(opt_one));
c6ad9b0c
SA
376 if (ret) {
377 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
378 F->fd, strerror(rb_get_sockerr(F)));
379 return ret;
380 }
381
1b64bfa0 382 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &opt_mapped, sizeof(opt_mapped));
c6ad9b0c
SA
383 if (ret) {
384 rb_lib_log("rb_setsockopt_sctp: Cannot unset SCTP_I_WANT_MAPPED_V4_ADDR for fd %d: %s",
385 F->fd, strerror(rb_get_sockerr(F)));
386 return ret;
387 }
388
389 /* Configure INIT message to specify that we only want one stream */
390 memset(&initmsg, 0, sizeof(initmsg));
391 initmsg.sinit_num_ostreams = 1;
392 initmsg.sinit_max_instreams = 1;
393
1b64bfa0 394 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
c6ad9b0c
SA
395 if (ret) {
396 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
397 F->fd, strerror(rb_get_sockerr(F)));
398 return ret;
399 }
400
401 /* Configure RTO values to reduce the maximum timeout */
402 memset(&rtoinfo, 0, sizeof(rtoinfo));
403 rtoinfo.srto_initial = 3000;
404 rtoinfo.srto_min = 1000;
405 rtoinfo.srto_max = 10000;
406
1b64bfa0 407 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo));
c6ad9b0c
SA
408 if (ret) {
409 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
410 F->fd, strerror(rb_get_sockerr(F)));
411 return ret;
412 }
413
414 /*
415 * Configure peer address parameters to ensure that we monitor the connection
416 * more often than the default and don't timeout retransmit attempts before
417 * the ping timeout does.
418 *
419 * Each peer address will timeout reachability in about 750s.
420 */
421 memset(&paddrparams, 0, sizeof(paddrparams));
422 paddrparams.spp_assoc_id = 0;
423 memcpy(&paddrparams.spp_address, &in6addr_any, sizeof(in6addr_any));
424 paddrparams.spp_pathmaxrxt = 50;
425 paddrparams.spp_hbinterval = 5000;
426 paddrparams.spp_flags |= SPP_HB_ENABLE;
427
1b64bfa0 428 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams));
c6ad9b0c
SA
429 if (ret) {
430 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_PEER_ADDR_PARAMS for fd %d: %s",
431 F->fd, strerror(rb_get_sockerr(F)));
432 return ret;
433 }
434
435 /* Configure association parameters for retransmit attempts as above */
436 memset(&assocparams, 0, sizeof(assocparams));
437 assocparams.sasoc_assoc_id = 0;
438 assocparams.sasoc_asocmaxrxt = 50;
439
1b64bfa0 440 ret = setsockopt(F->fd, IPPROTO_SCTP, SCTP_ASSOCINFO, &assocparams, sizeof(assocparams));
c6ad9b0c
SA
441 if (ret) {
442 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
443 F->fd, strerror(rb_get_sockerr(F)));
444 return ret;
445 }
446
447 return 0;
448}
449#endif
450
451int
452rb_bind(rb_fde_t *F, struct sockaddr *addr)
453{
454 int ret;
455
456 ret = rb_setsockopt_reuseaddr(F);
457 if (ret)
458 return ret;
459
460 ret = bind(F->fd, addr, GET_SS_LEN(addr));
461 if (ret)
462 return ret;
463
464 return 0;
465}
466
6003ce76
SA
467#ifdef HAVE_LIBSCTP
468static int
469rb_sctp_bindx_only(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
470{
471 int ret;
472
473 for (size_t i = 0; i < len; i++) {
474 if (GET_SS_FAMILY(&addrs[i]) == AF_UNSPEC)
475 continue;
476
477 ret = sctp_bindx(F->fd, (struct sockaddr *)&addrs[i], 1, SCTP_BINDX_ADD_ADDR);
478 if (ret)
479 return ret;
480 }
481
482 return 0;
483}
484#endif
485
c6ad9b0c
SA
486int
487rb_sctp_bindx(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
488{
489#ifdef HAVE_LIBSCTP
490 int ret;
491
492 if ((F->type & RB_FD_SCTP) == 0)
493 return -1;
494
495 ret = rb_setsockopt_reuseaddr(F);
496 if (ret)
497 return ret;
498
6003ce76
SA
499 ret = rb_sctp_bindx_only(F, addrs, len);
500 if (ret)
501 return ret;
c6ad9b0c
SA
502
503 return 0;
504#else
505 return -1;
506#endif
507}
508
509int
510rb_inet_get_proto(rb_fde_t *F)
db137867 511{
c6ad9b0c
SA
512#ifdef HAVE_LIBSCTP
513 if (F->type & RB_FD_SCTP)
514 return IPPROTO_SCTP;
515#endif
516 return IPPROTO_TCP;
517}
518
8679c0fe 519static void rb_accept_tryaccept(rb_fde_t *F, void *data __attribute__((unused))) {
db137867
AC
520 struct rb_sockaddr_storage st;
521 rb_fde_t *new_F;
b0adc7bf 522 rb_socklen_t addrlen;
db137867
AC
523 int new_fd;
524
525 while(1)
526 {
b0adc7bf
SA
527 memset(&st, 0, sizeof(st));
528 addrlen = sizeof(st);
529
db137867 530 new_fd = accept(F->fd, (struct sockaddr *)&st, &addrlen);
db137867
AC
531 if(new_fd < 0)
532 {
533 rb_setselect(F, RB_SELECT_ACCEPT, rb_accept_tryaccept, NULL);
534 return;
535 }
536
c6ad9b0c 537 new_F = rb_open(new_fd, RB_FD_SOCKET | (F->type & RB_FD_INHERIT_TYPES), "Incoming Connection");
db137867 538
a9fb3ed0
VY
539 if(new_F == NULL)
540 {
3202e249 541 rb_lib_log
c6ad9b0c 542 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
3202e249 543 new_fd);
a9fb3ed0
VY
544 close(new_fd);
545 continue;
546 }
547
c2ac22cc 548 if(rb_unlikely(!rb_set_nb(new_F)))
db137867 549 {
db137867
AC
550 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F->fd);
551 rb_close(new_F);
552 }
553
db137867 554 mangle_mapped_sockaddr((struct sockaddr *)&st);
3202e249 555
db137867
AC
556 if(F->accept->precb != NULL)
557 {
3202e249 558 if(!F->accept->precb(new_F, (struct sockaddr *)&st, addrlen, F->accept->data)) /* pre-callback decided to drop it */
db137867
AC
559 continue;
560 }
561#ifdef HAVE_SSL
562 if(F->type & RB_FD_SSL)
563 {
a9fb3ed0 564 rb_ssl_accept_setup(F, new_F, (struct sockaddr *)&st, addrlen);
3202e249 565 }
db137867 566 else
3202e249 567#endif /* HAVE_SSL */
db137867 568 {
3202e249
VY
569 F->accept->callback(new_F, RB_OK, (struct sockaddr *)&st, addrlen,
570 F->accept->data);
db137867
AC
571 }
572 }
573
574}
575
576/* try to accept a TCP connection */
577void
3202e249 578rb_accept_tcp(rb_fde_t *F, ACPRE * precb, ACCB * callback, void *data)
db137867
AC
579{
580 if(F == NULL)
581 return;
582 lrb_assert(callback);
583
584 F->accept = rb_malloc(sizeof(struct acceptdata));
585 F->accept->callback = callback;
586 F->accept->data = data;
587 F->accept->precb = precb;
588 rb_accept_tryaccept(F, NULL);
589}
590
591/*
8f0c3422 592 * void rb_connect_tcp(int fd, struct sockaddr *dest,
5ad62c80 593 * struct sockaddr *clocal,
db137867
AC
594 * CNCB *callback, void *data, int timeout)
595 * Input: An fd to connect with, a host and port to connect to,
5ad62c80 596 * a local sockaddr to connect from (or NULL to use the
db137867
AC
597 * default), a callback, the data to pass into the callback, the
598 * address family.
599 * Output: None.
600 * Side-effects: A non-blocking connection to the host is started, and
601 * if necessary, set up for selection. The callback given
602 * may be called now, or it may be called later.
603 */
604void
605rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
5ad62c80 606 struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
db137867 607{
589dbf4d
SA
608 int retval;
609
610 if (F == NULL)
db137867 611 return;
3202e249 612
db137867
AC
613 lrb_assert(callback);
614 F->connect = rb_malloc(sizeof(struct conndata));
615 F->connect->callback = callback;
616 F->connect->data = data;
617
618 memcpy(&F->connect->hostaddr, dest, sizeof(F->connect->hostaddr));
619
620 /* Note that we're using a passed sockaddr here. This is because
621 * generally you'll be bind()ing to a sockaddr grabbed from
622 * getsockname(), so this makes things easier.
623 * XXX If NULL is passed as local, we should later on bind() to the
624 * virtual host IP, for completeness.
625 * -- adrian
626 */
5ad62c80 627 if((clocal != NULL) && (bind(F->fd, clocal, GET_SS_LEN(clocal)) < 0))
db137867
AC
628 {
629 /* Failure, call the callback with RB_ERR_BIND */
630 rb_connect_callback(F, RB_ERR_BIND);
631 /* ... and quit */
632 return;
633 }
634
635 /* We have a valid IP, so we just call tryconnect */
636 /* Make sure we actually set the timeout here .. */
637 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
db137867 638
589dbf4d
SA
639 retval = connect(F->fd,
640 (struct sockaddr *)&F->connect->hostaddr,
641 GET_SS_LEN(&F->connect->hostaddr));
642 /* Error? */
643 if (retval < 0) {
644 /*
645 * If we get EISCONN, then we've already connect()ed the socket,
646 * which is a good thing.
647 * -- adrian
648 */
589dbf4d
SA
649 if (errno == EISCONN) {
650 rb_connect_callback(F, RB_OK);
651 } else if (rb_ignore_errno(errno)) {
652 /* Ignore error? Reschedule */
653 rb_setselect(F, RB_SELECT_CONNECT, rb_connect_outcome, NULL);
654 } else {
655 /* Error? Fail with RB_ERR_CONNECT */
656 rb_connect_callback(F, RB_ERR_CONNECT);
657 }
658 return;
659 }
660 /* If we get here, we've succeeded, so call with RB_OK */
661 rb_connect_callback(F, RB_OK);
662}
db137867 663
6003ce76
SA
664void
665rb_connect_sctp(rb_fde_t *F, struct sockaddr_storage *dest, size_t dest_len,
666 struct sockaddr_storage *clocal, size_t clocal_len,
667 CNCB *callback, void *data, int timeout)
668{
669#ifdef HAVE_LIBSCTP
670 uint8_t packed_dest[sizeof(struct sockaddr_storage) * dest_len];
671 uint8_t *p = &packed_dest[0];
672 size_t n = 0;
673 int retval;
674
675 if (F == NULL)
676 return;
677
678 lrb_assert(callback);
679 F->connect = rb_malloc(sizeof(struct conndata));
680 F->connect->callback = callback;
681 F->connect->data = data;
682
683 if ((F->type & RB_FD_SCTP) == 0) {
684 rb_connect_callback(F, RB_ERR_CONNECT);
685 return;
686 }
687
688 for (size_t i = 0; i < dest_len; i++) {
689 if (GET_SS_FAMILY(&dest[i]) == AF_INET6) {
690 memcpy(p, &dest[i], sizeof(struct sockaddr_in6));
691 n++;
692 p += sizeof(struct sockaddr_in6);
693 } else if (GET_SS_FAMILY(&dest[i]) == AF_INET) {
694 memcpy(p, &dest[i], sizeof(struct sockaddr_in));
695 n++;
696 p += sizeof(struct sockaddr_in);
697 }
698 }
699 dest_len = n;
700
701 memcpy(&F->connect->hostaddr, &dest[0], sizeof(F->connect->hostaddr));
702
703 if ((clocal_len > 0) && (rb_sctp_bindx_only(F, clocal, clocal_len) < 0)) {
704 /* Failure, call the callback with RB_ERR_BIND */
705 rb_connect_callback(F, RB_ERR_BIND);
706 /* ... and quit */
707 return;
708 }
709
710 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
711
712 retval = sctp_connectx(F->fd, (struct sockaddr *)packed_dest, dest_len, NULL);
713 /* Error? */
714 if (retval < 0) {
715 /*
716 * If we get EISCONN, then we've already connect()ed the socket,
717 * which is a good thing.
718 * -- adrian
719 */
6003ce76
SA
720 if (errno == EISCONN) {
721 rb_connect_callback(F, RB_OK);
722 } else if (rb_ignore_errno(errno)) {
723 /* Ignore error? Reschedule */
724 rb_setselect(F, RB_SELECT_CONNECT, rb_connect_outcome, NULL);
725 } else {
726 /* Error? Fail with RB_ERR_CONNECT */
727 rb_connect_callback(F, RB_ERR_CONNECT);
728 }
729 return;
730 }
731 /* If we get here, we've succeeded, so call with RB_OK */
732 rb_connect_callback(F, RB_OK);
733#else
734 rb_connect_callback(F, RB_ERR_CONNECT);
735#endif
736}
737
db137867
AC
738/*
739 * rb_connect_callback() - call the callback, and continue with life
740 */
741void
742rb_connect_callback(rb_fde_t *F, int status)
743{
744 CNCB *hdl;
745 void *data;
3202e249 746 int errtmp = errno; /* save errno as rb_settimeout clobbers it sometimes */
db137867
AC
747
748 /* This check is gross..but probably necessary */
749 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
750 return;
751 /* Clear the connect flag + handler */
752 hdl = F->connect->callback;
753 data = F->connect->data;
754 F->connect->callback = NULL;
755
aec4c3cb 756
db137867
AC
757 /* Clear the timeout handler */
758 rb_settimeout(F, 0, NULL, NULL);
3202e249 759 errno = errtmp;
db137867
AC
760 /* Call the handler */
761 hdl(F, status, data);
762}
763
764
765/*
766 * rb_connect_timeout() - this gets called when the socket connection
767 * times out. This *only* can be called once connect() is initially
768 * called ..
769 */
770static void
8679c0fe 771rb_connect_timeout(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
772{
773 /* error! */
774 rb_connect_callback(F, RB_ERR_TIMEOUT);
775}
776
db137867 777static void
8679c0fe 778rb_connect_outcome(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
779{
780 int retval;
589dbf4d
SA
781 int err = 0;
782 socklen_t len = sizeof(err);
db137867
AC
783
784 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
785 return;
589dbf4d 786 retval = getsockopt(F->fd, SOL_SOCKET, SO_ERROR, &err, &len);
8f0c3422 787 if ((retval >= 0) && (err != 0)) {
589dbf4d
SA
788 errno = err;
789 retval = -1;
790 }
791 if (retval < 0) {
792 /* Error? Fail with RB_ERR_CONNECT */
793 rb_connect_callback(F, RB_ERR_CONNECT);
db137867
AC
794 return;
795 }
589dbf4d 796 /* If we get here, we've succeeded, so call with RB_OK */
db137867
AC
797 rb_connect_callback(F, RB_OK);
798}
799
800
801int
802rb_connect_sockaddr(rb_fde_t *F, struct sockaddr *addr, int len)
803{
804 if(F == NULL)
805 return 0;
806
807 memcpy(addr, &F->connect->hostaddr, len);
808 return 1;
809}
810
811/*
812 * rb_error_str() - return an error string for the given error condition
813 */
814const char *
815rb_errstr(int error)
816{
817 if(error < 0 || error >= RB_ERR_MAX)
818 return "Invalid error number!";
819 return rb_err_str[error];
820}
821
822
823int
824rb_socketpair(int family, int sock_type, int proto, rb_fde_t **F1, rb_fde_t **F2, const char *note)
825{
8f0c3422 826 int nfd[2];
db137867
AC
827 if(number_fd >= rb_maxconnections)
828 {
829 errno = ENFILE;
830 return -1;
831 }
832
db137867 833 if(socketpair(family, sock_type, proto, nfd))
db137867
AC
834 return -1;
835
db137867
AC
836 *F1 = rb_open(nfd[0], RB_FD_SOCKET, note);
837 *F2 = rb_open(nfd[1], RB_FD_SOCKET, note);
838
839 if(*F1 == NULL)
840 {
841 if(*F2 != NULL)
842 rb_close(*F2);
843 return -1;
844 }
845
846 if(*F2 == NULL)
847 {
848 rb_close(*F1);
849 return -1;
850 }
851
852 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 853 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
854 {
855 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[0], strerror(errno));
856 rb_close(*F1);
857 rb_close(*F2);
858 return -1;
859 }
860
c2ac22cc 861 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
862 {
863 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[1], strerror(errno));
864 rb_close(*F1);
865 rb_close(*F2);
866 return -1;
867 }
868
869 return 0;
870}
871
872
873int
874rb_pipe(rb_fde_t **F1, rb_fde_t **F2, const char *desc)
875{
8f0c3422 876 int fd[2];
db137867
AC
877 if(number_fd >= rb_maxconnections)
878 {
879 errno = ENFILE;
880 return -1;
881 }
882 if(pipe(fd) == -1)
883 return -1;
db137867
AC
884 *F1 = rb_open(fd[0], RB_FD_PIPE, desc);
885 *F2 = rb_open(fd[1], RB_FD_PIPE, desc);
886
c2ac22cc 887 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
888 {
889 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[0], strerror(errno));
890 rb_close(*F1);
891 rb_close(*F2);
892 return -1;
893 }
894
c2ac22cc 895 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
896 {
897 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[1], strerror(errno));
898 rb_close(*F1);
899 rb_close(*F2);
900 return -1;
901 }
902
903
904 return 0;
db137867
AC
905}
906
907/*
908 * rb_socket() - open a socket
909 *
910 * This is a highly highly cut down version of squid's rb_open() which
911 * for the most part emulates socket(), *EXCEPT* it fails if we're about
912 * to run out of file descriptors.
913 */
914rb_fde_t *
915rb_socket(int family, int sock_type, int proto, const char *note)
916{
917 rb_fde_t *F;
8f0c3422 918 int fd;
db137867 919 /* First, make sure we aren't going to run out of file descriptors */
c2ac22cc 920 if(rb_unlikely(number_fd >= rb_maxconnections))
db137867
AC
921 {
922 errno = ENFILE;
923 return NULL;
924 }
925
926 /*
927 * Next, we try to open the socket. We *should* drop the reserved FD
928 * limit if/when we get an error, but we can deal with that later.
929 * XXX !!! -- adrian
930 */
931 fd = socket(family, sock_type, proto);
c2ac22cc 932 if(rb_unlikely(fd < 0))
db137867
AC
933 return NULL; /* errno will be passed through, yay.. */
934
55abcbb2 935 /*
db137867 936 * Make sure we can take both IPv4 and IPv6 connections
c6ad9b0c 937 * on an AF_INET6 SCTP socket, otherwise keep them separate
db137867
AC
938 */
939 if(family == AF_INET6)
940 {
c6ad9b0c
SA
941#ifdef HAVE_LIBSCTP
942 int v6only = (proto == IPPROTO_SCTP) ? 0 : 1;
943#else
944 int v6only = 1;
945#endif
946 if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)) == -1)
db137867 947 {
c6ad9b0c
SA
948 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
949 v6only, fd, strerror(errno));
db137867
AC
950 close(fd);
951 return NULL;
952 }
953 }
db137867
AC
954
955 F = rb_open(fd, RB_FD_SOCKET, note);
956 if(F == NULL)
a9fb3ed0 957 {
3202e249
VY
958 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd,
959 strerror(errno));
a9fb3ed0 960 close(fd);
db137867 961 return NULL;
a9fb3ed0 962 }
c6ad9b0c
SA
963
964#ifdef HAVE_LIBSCTP
965 if (proto == IPPROTO_SCTP) {
966 F->type |= RB_FD_SCTP;
967
968 if (rb_setsockopt_sctp(F)) {
969 rb_lib_log("rb_socket: Could not set SCTP socket options on FD %d: %s",
970 fd, strerror(errno));
971 close(fd);
972 return NULL;
973 }
974 }
975#endif
976
db137867 977 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 978 if(rb_unlikely(!rb_set_nb(F)))
db137867
AC
979 {
980 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
981 rb_close(F);
982 return NULL;
983 }
984
985 return F;
986}
987
988/*
989 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
990 * socket manged the sockaddr.
991 */
db137867
AC
992static void
993mangle_mapped_sockaddr(struct sockaddr *in)
994{
3202e249 995 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
db137867 996
db137867
AC
997 if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
998 {
999 struct sockaddr_in in4;
1000 memset(&in4, 0, sizeof(struct sockaddr_in));
1001 in4.sin_family = AF_INET;
1002 in4.sin_port = in6->sin6_port;
3202e249 1003 in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
db137867
AC
1004 memcpy(in, &in4, sizeof(struct sockaddr_in));
1005 }
db137867 1006}
db137867
AC
1007
1008/*
1009 * rb_listen() - listen on a port
1010 */
1011int
aa4737a0 1012rb_listen(rb_fde_t *F, int backlog, int defer_accept)
db137867 1013{
77cb59b3
AC
1014 int result;
1015
c6ad9b0c 1016 F->type = RB_FD_SOCKET | RB_FD_LISTEN | (F->type & RB_FD_INHERIT_TYPES);
77cb59b3
AC
1017 result = listen(F->fd, backlog);
1018
1019#ifdef TCP_DEFER_ACCEPT
aa4737a0 1020 if (defer_accept && !result)
77cb59b3 1021 {
e053adc8 1022 (void)setsockopt(F->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(int));
77cb59b3
AC
1023 }
1024#endif
797a29f3
JT
1025#ifdef SO_ACCEPTFILTER
1026 if (defer_accept && !result)
1027 {
1028 struct accept_filter_arg afa;
1029
1030 memset(&afa, '\0', sizeof afa);
1031 rb_strlcpy(afa.af_name, "dataready", sizeof afa.af_name);
1032 (void)setsockopt(F->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa,
1033 sizeof afa);
1034 }
1035#endif
77cb59b3
AC
1036
1037 return result;
db137867
AC
1038}
1039
1040void
1041rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
1042{
1043 static int initialized = 0;
db137867 1044
db137867
AC
1045 if(!initialized)
1046 {
1047 rb_maxconnections = maxfds;
1048 if(closeall)
1049 rb_close_all();
1050 /* Since we're doing this once .. */
1051 initialized = 1;
1052 }
1053 fd_heap = rb_bh_create(sizeof(rb_fde_t), heapsize, "librb_fd_heap");
1054
1055}
1056
1057
1058/* Called to open a given filedescriptor */
1059rb_fde_t *
8f0c3422 1060rb_open(int fd, uint8_t type, const char *desc)
db137867 1061{
a9fb3ed0 1062 rb_fde_t *F;
db137867
AC
1063 lrb_assert(fd >= 0);
1064
a9fb3ed0
VY
1065 F = add_fd(fd);
1066
1067 lrb_assert(!IsFDOpen(F));
c2ac22cc 1068 if(rb_unlikely(IsFDOpen(F)))
db137867 1069 {
a9fb3ed0
VY
1070 const char *fdesc;
1071 if(F != NULL && F->desc != NULL)
1072 fdesc = F->desc;
1073 else
1074 fdesc = "NULL";
3202e249 1075 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd, fdesc);
db137867
AC
1076 return NULL;
1077 }
db137867
AC
1078 F->fd = fd;
1079 F->type = type;
1080 SetFDOpen(F);
1081
1082 if(desc != NULL)
1083 F->desc = rb_strndup(desc, FD_DESC_SZ);
1084 number_fd++;
1085 return F;
1086}
1087
1088
1089/* Called to close a given filedescriptor */
1090void
1091rb_close(rb_fde_t *F)
1092{
1093 int type, fd;
3202e249 1094
db137867
AC
1095 if(F == NULL)
1096 return;
1097
1098 fd = F->fd;
3202e249 1099 type = F->type;
db137867
AC
1100 lrb_assert(IsFDOpen(F));
1101
1102 lrb_assert(!(type & RB_FD_FILE));
c2ac22cc 1103 if(rb_unlikely(type & RB_FD_FILE))
db137867
AC
1104 {
1105 lrb_assert(F->read_handler == NULL);
1106 lrb_assert(F->write_handler == NULL);
1107 }
c6ad9b0c
SA
1108
1109 if (type & RB_FD_LISTEN) {
1110 listen(F->fd, 0);
1111 }
1112
db137867
AC
1113 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
1114 rb_settimeout(F, 0, NULL, NULL);
1115 rb_free(F->accept);
1116 rb_free(F->connect);
1117 rb_free(F->desc);
1118#ifdef HAVE_SSL
1119 if(type & RB_FD_SSL)
1120 {
1121 rb_ssl_shutdown(F);
1122 }
1123#endif /* HAVE_SSL */
1124 if(IsFDOpen(F))
1125 {
1126 remove_fd(F);
1127 ClearFDOpen(F);
1128 }
8a29e7cd
SA
1129
1130 if(type & RB_FD_LISTEN)
1131 shutdown(fd, SHUT_RDWR);
db137867
AC
1132}
1133
1134
1135/*
1136 * rb_dump_fd() - dump the list of active filedescriptors
1137 */
1138void
1139rb_dump_fd(DUMPCB * cb, void *data)
1140{
1141 static const char *empty = "";
1142 rb_dlink_node *ptr;
1143 rb_dlink_list *bucket;
1144 rb_fde_t *F;
1145 unsigned int i;
1146
1147 for(i = 0; i < RB_FD_HASH_SIZE; i++)
1148 {
1149 bucket = &rb_fd_table[i];
1150
1151 if(rb_dlink_list_length(bucket) <= 0)
1152 continue;
1153
1154 RB_DLINK_FOREACH(ptr, bucket->head)
1155 {
1156 F = ptr->data;
1157 if(F == NULL || !IsFDOpen(F))
1158 continue;
1159
1160 cb(F->fd, F->desc ? F->desc : empty, data);
1161 }
1162 }
1163}
1164
1165/*
1166 * rb_note() - set the fd note
1167 *
1168 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1169 * calling.
1170 */
1171void
1172rb_note(rb_fde_t *F, const char *string)
1173{
1174 if(F == NULL)
1175 return;
1176
1177 rb_free(F->desc);
1178 F->desc = rb_strndup(string, FD_DESC_SZ);
1179}
1180
1181void
a9fb3ed0 1182rb_set_type(rb_fde_t *F, uint8_t type)
db137867
AC
1183{
1184 /* if the caller is calling this, lets assume they have a clue */
1185 F->type = type;
1186 return;
1187}
1188
a9fb3ed0 1189uint8_t
db137867
AC
1190rb_get_type(rb_fde_t *F)
1191{
1192 return F->type;
1193}
1194
3202e249 1195int
db137867
AC
1196rb_fd_ssl(rb_fde_t *F)
1197{
1198 if(F == NULL)
1199 return 0;
1200 if(F->type & RB_FD_SSL)
1201 return 1;
1202 return 0;
1203}
1204
8f0c3422 1205int
db137867
AC
1206rb_get_fd(rb_fde_t *F)
1207{
1208 if(F == NULL)
1209 return -1;
3202e249 1210 return (F->fd);
db137867
AC
1211}
1212
1213rb_fde_t *
8f0c3422 1214rb_get_fde(int fd)
db137867
AC
1215{
1216 return rb_find_fd(fd);
1217}
1218
1219ssize_t
1220rb_read(rb_fde_t *F, void *buf, int count)
1221{
ba1721d1 1222 ssize_t ret;
db137867
AC
1223 if(F == NULL)
1224 return 0;
3202e249 1225
55abcbb2
KB
1226 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1227 * an SSL socket as a regular socket
db137867
AC
1228 */
1229#ifdef HAVE_SSL
1230 if(F->type & RB_FD_SSL)
1231 {
1232 return rb_ssl_read(F, buf, count);
3202e249 1233 }
db137867
AC
1234#endif
1235 if(F->type & RB_FD_SOCKET)
1236 {
1237 ret = recv(F->fd, buf, count, 0);
db137867
AC
1238 return ret;
1239 }
1240
1241
1242 /* default case */
1243 return read(F->fd, buf, count);
1244}
1245
1246
1247ssize_t
1248rb_write(rb_fde_t *F, const void *buf, int count)
1249{
ba1721d1 1250 ssize_t ret;
db137867
AC
1251 if(F == NULL)
1252 return 0;
1253
1254#ifdef HAVE_SSL
1255 if(F->type & RB_FD_SSL)
1256 {
1257 return rb_ssl_write(F, buf, count);
3202e249 1258 }
db137867
AC
1259#endif
1260 if(F->type & RB_FD_SOCKET)
1261 {
1262 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
db137867
AC
1263 return ret;
1264 }
1265
1266 return write(F->fd, buf, count);
1267}
1268
3c586ccf 1269#ifdef HAVE_SSL
db137867
AC
1270static ssize_t
1271rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1272{
ba1721d1 1273 ssize_t count = 0;
db137867 1274
3202e249 1275 while(vpcount-- > 0)
db137867 1276 {
ba1721d1 1277 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
db137867 1278
3202e249 1279 if(written <= 0)
db137867
AC
1280 {
1281 if(count > 0)
1282 return count;
1283 else
1284 return written;
1285 }
1286 count += written;
1287 vp++;
1288 }
1289 return (count);
1290}
1291#endif
1292
db137867 1293ssize_t
3202e249 1294rb_writev(rb_fde_t *F, struct rb_iovec * vector, int count)
db137867 1295{
3202e249
VY
1296 if(F == NULL)
1297 {
db137867
AC
1298 errno = EBADF;
1299 return -1;
1300 }
1301#ifdef HAVE_SSL
1302 if(F->type & RB_FD_SSL)
1303 {
3202e249 1304 return rb_fake_writev(F, vector, count);
db137867
AC
1305 }
1306#endif /* HAVE_SSL */
db137867
AC
1307 if(F->type & RB_FD_SOCKET)
1308 {
1309 struct msghdr msg;
1310 memset(&msg, 0, sizeof(msg));
1311 msg.msg_iov = (struct iovec *)vector;
1312 msg.msg_iovlen = count;
1313 return sendmsg(F->fd, &msg, MSG_NOSIGNAL);
3202e249 1314 }
db137867
AC
1315 return writev(F->fd, (struct iovec *)vector, count);
1316
1317}
db137867 1318
55abcbb2 1319/*
db137867
AC
1320 * From: Thomas Helvey <tomh@inxpress.net>
1321 */
1322static const char *IpQuadTab[] = {
1323 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1324 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1325 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1326 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1327 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1328 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1329 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1330 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1331 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1332 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1333 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1334 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1335 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1336 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1337 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1338 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1339 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1340 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1341 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1342 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1343 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1344 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1345 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1346 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1347 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1348 "250", "251", "252", "253", "254", "255"
1349};
1350
1351/*
1352 * inetntoa - in_addr to string
1353 * changed name to remove collision possibility and
1354 * so behaviour is guaranteed to take a pointer arg.
1355 * -avalon 23/11/92
1356 * inet_ntoa -- returned the dotted notation of a given
1357 * internet number
1358 * argv 11/90).
1359 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1360 */
1361
1362static const char *
1363inetntoa(const char *in)
1364{
1365 static char buf[16];
1366 char *bufptr = buf;
3202e249 1367 const unsigned char *a = (const unsigned char *)in;
db137867
AC
1368 const char *n;
1369
1370 n = IpQuadTab[*a++];
3202e249 1371 while(*n)
db137867
AC
1372 *bufptr++ = *n++;
1373 *bufptr++ = '.';
1374 n = IpQuadTab[*a++];
3202e249 1375 while(*n)
db137867
AC
1376 *bufptr++ = *n++;
1377 *bufptr++ = '.';
1378 n = IpQuadTab[*a++];
3202e249 1379 while(*n)
db137867
AC
1380 *bufptr++ = *n++;
1381 *bufptr++ = '.';
1382 n = IpQuadTab[*a];
3202e249 1383 while(*n)
db137867
AC
1384 *bufptr++ = *n++;
1385 *bufptr = '\0';
1386 return buf;
1387}
1388
db137867
AC
1389/*
1390 * WARNING: Don't even consider trying to compile this on a system where
1391 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1392 */
1393
3202e249 1394static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
3202e249 1395static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
db137867
AC
1396
1397/* const char *
1398 * inet_ntop4(src, dst, size)
1399 * format an IPv4 address
1400 * return:
1401 * `dst' (as a const)
1402 * notes:
1403 * (1) uses no statics
1404 * (2) takes a unsigned char* not an in_addr as input
1405 * author:
1406 * Paul Vixie, 1996.
1407 */
1408static const char *
1409inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1410{
1411 if(size < 16)
1412 return NULL;
86510a73 1413 return strcpy(dst, inetntoa((const char *)src));
db137867
AC
1414}
1415
1416/* const char *
1417 * inet_ntop6(src, dst, size)
1418 * convert IPv6 binary address into presentation (printable) format
1419 * author:
1420 * Paul Vixie, 1996.
1421 */
db137867
AC
1422static const char *
1423inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
1424{
1425 /*
1426 * Note that int32_t and int16_t need only be "at least" large enough
1427 * to contain a value of the specified size. On some systems, like
1428 * Crays, there is no such thing as an integer variable with 16 bits.
1429 * Keep this in mind if you think this function should have been coded
1430 * to use pointer overlays. All the world's not a VAX.
1431 */
1432 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
1433 struct
1434 {
1435 int base, len;
1436 }
1437 best, cur;
1438 unsigned int words[IN6ADDRSZ / INT16SZ];
1439 int i;
1440
1441 /*
1442 * Preprocess:
1443 * Copy the input (bytewise) array into a wordwise array.
1444 * Find the longest run of 0x00's in src[] for :: shorthanding.
1445 */
1446 memset(words, '\0', sizeof words);
3202e249 1447 for(i = 0; i < IN6ADDRSZ; i += 2)
db137867
AC
1448 words[i / 2] = (src[i] << 8) | src[i + 1];
1449 best.base = -1;
1450 best.len = 0;
1451 cur.base = -1;
1452 cur.len = 0;
3202e249 1453 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1454 {
1455 if(words[i] == 0)
1456 {
1457 if(cur.base == -1)
1458 cur.base = i, cur.len = 1;
1459 else
1460 cur.len++;
1461 }
1462 else
1463 {
1464 if(cur.base != -1)
1465 {
1466 if(best.base == -1 || cur.len > best.len)
1467 best = cur;
1468 cur.base = -1;
1469 }
1470 }
1471 }
1472 if(cur.base != -1)
1473 {
1474 if(best.base == -1 || cur.len > best.len)
1475 best = cur;
1476 }
1477 if(best.base != -1 && best.len < 2)
1478 best.base = -1;
1479
1480 /*
1481 * Format the result.
1482 */
1483 tp = tmp;
3202e249 1484 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1485 {
1486 /* Are we inside the best run of 0x00's? */
1487 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
1488 {
1489 if(i == best.base)
1490 {
1491 if(i == 0)
1492 *tp++ = '0';
1493 *tp++ = ':';
1494 }
1495 continue;
1496 }
1497 /* Are we following an initial run of 0x00s or any real hex? */
1498 if(i != 0)
1499 *tp++ = ':';
1500 /* Is this address an encapsulated IPv4? */
1501 if(i == 6 && best.base == 0 &&
1502 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
1503 {
1504 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
1505 return (NULL);
1506 tp += strlen(tp);
1507 break;
1508 }
5203cba5 1509 tp += sprintf(tp, "%x", words[i]);
db137867
AC
1510 }
1511 /* Was it a trailing run of 0x00's? */
1512 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
1513 *tp++ = ':';
1514 *tp++ = '\0';
1515
1516 /*
1517 * Check for overflow, copy, and we're done.
1518 */
1519
3202e249 1520 if((unsigned int)(tp - tmp) > size)
db137867
AC
1521 {
1522 return (NULL);
1523 }
86510a73 1524 return memcpy(dst, tmp, tp - tmp);
db137867 1525}
db137867
AC
1526
1527int
17809d2d 1528rb_inet_pton_sock(const char *src, struct sockaddr_storage *dst)
db137867 1529{
9caecc93 1530 memset(dst, 0, sizeof(*dst));
3202e249 1531 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
db137867 1532 {
d86692fa 1533 SET_SS_FAMILY(dst, AF_INET);
1315fd59 1534 SET_SS_PORT(dst, 0);
db137867
AC
1535 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1536 return 1;
1537 }
3202e249 1538 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
db137867 1539 {
d86692fa 1540 SET_SS_FAMILY(dst, AF_INET6);
1315fd59 1541 SET_SS_PORT(dst, 0);
db137867
AC
1542 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1543 return 1;
1544 }
db137867
AC
1545 return 0;
1546}
1547
1548const char *
1549rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1550{
1551 switch (src->sa_family)
1552 {
1553 case AF_INET:
3202e249 1554 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
db137867 1555 case AF_INET6:
3202e249
VY
1556 return (rb_inet_ntop
1557 (AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
db137867
AC
1558 default:
1559 return NULL;
db137867
AC
1560 }
1561}
1562
1563/* char *
1564 * rb_inet_ntop(af, src, dst, size)
1565 * convert a network format address to presentation format.
1566 * return:
1567 * pointer to presentation format address (`dst'), or NULL (see errno).
1568 * author:
1569 * Paul Vixie, 1996.
1570 */
1571const char *
1572rb_inet_ntop(int af, const void *src, char *dst, unsigned int size)
1573{
1574 switch (af)
1575 {
1576 case AF_INET:
1577 return (inet_ntop4(src, dst, size));
db137867 1578 case AF_INET6:
3202e249
VY
1579 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
1580 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
db137867 1581 return (inet_ntop4
3202e249
VY
1582 ((const unsigned char *)&((const struct in6_addr *)src)->
1583 s6_addr[12], dst, size));
db137867
AC
1584 else
1585 return (inet_ntop6(src, dst, size));
db137867
AC
1586 default:
1587 return (NULL);
1588 }
1589 /* NOTREACHED */
1590}
1591
1592/*
1593 * WARNING: Don't even consider trying to compile this on a system where
1594 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1595 */
1596
1597/* int
1598 * rb_inet_pton(af, src, dst)
1599 * convert from presentation format (which usually means ASCII printable)
1600 * to network format (which is usually some kind of binary format).
1601 * return:
1602 * 1 if the address was valid for the specified address family
1603 * 0 if the address wasn't valid (`dst' is untouched in this case)
1604 * -1 if some other error occurred (`dst' is untouched in this case, too)
1605 * author:
1606 * Paul Vixie, 1996.
1607 */
1608
1609/* int
1610 * inet_pton4(src, dst)
1611 * like inet_aton() but without all the hexadecimal and shorthand.
1612 * return:
1613 * 1 if `src' is a valid dotted quad, else 0.
1614 * notice:
1615 * does not touch `dst' unless it's returning 1.
1616 * author:
1617 * Paul Vixie, 1996.
1618 */
1619static int
1620inet_pton4(const char *src, unsigned char *dst)
1621{
1622 int saw_digit, octets, ch;
1623 unsigned char tmp[INADDRSZ], *tp;
1624
1625 saw_digit = 0;
1626 octets = 0;
1627 *(tp = tmp) = 0;
3202e249 1628 while((ch = *src++) != '\0')
db137867
AC
1629 {
1630
1631 if(ch >= '0' && ch <= '9')
1632 {
1633 unsigned int new = *tp * 10 + (ch - '0');
1634
1635 if(new > 255)
1636 return (0);
1637 *tp = new;
1638 if(!saw_digit)
1639 {
1640 if(++octets > 4)
1641 return (0);
1642 saw_digit = 1;
1643 }
1644 }
1645 else if(ch == '.' && saw_digit)
1646 {
1647 if(octets == 4)
1648 return (0);
1649 *++tp = 0;
1650 saw_digit = 0;
1651 }
1652 else
1653 return (0);
1654 }
1655 if(octets < 4)
1656 return (0);
1657 memcpy(dst, tmp, INADDRSZ);
1658 return (1);
1659}
1660
db137867
AC
1661/* int
1662 * inet_pton6(src, dst)
1663 * convert presentation level address to network order binary form.
1664 * return:
1665 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1666 * notice:
1667 * (1) does not touch `dst' unless it's returning 1.
1668 * (2) :: in a full address is silently ignored.
1669 * credit:
1670 * inspired by Mark Andrews.
1671 * author:
1672 * Paul Vixie, 1996.
1673 */
1674
1675static int
1676inet_pton6(const char *src, unsigned char *dst)
1677{
1678 static const char xdigits[] = "0123456789abcdef";
1679 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
1680 const char *curtok;
1681 int ch, saw_xdigit;
1682 unsigned int val;
1683
1684 tp = memset(tmp, '\0', IN6ADDRSZ);
1685 endp = tp + IN6ADDRSZ;
1686 colonp = NULL;
1687 /* Leading :: requires some special handling. */
1688 if(*src == ':')
1689 if(*++src != ':')
1690 return (0);
1691 curtok = src;
1692 saw_xdigit = 0;
1693 val = 0;
29c92cf9 1694 while((ch = tolower((unsigned char)*src++)) != '\0')
db137867
AC
1695 {
1696 const char *pch;
1697
1698 pch = strchr(xdigits, ch);
1699 if(pch != NULL)
1700 {
1701 val <<= 4;
1702 val |= (pch - xdigits);
1703 if(val > 0xffff)
1704 return (0);
1705 saw_xdigit = 1;
1706 continue;
1707 }
1708 if(ch == ':')
1709 {
1710 curtok = src;
1711 if(!saw_xdigit)
1712 {
1713 if(colonp)
1714 return (0);
1715 colonp = tp;
1716 continue;
1717 }
1718 else if(*src == '\0')
1719 {
1720 return (0);
1721 }
1722 if(tp + INT16SZ > endp)
1723 return (0);
3202e249
VY
1724 *tp++ = (unsigned char)(val >> 8) & 0xff;
1725 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1726 saw_xdigit = 0;
1727 val = 0;
1728 continue;
1729 }
1730 if(*src != '\0' && ch == '.')
1731 {
1732 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
1733 {
1734 tp += INADDRSZ;
1735 saw_xdigit = 0;
1736 break; /* '\0' was seen by inet_pton4(). */
1737 }
1738 }
1739 else
1740 continue;
1741 return (0);
1742 }
1743 if(saw_xdigit)
1744 {
1745 if(tp + INT16SZ > endp)
1746 return (0);
3202e249
VY
1747 *tp++ = (unsigned char)(val >> 8) & 0xff;
1748 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1749 }
1750 if(colonp != NULL)
1751 {
1752 /*
1753 * Since some memmove()'s erroneously fail to handle
1754 * overlapping regions, we'll do the shift by hand.
1755 */
1756 const int n = tp - colonp;
1757 int i;
1758
1759 if(tp == endp)
1760 return (0);
3202e249 1761 for(i = 1; i <= n; i++)
db137867
AC
1762 {
1763 endp[-i] = colonp[n - i];
1764 colonp[n - i] = 0;
1765 }
1766 tp = endp;
1767 }
1768 if(tp != endp)
1769 return (0);
1770 memcpy(dst, tmp, IN6ADDRSZ);
1771 return (1);
1772}
de293496 1773
db137867
AC
1774int
1775rb_inet_pton(int af, const char *src, void *dst)
1776{
1777 switch (af)
1778 {
1779 case AF_INET:
1780 return (inet_pton4(src, dst));
db137867
AC
1781 case AF_INET6:
1782 /* Somebody might have passed as an IPv4 address this is sick but it works */
1783 if(inet_pton4(src, dst))
1784 {
1785 char tmp[HOSTIPLEN];
5203cba5 1786 sprintf(tmp, "::ffff:%s", src);
db137867
AC
1787 return (inet_pton6(tmp, dst));
1788 }
1789 else
1790 return (inet_pton6(src, dst));
db137867
AC
1791 default:
1792 return (-1);
1793 }
1794 /* NOTREACHED */
1795}
1796
1797
db137867
AC
1798static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
1799static int (*select_handler) (long);
1800static int (*setup_fd_handler) (rb_fde_t *);
1801static int (*io_sched_event) (struct ev_entry *, int);
1802static void (*io_unsched_event) (struct ev_entry *);
1803static int (*io_supports_event) (void);
1804static void (*io_init_event) (void);
1805static char iotype[25];
1806
1807const char *
1808rb_get_iotype(void)
1809{
1810 return iotype;
1811}
1812
1813static int
1814rb_unsupported_event(void)
1815{
1816 return 0;
1817}
1818
1819static int
1820try_kqueue(void)
1821{
1822 if(!rb_init_netio_kqueue())
1823 {
1824 setselect_handler = rb_setselect_kqueue;
1825 select_handler = rb_select_kqueue;
1826 setup_fd_handler = rb_setup_fd_kqueue;
1827 io_sched_event = rb_kqueue_sched_event;
1828 io_unsched_event = rb_kqueue_unsched_event;
1829 io_init_event = rb_kqueue_init_event;
1830 io_supports_event = rb_kqueue_supports_event;
1831 rb_strlcpy(iotype, "kqueue", sizeof(iotype));
1832 return 0;
1833 }
3202e249 1834 return -1;
db137867
AC
1835}
1836
1837static int
1838try_epoll(void)
1839{
1840 if(!rb_init_netio_epoll())
1841 {
1842 setselect_handler = rb_setselect_epoll;
1843 select_handler = rb_select_epoll;
1844 setup_fd_handler = rb_setup_fd_epoll;
1845 io_sched_event = rb_epoll_sched_event;
1846 io_unsched_event = rb_epoll_unsched_event;
1847 io_supports_event = rb_epoll_supports_event;
1848 io_init_event = rb_epoll_init_event;
1849 rb_strlcpy(iotype, "epoll", sizeof(iotype));
1850 return 0;
1851 }
1852 return -1;
1853}
1854
1855static int
1856try_ports(void)
1857{
1858 if(!rb_init_netio_ports())
1859 {
1860 setselect_handler = rb_setselect_ports;
1861 select_handler = rb_select_ports;
3202e249 1862 setup_fd_handler = rb_setup_fd_ports;
030272f3
VY
1863 io_sched_event = rb_ports_sched_event;
1864 io_unsched_event = rb_ports_unsched_event;
1865 io_init_event = rb_ports_init_event;
1866 io_supports_event = rb_ports_supports_event;
db137867
AC
1867 rb_strlcpy(iotype, "ports", sizeof(iotype));
1868 return 0;
1869 }
1870 return -1;
1871}
1872
1873static int
1874try_devpoll(void)
1875{
1876 if(!rb_init_netio_devpoll())
1877 {
1878 setselect_handler = rb_setselect_devpoll;
1879 select_handler = rb_select_devpoll;
3202e249 1880 setup_fd_handler = rb_setup_fd_devpoll;
db137867
AC
1881 io_sched_event = NULL;
1882 io_unsched_event = NULL;
1883 io_init_event = NULL;
1884 io_supports_event = rb_unsupported_event;
1885 rb_strlcpy(iotype, "devpoll", sizeof(iotype));
1886 return 0;
1887 }
1888 return -1;
1889}
1890
1891static int
1892try_sigio(void)
1893{
1894 if(!rb_init_netio_sigio())
1895 {
1896 setselect_handler = rb_setselect_sigio;
1897 select_handler = rb_select_sigio;
3202e249 1898 setup_fd_handler = rb_setup_fd_sigio;
db137867 1899 io_sched_event = rb_sigio_sched_event;
3202e249
VY
1900 io_unsched_event = rb_sigio_unsched_event;
1901 io_supports_event = rb_sigio_supports_event;
1902 io_init_event = rb_sigio_init_event;
1903
db137867
AC
1904 rb_strlcpy(iotype, "sigio", sizeof(iotype));
1905 return 0;
1906 }
1907 return -1;
1908}
1909
3202e249 1910static int
db137867
AC
1911try_poll(void)
1912{
1913 if(!rb_init_netio_poll())
1914 {
1915 setselect_handler = rb_setselect_poll;
1916 select_handler = rb_select_poll;
3202e249 1917 setup_fd_handler = rb_setup_fd_poll;
db137867
AC
1918 io_sched_event = NULL;
1919 io_unsched_event = NULL;
1920 io_init_event = NULL;
1921 io_supports_event = rb_unsupported_event;
1922 rb_strlcpy(iotype, "poll", sizeof(iotype));
1923 return 0;
1924 }
1925 return -1;
1926}
1927
db137867
AC
1928int
1929rb_io_sched_event(struct ev_entry *ev, int when)
1930{
3202e249
VY
1931 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL
1932 || !io_supports_event())
db137867
AC
1933 return 0;
1934 return io_sched_event(ev, when);
1935}
1936
1937void
1938rb_io_unsched_event(struct ev_entry *ev)
1939{
3202e249
VY
1940 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL
1941 || !io_supports_event())
db137867 1942 return;
3202e249 1943 io_unsched_event(ev);
db137867 1944}
3202e249 1945
db137867
AC
1946int
1947rb_io_supports_event(void)
1948{
1949 if(io_supports_event == NULL)
1950 return 0;
1951 return io_supports_event();
1952}
1953
1954void
1955rb_io_init_event(void)
1956{
1957 io_init_event();
1958 rb_event_io_register_all();
1959}
1960
1961void
1962rb_init_netio(void)
1963{
1964 char *ioenv = getenv("LIBRB_USE_IOTYPE");
1965 rb_fd_table = rb_malloc(RB_FD_HASH_SIZE * sizeof(rb_dlink_list));
1966 rb_init_ssl();
3202e249 1967
db137867
AC
1968 if(ioenv != NULL)
1969 {
1970 if(!strcmp("epoll", ioenv))
1971 {
1972 if(!try_epoll())
1973 return;
3202e249
VY
1974 }
1975 else if(!strcmp("kqueue", ioenv))
db137867
AC
1976 {
1977 if(!try_kqueue())
1978 return;
3202e249
VY
1979 }
1980 else if(!strcmp("ports", ioenv))
db137867
AC
1981 {
1982 if(!try_ports())
1983 return;
3202e249
VY
1984 }
1985 else if(!strcmp("poll", ioenv))
db137867
AC
1986 {
1987 if(!try_poll())
1988 return;
3202e249
VY
1989 }
1990 else if(!strcmp("devpoll", ioenv))
db137867
AC
1991 {
1992 if(!try_devpoll())
1993 return;
3202e249
VY
1994 }
1995 else if(!strcmp("sigio", ioenv))
db137867
AC
1996 {
1997 if(!try_sigio())
1998 return;
3202e249 1999 }
db137867
AC
2000 }
2001
2002 if(!try_kqueue())
2003 return;
2004 if(!try_epoll())
2005 return;
2006 if(!try_ports())
2007 return;
2008 if(!try_devpoll())
2009 return;
2010 if(!try_sigio())
2011 return;
2012 if(!try_poll())
2013 return;
db137867
AC
2014
2015 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2016
2017 abort();
2018}
2019
3202e249 2020void
db137867
AC
2021rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
2022{
2023 setselect_handler(F, type, handler, client_data);
2024}
2025
59ea3c67
EK
2026void
2027rb_defer(void (*fn)(void *), void *data)
2028{
2029 struct defer *defer = rb_malloc(sizeof *defer);
2030 defer->fn = fn;
2031 defer->data = data;
2032 rb_dlinkAdd(defer, &defer->node, &defer_list);
2033}
2034
3202e249 2035int
db137867
AC
2036rb_select(unsigned long timeout)
2037{
2038 int ret = select_handler(timeout);
59ea3c67
EK
2039 rb_dlink_node *ptr, *next;
2040 RB_DLINK_FOREACH_SAFE(ptr, next, defer_list.head)
2041 {
2042 struct defer *defer = ptr->data;
2043 defer->fn(defer->data);
2044 rb_dlinkDelete(ptr, &defer_list);
2045 rb_free(defer);
2046 }
ad2421c7 2047 rb_close_pending_fds();
db137867
AC
2048 return ret;
2049}
2050
3202e249 2051int
db137867
AC
2052rb_setup_fd(rb_fde_t *F)
2053{
1cad0654 2054 rb_set_cloexec(F);
db137867
AC
2055 return setup_fd_handler(F);
2056}
2057
2058
db137867
AC
2059int
2060rb_ignore_errno(int error)
2061{
3202e249 2062 switch (error)
db137867
AC
2063 {
2064#ifdef EINPROGRESS
3202e249 2065 case EINPROGRESS:
db137867
AC
2066#endif
2067#if defined EWOULDBLOCK
3202e249 2068 case EWOULDBLOCK:
db137867
AC
2069#endif
2070#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
3202e249 2071 case EAGAIN:
db137867
AC
2072#endif
2073#ifdef EINTR
3202e249 2074 case EINTR:
db137867
AC
2075#endif
2076#ifdef ERESTART
3202e249 2077 case ERESTART:
db137867
AC
2078#endif
2079#ifdef ENOBUFS
3202e249
VY
2080 case ENOBUFS:
2081#endif
2082 return 1;
2083 default:
2084 break;
2085 }
db137867
AC
2086 return 0;
2087}
2088
2089
2090int
2091rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2092{
2093 struct msghdr msg;
2094 struct cmsghdr *cmsg;
2095 struct iovec iov[1];
2096 struct stat st;
a9fb3ed0 2097 uint8_t stype = RB_FD_UNKNOWN;
db137867 2098 const char *desc;
8f0c3422 2099 int fd, len, x, rfds;
db137867
AC
2100
2101 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2102
2103 iov[0].iov_base = data;
2104 iov[0].iov_len = datasize;
3202e249 2105
db137867
AC
2106 msg.msg_name = NULL;
2107 msg.msg_namelen = 0;
2108 msg.msg_iov = iov;
2109 msg.msg_iovlen = 1;
2110 msg.msg_flags = 0;
2111 cmsg = alloca(control_len);
2112 msg.msg_control = cmsg;
2113 msg.msg_controllen = control_len;
2114
2115 if((len = recvmsg(rb_get_fd(F), &msg, 0)) <= 0)
2116 return len;
2117
3202e249
VY
2118 if(msg.msg_controllen > 0 && msg.msg_control != NULL
2119 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
db137867 2120 {
90e960f0 2121 rfds = ((unsigned char *)cmsg + cmsg->cmsg_len - CMSG_DATA(cmsg)) / sizeof(int);
db137867
AC
2122
2123 for(x = 0; x < nfds && x < rfds; x++)
2124 {
2125 fd = ((int *)CMSG_DATA(cmsg))[x];
2126 stype = RB_FD_UNKNOWN;
2127 desc = "remote unknown";
2128 if(!fstat(fd, &st))
2129 {
2130 if(S_ISSOCK(st.st_mode))
2131 {
2132 stype = RB_FD_SOCKET;
2133 desc = "remote socket";
2134 }
2135 else if(S_ISFIFO(st.st_mode))
2136 {
2137 stype = RB_FD_PIPE;
2138 desc = "remote pipe";
2139 }
2140 else if(S_ISREG(st.st_mode))
2141 {
2142 stype = RB_FD_FILE;
2143 desc = "remote file";
2144 }
2145 }
2146 xF[x] = rb_open(fd, stype, desc);
2147 }
3202e249
VY
2148 }
2149 else
db137867 2150 *xF = NULL;
3202e249 2151 return len;
db137867
AC
2152}
2153
2154
2155int
8679c0fe 2156rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid __attribute__((unused)))
db137867 2157{
db137867
AC
2158 struct msghdr msg;
2159 struct cmsghdr *cmsg;
2160 struct iovec iov[1];
2161 char empty = '0';
db137867 2162
5cc7ba25 2163 memset(&msg, 0, sizeof(msg));
db137867
AC
2164 if(datasize == 0)
2165 {
2166 iov[0].iov_base = &empty;
3202e249
VY
2167 iov[0].iov_len = 1;
2168 }
2169 else
2170 {
db137867
AC
2171 iov[0].iov_base = data;
2172 iov[0].iov_len = datasize;
2173 }
2174 msg.msg_iov = iov;
2175 msg.msg_iovlen = 1;
2176 msg.msg_name = NULL;
2177 msg.msg_namelen = 0;
2178 msg.msg_flags = 0;
2179 msg.msg_control = NULL;
2180 msg.msg_controllen = 0;
2181
2182 if(count > 0)
2183 {
e23126c8 2184 size_t ucount = (size_t)count;
db137867 2185 int len = CMSG_SPACE(sizeof(int) * count);
5cc7ba25 2186 char buf[len];
db137867
AC
2187
2188 msg.msg_control = buf;
2189 msg.msg_controllen = len;
2190 cmsg = CMSG_FIRSTHDR(&msg);
2191 cmsg->cmsg_level = SOL_SOCKET;
2192 cmsg->cmsg_type = SCM_RIGHTS;
2193 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * count);
2194
e23126c8 2195 for(size_t i = 0; i < ucount; i++)
3202e249
VY
2196 {
2197 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
db137867
AC
2198 }
2199 msg.msg_controllen = cmsg->cmsg_len;
5cc7ba25 2200 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2201 }
5cc7ba25 2202 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2203}
4eafa9e6 2204
4eafa9e6
EM
2205int
2206rb_ipv4_from_ipv6(const struct sockaddr_in6 *restrict ip6, struct sockaddr_in *restrict ip4)
2207{
2208 int i;
2209
2210 if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x02", 2))
2211 {
2212 /* 6to4 and similar */
2213 memcpy(&ip4->sin_addr, ip6->sin6_addr.s6_addr + 2, 4);
2214 }
2215 else if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x01\x00\x00", 4))
2216 {
2217 /* Teredo */
2218 for (i = 0; i < 4; i++)
2219 ((uint8_t *)&ip4->sin_addr)[i] = 0xFF ^
2220 ip6->sin6_addr.s6_addr[12 + i];
2221 }
2222 else
2223 return 0;
2224 SET_SS_LEN(ip4, sizeof(struct sockaddr_in));
2225 ip4->sin_family = AF_INET;
2226 ip4->sin_port = 0;
2227 return 1;
2228}