The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fd.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: c32cda1bd54358df245bfea9a48747d5494e3847 $
19 * @file lib/bio/fd.c
20 * @brief BIO abstractions for file descriptors
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/bio/fd_priv.h>
26#include <freeradius-devel/bio/null.h>
27
28/*
29 * More portability idiocy
30 * Mac OSX Lion doesn't define SOL_IP. But IPPROTO_IP works.
31 */
32#ifndef SOL_IP
33# define SOL_IP IPPROTO_IP
34#endif
35
36/*
37 * glibc 2.4 and uClibc 0.9.29 introduce IPV6_RECVPKTINFO etc. and
38 * change IPV6_PKTINFO This is only supported in Linux kernel >=
39 * 2.6.14
40 *
41 * This is only an approximation because the kernel version that libc
42 * was compiled against could be older or newer than the one being
43 * run. But this should not be a problem -- we just keep using the
44 * old kernel interface.
45 */
46#ifdef __linux__
47# ifdef IPV6_RECVPKTINFO
48# include <linux/version.h>
49# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
50# ifdef IPV6_2292PKTINFO
51# undef IPV6_RECVPKTINFO
52# undef IPV6_PKTINFO
53# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
54# define IPV6_PKTINFO IPV6_2292PKTINFO
55# endif
56# endif
57/* Fall back to the legacy socket option if IPV6_RECVPKTINFO isn't defined */
58# elif defined(IPV6_2292PKTINFO)
59# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
60# endif
61#else
62
63/*
64 * For everything that's not Linux we assume RFC 3542 compliance
65 * - setsockopt() takes IPV6_RECVPKTINFO
66 * - cmsg_type is IPV6_PKTINFO (in sendmsg, recvmsg)
67 *
68 * If we don't have IPV6_RECVPKTINFO defined but do have IPV6_PKTINFO
69 * defined, chances are the API is RFC2292 compliant and we need to use
70 * IPV6_PKTINFO for both.
71 */
72# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
73# define IPV6_RECVPKTINFO IPV6_PKTINFO
74
75/*
76 * Ensure IPV6_RECVPKTINFO is not defined somehow if we have we
77 * don't have IPV6_PKTINFO.
78 */
79# elif !defined(IPV6_PKTINFO)
80# undef IPV6_RECVPKTINFO
81# endif
82#endif
83
84#define ADDR_INIT do { \
85 addr->when = fr_time(); \
86 addr->socket.type = my->info.socket.type; \
87 addr->socket.fd = -1; \
88 addr->socket.inet.ifindex = my->info.socket.inet.ifindex; \
89 } while (0)
90
91/** Orderly shutdown.
92 *
93 */
95{
96 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
97
98 if (my->info.state == FR_BIO_FD_STATE_CLOSED) return 0;
99
100 FR_TIMER_DELETE(&my->connect.ev);
101 if (my->connect.el) {
102 (void) fr_event_fd_delete(my->connect.el, my->info.socket.fd, FR_EVENT_FILTER_IO);
103 my->connect.el = NULL;
104 }
105
106 return fr_bio_fd_close(&my->bio);
107}
108
109static int fr_bio_fd_eof(fr_bio_t *bio)
110{
111 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
112
113 my->info.eof = true;
114
115 bio->read = fr_bio_null_read;
117
118 /*
119 * Nothing more for us to do, tell fr_bio_eof() that it can continue with poking other BIOs.
120 */
121 return 1;
122}
123
125{
126 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
127
128 my->info.write_blocked = false;
129 return 1;
130}
131
132/** Stream read.
133 *
134 * Stream sockets return 0 at EOF. However, we want to distinguish that from the case of datagram
135 * sockets, which return 0 when there's no data. So we return 0 to the caller for "no data", but also
136 * call the EOF function to tell all of the related BIOs that we're at EOF.
137 */
138static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
139{
140 int tries = 0;
141 ssize_t rcode;
142 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
143
144retry:
145 rcode = read(my->info.socket.fd, buffer, size);
146 if (rcode == 0) {
147 fr_bio_t *head;
148
149 /*
150 * Flush any pending writes, shut down the BIO, and then mark it as EOF.
151 */
152 head = fr_bio_head(bio);
153
154 (void) fr_bio_write(head, NULL, NULL, SIZE_MAX);
155
156 rcode = fr_bio_shutdown(head);
157 if (rcode < 0) return rcode;
158
159 fr_bio_eof(bio);
160 return 0;
161 }
162
163#include "fd_read.h"
164
165 return fr_bio_error(IO);
166}
167
168/** Connected datagram read.
169 *
170 * The difference between this and stream protocols is that for datagrams. a read of zero means "no packets",
171 * where a read of zero on a steam socket means "EOF".
172 *
173 * Connected sockets do _not_ update per-packet contexts.
174 */
175static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
176{
177 int tries = 0;
178 ssize_t rcode;
179 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
180 socklen_t salen;
181 struct sockaddr_storage sockaddr;
182
183#ifdef STATIC_ANALYZER
184 sockaddr = (struct sockaddr_storage) {};
185#endif
186
187retry:
188 salen = sizeof(sockaddr);
189
190 rcode = recvfrom(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, &salen);
191 if (rcode > 0) {
192 fr_assert(salen == my->remote_sockaddr_len);
193 fr_assert(sockaddr.ss_family == my->remote_sockaddr.ss_family);
194 fr_assert((sockaddr.ss_family == AF_INET) || (sockaddr.ss_family == AF_INET6)); /* datagram unix is not supported */
195 }
196
197 /*
198 * We do NOT call fr_bio_eof(), as 0 just means "no more data".
199 */
200 if (rcode == 0) return rcode;
201
202#include "fd_read.h"
203
204 return fr_bio_error(IO);
205}
206
207/** Read from a UDP socket where we know our IP
208 */
209static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
210{
211 int tries = 0;
212 ssize_t rcode;
213 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
214 socklen_t salen;
215 struct sockaddr_storage sockaddr;
216
217retry:
218 salen = sizeof(sockaddr);
219
220 rcode = recvfrom(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, &salen);
221 if (rcode > 0) {
223
224 ADDR_INIT;
225
226 addr->socket.inet.dst_ipaddr = my->info.socket.inet.src_ipaddr;
227 addr->socket.inet.dst_port = my->info.socket.inet.src_port;
228
229 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
230 &sockaddr, salen);
231 }
232
233 if (rcode == 0) return rcode;
234
235#include "fd_read.h"
236
237 return fr_bio_error(IO);
238}
239
240/** Write to fd.
241 *
242 * This function is used for connected sockets, where we ignore the packet_ctx.
243 */
244static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
245{
246 int tries = 0;
247 ssize_t rcode;
248 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
249
250 /*
251 * FD bios do nothing on flush.
252 */
253 if (!buffer) return 0;
254
255retry:
256 /*
257 * We could call send() instead of write()! Posix says:
258 *
259 * "A write was attempted on a socket that is shut down for writing, or is no longer
260 * connected. In the latter case, if the socket is of type SOCK_STREAM, a SIGPIPE signal shall
261 * also be sent to the thread."
262 *
263 * We can override this behavior by calling send(), and passing the special flag which says
264 * "don't do that!". The system call will then return EPIPE, which indicates that the socket is
265 * no longer usable.
266 *
267 * However, we also set the SO_NOSIGPIPE socket option, which means that we can just call write()
268 * here.
269 */
270 rcode = write(my->info.socket.fd, buffer, size);
271
272#include "fd_write.h"
273
274 return fr_bio_error(IO);
275}
276
277/** Write to a UDP socket where we know our IP
278 *
279 */
280static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
281{
282 int tries = 0;
283 ssize_t rcode;
284 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
286 socklen_t salen;
287 struct sockaddr_storage sockaddr;
288
289 /*
290 * FD bios do nothing on flush.
291 */
292 if (!buffer) return 0;
293
294 // get destination IP
295 (void) fr_ipaddr_to_sockaddr(&sockaddr, &salen, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
296
297retry:
298 rcode = sendto(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, salen);
299
300#include "fd_write.h"
301
302 return fr_bio_error(IO);
303}
304
305
306#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
307static ssize_t fd_fd_recvfromto_common(fr_bio_fd_t *my, void *packet_ctx, void *buffer, size_t size)
308{
309 int tries = 0;
310 ssize_t rcode;
311 struct sockaddr_storage from;
313
314#ifdef STATIC_ANALYZER
315 from.ss_family = AF_UNSPEC;
316#endif
317
318 memset(&my->cbuf, 0, sizeof(my->cbuf));
319 memset(&my->msgh, 0, sizeof(struct msghdr));
320
321 my->iov = (struct iovec) {
322 .iov_base = buffer,
323 .iov_len = size,
324 };
325
326 my->msgh = (struct msghdr) {
327 .msg_control = my->cbuf,
328 .msg_controllen = sizeof(my->cbuf),
329 .msg_name = &from,
330 .msg_namelen = sizeof(from),
331 .msg_iov = &my->iov,
332 .msg_iovlen = 1,
333 .msg_flags = 0,
334 };
335
336retry:
337 rcode = recvmsg(my->info.socket.fd, &my->msgh, 0);
338 if (rcode > 0) {
339 if (my->msgh.msg_flags == MSG_TRUNC) return 0;
340 if (my->msgh.msg_flags == MSG_CTRUNC) return 0;
341
342 ADDR_INIT;
343
344 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
345 &from, my->msgh.msg_namelen);
346 }
347
348 if (rcode == 0) return rcode;
349
350#include "fd_read.h"
351
352 return fr_bio_error(IO);
353}
354#endif
355
356#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
357
358/** Read from a UDP socket where we can change our IP, IPv4 version.
359 */
360static ssize_t fr_bio_fd_recvfromto4(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
361{
362 ssize_t rcode;
363 struct cmsghdr *cmsg;
364 fr_time_t when = fr_time_wrap(0);
365 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
367
368 rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
369 if (rcode <= 0) return rcode;
370
371DIAG_OFF(sign-compare)
372 /* Process auxiliary received data in msgh */
373 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
374 cmsg != NULL;
375 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
376DIAG_ON(sign-compare)
377
378#ifdef IP_PKTINFO
379 if ((cmsg->cmsg_level == SOL_IP) &&
380 (cmsg->cmsg_type == IP_PKTINFO)) {
381 struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
382 struct sockaddr_in to;
383
384 to.sin_family = AF_INET;
385 to.sin_addr = i->ipi_addr;
386
387 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
388 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
389 addr->socket.inet.ifindex = i->ipi_ifindex;
390 break;
391 }
392#endif
393
394#ifdef IP_RECVDSTADDR
395 if ((cmsg->cmsg_level == IPPROTO_IP) &&
396 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
397 struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
398 struct sockaddr_in to;
399
400 to.sin_family = AF_INET;
401 to.sin_addr = *i;
402 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
403 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
404 break;
405 }
406#endif
407
408#ifdef SO_TIMESTAMPNS
409 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
410 when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
411 }
412
413#elif defined(SO_TIMESTAMP)
414 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
415 when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
416 }
417#endif
418 }
419
420 if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
421
422 addr->when = when;
423
424 return rcode;
425}
426
427/** Send to UDP socket where we can change our IP, IPv4 version.
428 */
429static ssize_t fr_bio_fd_sendfromto4(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
430{
431 int tries = 0;
432 ssize_t rcode;
433 struct cmsghdr *cmsg;
434 struct sockaddr_storage to;
435 socklen_t to_len;
436 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
438
439 memset(&my->cbuf, 0, sizeof(my->cbuf));
440 memset(&my->msgh, 0, sizeof(struct msghdr));
441
442 (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
443
444 my->iov = (struct iovec) {
445 .iov_base = UNCONST(void *, buffer),
446 .iov_len = size,
447 };
448
449 my->msgh = (struct msghdr) {
450 .msg_control = my->cbuf,
451 // controllen is set below
452 .msg_name = &to,
453 .msg_namelen = to_len,
454 .msg_iov = &my->iov,
455 .msg_iovlen = 1,
456 .msg_flags = 0,
457 };
458
459 {
460#ifdef IP_PKTINFO
461 struct in_pktinfo *pkt;
462
463 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
464
465 cmsg = CMSG_FIRSTHDR(&my->msgh);
466 cmsg->cmsg_level = SOL_IP;
467 cmsg->cmsg_type = IP_PKTINFO;
468 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
469
470 pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
471 memset(pkt, 0, sizeof(*pkt));
472 pkt->ipi_spec_dst = addr->socket.inet.src_ipaddr.addr.v4;
473 pkt->ipi_ifindex = addr->socket.inet.ifindex;
474
475#elif defined(IP_SENDSRCADDR)
476 struct in_addr *in;
477
478 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
479
480 cmsg = CMSG_FIRSTHDR(&my->msgh);
481 cmsg->cmsg_level = IPPROTO_IP;
482 cmsg->cmsg_type = IP_SENDSRCADDR;
483 cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
484
485 in = (struct in_addr *) CMSG_DATA(cmsg);
486 *in = addr->socket.inet.src_ipaddr.addr.v4;
487#endif
488 }
489
490retry:
491 rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
492
493#include "fd_write.h"
494
495 return fr_bio_error(IO);
496}
497
498static inline int fr_bio_fd_udpfromto_init4(int fd)
499{
500 int proto = 0, flag = 0, opt = 1;
501
502#ifdef HAVE_IP_PKTINFO
503 /*
504 * Linux
505 */
506 proto = SOL_IP;
507 flag = IP_PKTINFO;
508
509#elif defined(IP_RECVDSTADDR)
510 /*
511 * Set the IP_RECVDSTADDR option (BSD). Note:
512 * IP_RECVDSTADDR == IP_SENDSRCADDR
513 */
514 proto = IPPROTO_IP;
515 flag = IP_RECVDSTADDR;
516#endif
517
518 return setsockopt(fd, proto, flag, &opt, sizeof(opt));
519}
520#endif
521
522#if defined(IPV6_PKTINFO)
523/** Read from a UDP socket where we can change our IP, IPv4 version.
524 */
525static ssize_t fr_bio_fd_recvfromto6(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
526{
527 ssize_t rcode;
528 struct cmsghdr *cmsg;
529 fr_time_t when = fr_time_wrap(0);
530 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
532
533 rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
534 if (rcode <= 0) return rcode;
535
536DIAG_OFF(sign-compare)
537 /* Process auxiliary received data in msgh */
538 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
539 cmsg != NULL;
540 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
541DIAG_ON(sign-compare)
542
543 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
544 (cmsg->cmsg_type == IPV6_PKTINFO)) {
545 struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg);
546 struct sockaddr_in6 to;
547
548 to.sin6_family = AF_INET6;
549 to.sin6_addr = i->ipi6_addr;
550
551 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
552 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in6));
553 addr->socket.inet.ifindex = i->ipi6_ifindex;
554 break;
555 }
556
557#ifdef SO_TIMESTAMPNS
558 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
559 when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
560 }
561
562#elif defined(SO_TIMESTAMP)
563 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
564 when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
565 }
566#endif
567 }
568
569 if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
570
571 addr->when = when;
572
573 return rcode;
574}
575
576/** Send to UDP socket where we can change our IP, IPv6 version.
577 */
578static ssize_t fr_bio_fd_sendfromto6(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
579{
580 int tries = 0;
581 ssize_t rcode;
582 struct cmsghdr *cmsg;
583 struct sockaddr_storage to;
584 socklen_t to_len;
585 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
587
588 memset(&my->cbuf, 0, sizeof(my->cbuf));
589 memset(&my->msgh, 0, sizeof(struct msghdr));
590
591 (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
592
593 my->iov = (struct iovec) {
594 .iov_base = UNCONST(void *, buffer),
595 .iov_len = size,
596 };
597
598 my->msgh = (struct msghdr) {
599 .msg_control = my->cbuf,
600 // controllen is set below
601 .msg_name = &to,
602 .msg_namelen = to_len,
603 .msg_iov = &my->iov,
604 .msg_iovlen = 1,
605 .msg_flags = 0,
606 };
607
608 {
609 struct in6_pktinfo *pkt;
610
611 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
612
613 cmsg = CMSG_FIRSTHDR(&my->msgh);
614 cmsg->cmsg_level = IPPROTO_IPV6;
615 cmsg->cmsg_type = IPV6_PKTINFO;
616 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
617
618 pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
619 memset(pkt, 0, sizeof(*pkt));
620 pkt->ipi6_addr = addr->socket.inet.src_ipaddr.addr.v6;
621 pkt->ipi6_ifindex = addr->socket.inet.ifindex;
622 }
623
624retry:
625 rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
626
627#include "fd_write.h"
628
629 return fr_bio_error(IO);
630}
631
632
633static inline int fr_bio_fd_udpfromto_init6(int fd)
634{
635 int opt = 1;
636
637 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt));
638}
639#endif
640
641int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
642{
643 size_t len;
644
645 len = strlen(filename);
646 if (len >= sizeof(sun->sun_path)) {
647 fr_strerror_const("Failed parsing unix domain socket filename: Name is too long");
648 return -1;
649 }
650
651 sun->sun_family = AF_LOCAL;
652 memcpy(sun->sun_path, filename, len + 1); /* SUN_LEN will do strlen */
653
654 *sunlen = SUN_LEN(sun);
655
656 return 0;
657}
658
660{
661 socklen_t salen;
662 struct sockaddr_storage salocal;
663
664 /*
665 * Already set: do nothing.
666 */
667 if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr) &&
668 (my->info.socket.inet.src_port != 0)) {
669 return 0;
670 }
671
672 /*
673 * FreeBSD jail issues. We bind to 0.0.0.0, but the
674 * kernel instead binds us to a 1.2.3.4. So once the
675 * socket is bound, ask it what it's IP address is.
676 */
677 salen = sizeof(salocal);
678 memset(&salocal, 0, salen);
679 if (getsockname(my->info.socket.fd, (struct sockaddr *) &salocal, &salen) < 0) {
680 fr_strerror_printf("Failed getting socket name: %s", fr_syserror(errno));
681 return -1;
682 }
683
684 if (fr_ipaddr_from_sockaddr(&my->info.socket.inet.src_ipaddr, &my->info.socket.inet.src_port, &salocal, salen) < 0) return -1;
685
686 fr_ipaddr_get_scope_id(&my->info.socket.inet.src_ipaddr);
687 my->info.socket.inet.ifindex = my->info.socket.inet.src_ipaddr.scope_id;
688
689 return 0;
690}
691
693{
694 my->info.state = FR_BIO_FD_STATE_OPEN;
695 my->info.eof = false;
696 my->info.read_blocked = false;
697 my->info.write_blocked = false;
698
699 /*
700 * Tell the caller that the socket is ready for application data.
701 */
702 if (my->cb.connected) my->cb.connected(&my->bio);
703}
704
705
706/** Try to connect().
707 *
708 * If connect is blocking, we either succeed or error immediately. Otherwise, the caller has to select the
709 * socket for writeability, and then call fr_bio_fd_connect() as soon as the socket is writeable.
710 */
712{
713 int tries = 0;
714 int rcode;
715
716 /*
717 * Save a "sockaddr" version of the address of the other end.
718 */
719 if (my->info.socket.af != AF_LOCAL) {
720 rcode = fr_ipaddr_to_sockaddr(&my->remote_sockaddr, &my->remote_sockaddr_len,
721 &my->info.socket.inet.dst_ipaddr, my->info.socket.inet.dst_port);
722 } else {
723 rcode = fr_filename_to_sockaddr((struct sockaddr_un *) &my->remote_sockaddr, &my->remote_sockaddr_len,
724 my->info.socket.unix.path);
725 }
726
727 if (rcode < 0) {
728 (void) fr_bio_shutdown(&my->bio);
729 return fr_bio_error(GENERIC);
730 }
731
732 my->info.state = FR_BIO_FD_STATE_CONNECTING;
733
734retry:
735 if (connect(my->info.socket.fd, (struct sockaddr *) &my->remote_sockaddr, my->remote_sockaddr_len) == 0) {
736 /*
737 * The source IP may have changed, so get the new one.
738 */
739 if (fr_bio_fd_socket_name(my) < 0) goto fail;
740
741 if (fr_bio_fd_init_common(my) < 0) goto fail;
742
744 return 0;
745 }
746
747 switch (errno) {
748 case EINTR:
749 tries++;
750 if (tries <= my->max_tries) goto retry;
752
753 /*
754 * This shouldn't happen, but we'll allow it
755 */
756 case EALREADY:
758
759 /*
760 * Once the socket is writable, it will be active, or in an error state. The caller has
761 * to call fr_bio_fd_connect() before calling write()
762 */
763 case EINPROGRESS:
764 if (!my->info.write_blocked) {
765 my->info.write_blocked = true;
766
767 rcode = fr_bio_write_blocked((fr_bio_t *) my);
768 if (rcode < 0) return rcode;
769 }
770
771 return fr_bio_error(IO_WOULD_BLOCK);
772
773 default:
774 break;
775 }
776
777fail:
778 (void) fr_bio_shutdown(&my->bio);
779 return fr_bio_error(IO);
780}
781
782
783/** Files are a special case of connected sockets.
784 *
785 */
787{
789
790 /*
791 * Other flags may be O_CREAT, etc.
792 */
793 switch (my->info.cfg->flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
794 case O_RDONLY:
795 my->bio.read = fr_bio_fd_read_stream;
796 my->bio.write = fr_bio_fail_write;
797 break;
798
799 case O_WRONLY:
800 my->bio.read = fr_bio_fail_read;
801 my->bio.write = fr_bio_fd_write;
802 break;
803
804 case O_RDWR:
805 my->bio.read = fr_bio_fd_read_stream;
806 my->bio.write = fr_bio_fd_write;
807 break;
808
809 default:
810 fr_strerror_const("Invalid flag for opening file");
811 return -1;
812 }
813
814 return 0;
815}
816
818{
819 int rcode;
820
821 if (my->info.socket.af == AF_FILE_BIO) return fr_bio_fd_init_file(my);
822
823 /*
824 * The source IP can be unspecified. It will get updated after we call connect().
825 */
826
827 /*
828 * All connected sockets must have a destination IP.
829 */
830 if (fr_ipaddr_is_inaddr_any(&my->info.socket.inet.dst_ipaddr)) {
831 fr_strerror_const("Destination IP address cannot be wildcard");
832 return -1;
833 }
834
835 /*
836 * Don't do any reads until we're connected.
837 */
838 my->bio.read = fr_bio_null_read;
839 my->bio.write = fr_bio_null_write;
840
841 my->info.eof = false;
842
843 my->info.read_blocked = false;
844 my->info.write_blocked = false;
845
846#ifdef SO_NOSIGPIPE
847 /*
848 * Although the server ignore SIGPIPE, some operating systems like BSD and OSX ignore the
849 * ignoring.
850 *
851 * Fortunately, those operating systems usually support SO_NOSIGPIPE. We set that to prevent
852 * them raising the signal in the first place.
853 */
854 {
855 int on = 1;
856
857 setsockopt(my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
858 }
859#endif
860
861 /*
862 * Don't call connect() if the socket is synchronous, it will block.
863 */
864 if (!my->info.cfg->async) return 0;
865
866 rcode = fr_bio_fd_try_connect(my);
867 if (rcode == 0) return 0;
868
869 if (rcode != fr_bio_error(IO_WOULD_BLOCK)) return rcode;
870
871 /*
872 * The socket is blocked, and should be selected for writing.
873 */
874 fr_assert(my->info.write_blocked);
876
877 return 0;
878}
879
881{
882 if (my->info.socket.type == SOCK_STREAM) { //!< stream socket
883 my->bio.read = fr_bio_fd_read_stream;
884 my->bio.write = fr_bio_fd_write;
885
886 } else if (my->info.type == FR_BIO_FD_CONNECTED) { //!< connected datagram
888 my->bio.write = fr_bio_fd_write;
889
890 } else if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr)) { //!< we know our IP address
891 my->bio.read = fr_bio_fd_recvfrom;
892 my->bio.write = fr_bio_fd_sendto;
893
894#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
895 } else if (my->info.socket.inet.src_ipaddr.af == AF_INET) { //!< we don't know our IPv4
896 if (fr_bio_fd_udpfromto_init4(my->info.socket.fd) < 0) return -1;
897
898 my->bio.read = fr_bio_fd_recvfromto4;
899 my->bio.write = fr_bio_fd_sendfromto4;
900#endif
901
902#if defined(IPV6_PKTINFO)
903 } else if (my->info.socket.inet.src_ipaddr.af == AF_INET6) { //!< we don't know our IPv6
904
905 if (fr_bio_fd_udpfromto_init6(my->info.socket.fd) < 0) return -1;
906
907 my->bio.read = fr_bio_fd_recvfromto6;
908 my->bio.write = fr_bio_fd_sendfromto6;
909#endif
910
911 } else {
912 fr_strerror_const("Failed initializing socket: cannot determine what to do");
913 return -1;
914 }
915
917
918 return 0;
919}
920
922{
923 fr_assert(my->info.socket.type == SOCK_STREAM);
924
925 my->bio.read = fr_bio_null_read;
926 my->bio.write = fr_bio_null_write;
927
928 if (listen(my->info.socket.fd, my->info.cfg->backlog_is_set ? my->info.cfg->backlog : 8) < 0) {
929 fr_strerror_printf("Failed calling listen() %s", fr_syserror(errno));
930 return fr_bio_error(IO);
931 }
932
934
935 return 0;
936}
937
938/** Allocate a FD bio
939 *
940 * The caller is responsible for tracking the FD, and all associated management of it. The bio API is
941 * intended to be simple, and does not provide wrapper functions for various ioctls. The caller should
942 * instead do that work.
943 *
944 * Once the FD is give to the bio, its lifetime is "owned" by the bio. Calling talloc_free(bio) will close
945 * the FD.
946 *
947 * The caller can still manage the FD for being readable / writeable. However, the caller should not call
948 * this bio directly (unless it is the only one). Instead, the caller should read from / write to the
949 * previous bio which will then eventually call this one.
950 *
951 * Before updating any event handler readable / writeable callbacks, the caller should check
952 * fr_bio_fd_at_eof(). If true, then the handlers should not be inserted. The previous bios should still be
953 * called to process any pending data, until they return EOF.
954 *
955 * The main purpose of an FD bio is to wrap the FD in a bio container. That, and handling retries on read /
956 * write, along with returning EOF as an error instead of zero.
957 *
958 * Note that the read / write functions can return partial data. It is the callers responsibility to ensure
959 * that any writes continue from where they left off (otherwise dat awill be missing). And any partial reads
960 * should go to a memory bio.
961 *
962 * If a read returns EOF, then the FD remains open until talloc_free(bio) or fr_bio_fd_close() is called.
963 *
964 * @param ctx the talloc ctx
965 * @param cfg structure holding configuration information
966 * @param offset only for unconnected datagram sockets, where #fr_bio_fd_packet_ctx_t is stored
967 * @return
968 * - NULL on error, memory allocation failed
969 * - !NULL the bio
970 */
971fr_bio_t *fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
972{
974
975 my = talloc_zero(ctx, fr_bio_fd_t);
976 if (!my) return NULL;
977
978 my->max_tries = 4;
979 my->offset = offset;
980
981 if (!cfg) {
982 /*
983 * Add place-holder information.
984 */
985 my->info = (fr_bio_fd_info_t) {
986 .socket = {
987 .af = AF_UNSPEC,
988 .fd = -1,
989 },
990 .type = FR_BIO_FD_UNCONNECTED,
991 .read_blocked = false,
992 .write_blocked = false,
993 .eof = false,
994 .state = FR_BIO_FD_STATE_CLOSED,
995 };
996
997 my->bio.read = fr_bio_null_read;
998 my->bio.write = fr_bio_null_write;
999 } else {
1000 my->info.state = FR_BIO_FD_STATE_CLOSED;
1001
1002 if (fr_bio_fd_open(&my->bio, cfg) < 0) {
1003 talloc_free(my);
1004 return NULL;
1005 }
1006 }
1007
1008 my->priv_cb.eof = fr_bio_fd_eof;
1009 my->priv_cb.write_resume = fr_bio_fd_write_resume;
1010 my->priv_cb.shutdown = fr_bio_fd_shutdown;
1011
1012 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor); /* always use a common destructor */
1013 return (fr_bio_t *) my;
1014}
1015
1016/** Close the FD, but leave the bio allocated and alive.
1017 *
1018 */
1020{
1021 int rcode;
1022 int tries = 0;
1023 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1024
1025 if (my->info.state == FR_BIO_FD_STATE_CLOSED) return 0;
1026
1027 my->bio.read = fr_bio_shutdown_read;
1028 my->bio.write = fr_bio_shutdown_write;
1029
1030 /*
1031 * Shut down the connected socket. The only errors possible here are things we can't do anything
1032 * about.
1033 *
1034 * shutdown() will close ALL versions of this file descriptor, even if it's (somehow) used in
1035 * another process. shutdown() will also tell the kernel to gracefully close the connected
1036 * socket, so that it can signal the other end, instead of having the connection disappear.
1037 *
1038 * This shouldn't strictly be necessary, as no other processes should be sharing this file
1039 * descriptor. But it's the safe (and polite) thing to do.
1040 */
1041 if (my->info.type == FR_BIO_FD_CONNECTED) {
1042 (void) shutdown(my->info.socket.fd, SHUT_RDWR);
1043 }
1044
1045retry:
1046 rcode = close(my->info.socket.fd);
1047 if (rcode < 0) {
1048 switch (errno) {
1049 case EINTR:
1050 case EIO:
1051 tries++;
1052 if (tries < my->max_tries) goto retry;
1053 return fr_bio_error(IO);
1054
1055 default:
1056 /*
1057 * EBADF, or other unrecoverable error. We just call it closed, and continue.
1058 */
1059 break;
1060 }
1061 }
1062
1063 my->info.state = FR_BIO_FD_STATE_CLOSED;
1064 my->info.read_blocked = true;
1065 my->info.write_blocked = true;
1066 my->info.eof = true;
1067 my->info.socket.fd = -1;
1068
1069 return 0;
1070}
1071
1072/** FD error when trying to connect, give up on the BIO.
1073 *
1074 */
1075static void fr_bio_fd_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
1076{
1077 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1078
1079 my->info.connect_errno = fd_errno;
1080
1081 if (my->connect.error) {
1082 my->connect.error(&my->bio);
1083 }
1084
1085 /*
1086 * The entire bio is unusable.
1087 */
1088 (void) fr_bio_shutdown(&my->bio);
1089}
1090
1091/** Connect callback for when the socket is writable.
1092 *
1093 * We try to connect the socket, and if so, call the application which should update the BIO status.
1094 */
1096{
1097 int rcode;
1098 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1099
1100 fr_assert(my->info.type == FR_BIO_FD_CONNECTED);
1101 fr_assert(my->info.state == FR_BIO_FD_STATE_CONNECTING);
1102 fr_assert(my->connect.el == el); /* and not NULL */
1103 fr_assert(my->connect.success != NULL);
1104 fr_assert(my->info.socket.fd == fd);
1105
1106#ifndef NDEBUG
1107 /*
1108 * This check shouldn't be necessary, as we have a kqeueue error callback. That should be called
1109 * when there's a connect error.
1110 */
1111 {
1112 int error;
1113 socklen_t socklen = sizeof(error);
1114
1115 /*
1116 * The socket is writeable. Let's see if there's an error.
1117 *
1118 * Unix Network Programming says:
1119 *
1120 * ""If so_error is nonzero when the process calls write, -1 is returned with errno set to the
1121 * value of SO_ERROR (p. 495 of TCPv2) and SO_ERROR is reset to 0. We have to check for the
1122 * error, and if there's no error, set the state to "open". ""
1123 *
1124 * The same applies to connect(). If a non-blocking connect returns INPROGRESS, it may later
1125 * become writable. It will be writable even if the connection fails. Rather than writing some
1126 * random application data, we call SO_ERROR, and get the underlying error.
1127 */
1128 if (getsockopt(my->info.socket.fd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen) < 0) {
1129 fr_bio_fd_el_error(el, fd, flags, errno, uctx);
1130 return;
1131 }
1132
1133 /*
1134 * There was an error, we call the error handler.
1135 */
1136 if (error) {
1137 fr_bio_fd_el_error(el, fd, flags, error, uctx);
1138 return;
1139 }
1140 }
1141#endif
1142
1143 /*
1144 * Try to connect it. Any magic handling is done in the callbacks.
1145 *
1146 * On WOULD_BLOCK, leave the timers, etc. open.
1147 *
1148 * Otherwise the try_connect() function has shut down the BIO.
1149 */
1150 rcode = fr_bio_fd_try_connect(my);
1151 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return;
1152
1153 if (rcode < 0) {
1154 FR_TIMER_DELETE(&my->connect.ev);
1155 my->connect.el = NULL;
1156 return;
1157 }
1158
1159 /*
1160 * my->connect.success was already called from fr_bio_fd_set_open().
1161 */
1162
1163 FR_TIMER_DELETE(&my->connect.ev);
1164 my->connect.el = NULL;
1165}
1166
1167/** We have a timeout on the conenction
1168 *
1169 */
1171{
1172 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1173
1174 fr_assert(my->connect.timeout);
1175
1176 my->connect.timeout(&my->bio);
1177
1178 (void) fr_bio_shutdown(&my->bio);
1179}
1180
1181
1182/** Finalize a connect()
1183 *
1184 * connect() said "come back when the socket is writeable". It's now writeable, so we check if there was a
1185 * connection error.
1186 *
1187 * @param bio the binary IO handler
1188 * @param el the event list
1189 * @param connected_cb callback to run when the BIO is connected
1190 * @param error_cb callback to run when the FD has an error
1191 * @param timeout when to time out the connect() attempt
1192 * @param timeout_cb to call when the timeout runs.
1193 * @return
1194 * - <0 on error
1195 * - 0 for "try again later". If callbacks are set, the callbacks will try again. Otherwise the application has to try again.
1196 * - 1 for "we are now connected".
1197 */
1199 fr_bio_callback_t error_cb,
1200 fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
1201{
1202 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1203
1204 /*
1205 * We shouldn't be connected an unconnected socket.
1206 */
1207 if (my->info.type == FR_BIO_FD_UNCONNECTED) {
1208 error:
1209#ifdef ECONNABORTED
1210 my->info.connect_errno = ECONNABORTED;
1211#else
1212 my->info.connect_errno = ECONNREFUSED;
1213#endif
1214 if (error_cb) error_cb(bio);
1215 (void) fr_bio_shutdown(&my->bio);
1216 return fr_bio_error(GENERIC);
1217 }
1218
1219 /*
1220 * The initial open may have succeeded in connecting the socket. In which case we just run the
1221 * callbacks and return.
1222 */
1223 if (my->info.state == FR_BIO_FD_STATE_OPEN) {
1224 connected:
1225 if (connected_cb) connected_cb(bio);
1226
1227 return 1;
1228 }
1229
1230 /*
1231 * The caller may just call us without caring about what the underlying BIO is. In which case we
1232 * need to be safe.
1233 */
1234 if ((my->info.socket.af == AF_FILE_BIO) || (my->info.type == FR_BIO_FD_LISTEN)) {
1236 goto connected;
1237 }
1238
1239 /*
1240 * It must be in the connecting state, i.e. not INVALID or CLOSED.
1241 */
1242 if (my->info.state != FR_BIO_FD_STATE_CONNECTING) goto error;
1243
1244 /*
1245 * No callback
1246 */
1247 if (!connected_cb) {
1248 ssize_t rcode;
1249
1250 rcode = fr_bio_fd_try_connect(my);
1251 if (rcode < 0) {
1252 if (error_cb) error_cb(bio);
1253 return rcode; /* it already called shutdown */
1254 }
1255
1256 return 1;
1257 }
1258
1259 /*
1260 * It's not connected, the caller has to try again.
1261 */
1262 if (!el) return 0;
1263
1264 /*
1265 * Set the callbacks to run when something happens.
1266 */
1267 my->connect.success = connected_cb;
1268 my->connect.error = error_cb;
1269 my->connect.timeout = timeout_cb;
1270
1271 /*
1272 * Set the timeout callback if asked.
1273 */
1274 if (timeout_cb) {
1275 if (fr_timer_in(my, el->tl, &my->connect.ev, *timeout, false, fr_bio_fd_el_timeout, my) < 0) {
1276 goto error;
1277 }
1278 }
1279
1280 /*
1281 * Set the FD callbacks, and tell the caller that we're not connected.
1282 */
1283 if (fr_event_fd_insert(my, NULL, el, my->info.socket.fd, NULL,
1285 goto error;
1286 }
1287 my->connect.el = el;
1288
1289 return 0;
1290}
1291
1292/** Returns a pointer to the bio-specific information.
1293 *
1294 */
1296{
1297 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1298
1299 return &my->info;
1300}
1301
1302
1303/** Discard all reads from a UDP socket.
1304 */
1305static ssize_t fr_bio_fd_read_discard_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1306{
1307 int tries = 0;
1308 ssize_t rcode;
1309 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1310
1311retry:
1312 rcode = read(my->info.socket.fd, buffer, size);
1313 if (rcode >= 0) return 0; /* always return that we read no data */
1314
1315#undef flag_blocked
1316#define flag_blocked read_blocked
1317#include "fd_errno.h"
1318
1319 return fr_bio_error(IO);
1320}
1321
1322/** Discard all reads from a TCP socket.
1323 */
1324static ssize_t fr_bio_fd_read_discard_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1325{
1326 int tries = 0;
1327 ssize_t rcode;
1328 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1329
1330retry:
1331 rcode = read(my->info.socket.fd, buffer, size);
1332 if (rcode > 0 ) return 0; /* always return that we read no data */
1333 if (rcode == 0) {
1334 fr_bio_eof(bio);
1335 return 0;
1336 }
1337
1338#undef flag_blocked
1339#define flag_blocked read_blocked
1340#include "fd_errno.h"
1341
1342 return fr_bio_error(IO);
1343}
1344
1345/** Mark up a bio as write-only
1346 *
1347 */
1349{
1350 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1351
1352 switch (my->info.type) {
1353 case FR_BIO_FD_INVALID:
1354 return -1;
1355
1357 if (my->info.socket.type != SOCK_DGRAM) {
1358 fr_strerror_const("Only datagram sockets can be marked 'write-only'");
1359 return -1;
1360 }
1361 goto set_recv_buff_zero;
1362
1364 /*
1365 * Further reads are disallowed. However, this likely has no effect for UDP sockets.
1366 */
1367 if (shutdown(my->info.socket.fd, SHUT_RD) < 0) {
1368 fr_strerror_printf("Failed shutting down connected socket - %s", fr_syserror(errno));
1369 return -1;
1370 }
1371
1372 set_recv_buff_zero:
1373#ifdef __linux__
1374#ifdef SO_RCVBUF
1375 /*
1376 * On Linux setting the receive buffer to zero has the effect of discarding all incoming
1377 * data in the kernel. With macOS and others it's an invalid value.
1378 */
1379 {
1380 int opt = 0;
1381
1382 if (setsockopt(my->info.socket.fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
1383 fr_strerror_printf("Failed setting SO_RCVBUF: %s", fr_syserror(errno));
1384 return -1;
1385 }
1386 }
1387#endif
1388#endif
1389 break;
1390
1391 case FR_BIO_FD_LISTEN:
1392 fr_strerror_const("Only unconnected sockets can be marked 'write-only'");
1393 return -1;
1394 }
1395
1396 /*
1397 * No matter what the possibilities above, we replace the read function with a "discard"
1398 * function.
1399 */
1400 my->bio.read = (my->info.socket.type == SOCK_DGRAM) ? fr_bio_fd_read_discard_datagram : fr_bio_fd_read_discard_stream;
1401 return 0;
1402}
1403
1404#if !defined(__linux__) && !defined(__FreeBSD__)
1405static int inline accept4(int fd, struct sockaddr *sockaddr, socklen_t *salen, UNUSED int flags)
1406{
1407 fd = accept(fd, sockaddr, salen);
1408 if (fd >= 0) {
1409 if ((fr_nonblock(fd) < 0) || (fr_cloexec(fd) < 0)) {
1410 close(fd);
1411 return -1;
1412 }
1413 }
1414
1415 return fd;
1416}
1417#ifndef SOCK_NONBLOCK
1418#define SOCK_NONBLOCK 0
1419#endif
1420
1421#ifndef SOCK_CLOEXEC
1422#define SOCK_CLOEXEC 0
1423#endif
1424#endif
1425
1426/** Accept a stream socket and initialize its flags.
1427 *
1428 */
1430{
1431 int rcode;
1432 int fd, tries = 0;
1433
1434 my->remote_sockaddr_len = sizeof(my->remote_sockaddr);
1435
1436retry:
1437 /*
1438 * Set these flags immediately on the new socket.
1439 */
1440 fd = accept4(parent->info.socket.fd, (struct sockaddr *) &my->remote_sockaddr, &my->remote_sockaddr_len,
1442 if (fd < 0) {
1443 /*
1444 * Try a few times before giving up.
1445 */
1446 if (errno == EINTR) {
1447 tries++;
1448 if (tries <= my->max_tries) goto retry;
1449 }
1450
1451 return fr_bio_error(IO);
1452 }
1453
1454 /*
1455 * Get IP addresses from the sockaddr.
1456 */
1457 if ((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6)) {
1458 fr_ipaddr_from_sockaddr(&my->info.socket.inet.dst_ipaddr, &my->info.socket.inet.dst_port,
1459 &my->remote_sockaddr, my->remote_sockaddr_len);
1460 }
1461
1462 /*
1463 * The socket is now open. Save the new state.
1464 */
1465 my->info.socket.fd = fd;
1466 my->info.type = FR_BIO_FD_CONNECTED;
1467
1468 rcode = fr_bio_fd_init_common(my);
1469 if (rcode < 0) {
1470 my->info.socket.fd = -1;
1471 close(fd);
1472 return rcode;
1473 }
1474
1476 if (!my->info.name) {
1477 my->info.socket.fd = -1;
1478 close(fd);
1479 return fr_bio_error(OOM);
1480 }
1481
1482 return 0;
1483}
1484
1485
1486/** Accept a new connection on a socket.
1487 *
1488 */
1489int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
1490{
1491 int rcode;
1492 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1494
1495 *out_p = NULL;
1496
1497 fr_assert(my->info.type == FR_BIO_FD_LISTEN);
1498
1499 /*
1500 * Allocate the base BIO and set it up.
1501 */
1502 out = (fr_bio_fd_t *) fr_bio_fd_alloc(ctx, NULL, my->offset);
1503 if (!out) return fr_bio_error(GENERIC);
1504
1505 /*
1506 * Initialize the new BIO information.
1507 */
1508 out->info.cfg = my->info.cfg;
1509
1510 /*
1511 * Copy all socket fields, including ones which will be over-written later.
1512 */
1513 out->info.socket = my->info.socket;
1514
1515 if (my->info.socket.type == SOCK_STREAM) {
1516 rcode = fr_bio_fd_accept_stream(out, my);
1517
1518 } else {
1519 fr_assert(my->info.socket.type == SOCK_DGRAM);
1520
1521 // rcode = fr_bio_fd_accept_datagram(out, my);
1522 rcode = -1;
1523 }
1524 if (rcode < 0) {
1526 return rcode;
1527 }
1528
1529 /*
1530 * The socket is now
1531 */
1532
1533 *out_p = (fr_bio_t *) out;
1534 return 1;
1535}
static int const char char buffer[256]
Definition acutest.h:578
fr_bio_write_t _CONST write
write to the underlying bio
Definition base.h:117
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:116
static ssize_t fr_bio_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write raw data to a bio.
Definition base.h:184
static fr_bio_t * fr_bio_head(fr_bio_t *bio)
Definition base.h:140
void(* fr_bio_callback_t)(fr_bio_t *bio)
Definition base.h:86
#define fr_bio_error(_x)
Definition base.h:200
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define NDEBUG_UNUSED
Definition build.h:328
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define DIAG_ON(_x)
Definition build.h:462
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:461
static fr_slen_t in
Definition dict.h:884
#define fr_event_fd_insert(...)
Definition event.h:248
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:84
int fr_bio_fd_connect_full(fr_bio_t *bio, fr_event_list_t *el, fr_bio_callback_t connected_cb, fr_bio_callback_t error_cb, fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
Finalize a connect()
Definition fd.c:1198
static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
Write to fd.
Definition fd.c:244
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
Definition fd.c:659
static void fr_bio_fd_el_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, NDEBUG_UNUSED int flags, void *uctx)
Connect callback for when the socket is writable.
Definition fd.c:1095
#define ADDR_INIT
Definition fd.c:84
static int fr_bio_fd_write_resume(fr_bio_t *bio)
Definition fd.c:124
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
Definition fd.c:971
static ssize_t fr_bio_fd_read_discard_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a TCP socket.
Definition fd.c:1324
static int accept4(int fd, struct sockaddr *sockaddr, socklen_t *salen, UNUSED int flags)
Definition fd.c:1405
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
Definition fd.c:817
static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Connected datagram read.
Definition fd.c:175
static ssize_t fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
Definition fd.c:711
static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a UDP socket where we know our IP.
Definition fd.c:209
#define SOL_IP
Definition fd.c:33
static int fr_bio_fd_eof(fr_bio_t *bio)
Definition fd.c:109
static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
Write to a UDP socket where we know our IP.
Definition fd.c:280
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
Definition fd.c:641
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
Definition fd.c:921
int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
Accept a new connection on a socket.
Definition fd.c:1489
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
Definition fd.c:1295
static int fr_bio_fd_shutdown(fr_bio_t *bio)
Orderly shutdown.
Definition fd.c:94
static int fr_bio_fd_accept_stream(fr_bio_fd_t *my, fr_bio_fd_t const *parent)
Accept a stream socket and initialize its flags.
Definition fd.c:1429
static int fr_bio_fd_init_file(fr_bio_fd_t *my)
Files are a special case of connected sockets.
Definition fd.c:786
static void fr_bio_fd_el_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
We have a timeout on the conenction.
Definition fd.c:1170
#define SOCK_CLOEXEC
Definition fd.c:1422
int fr_bio_fd_init_common(fr_bio_fd_t *my)
Definition fd.c:880
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition fd.c:1348
static ssize_t fr_bio_fd_read_discard_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a UDP socket.
Definition fd.c:1305
static void fr_bio_fd_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
FD error when trying to connect, give up on the BIO.
Definition fd.c:1075
#define SOCK_NONBLOCK
Definition fd.c:1418
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
Definition fd.c:1019
static void fr_bio_fd_set_open(fr_bio_fd_t *my)
Definition fd.c:692
static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Stream read.
Definition fd.c:138
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
@ FR_BIO_FD_INVALID
not set
Definition fd.h:64
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition fd.h:65
@ FR_BIO_FD_LISTEN
returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
Definition fd.h:69
@ FR_BIO_FD_STATE_CLOSED
Definition fd.h:58
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:60
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:59
#define AF_FILE_BIO
Definition fd.h:40
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
Definition fd_open.c:1045
fr_socket_t socket
socket information, including FD.
Definition fd.h:52
Configuration for sockets.
Definition fd.h:80
Run-time status of the socket.
Definition fd.h:131
Per-packet context.
Definition fd.h:51
void fr_bio_shutdown & my
Definition fd_errno.h:70
void fr_bio_fd_name(fr_bio_fd_t *my)
Set the name of an FD BIO.
Definition fd_open.c:882
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
Definition fd_priv.h:62
Our FD bio structure.
Definition fd_priv.h:35
talloc_free(hp)
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
Definition inet.c:1494
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1449
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:63
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1400
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:272
ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Definition base.c:74
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:212
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition base.c:35
ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Definition base.c:79
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
#define fr_time()
Definition event.c:60
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1203
Stores all information relating to an event list.
Definition event.c:377
long int ssize_t
int fr_nonblock(UNUSED int fd)
Definition misc.c:294
int fr_cloexec(UNUSED int fd)
Definition misc.c:332
ssize_t fr_bio_null_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
Definition null.c:39
ssize_t fr_bio_null_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return 0 on read.
Definition null.c:31
ssize_t fr_bio_fail_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return error on read.
Definition null.c:47
ssize_t fr_bio_fail_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return an error on write.
Definition null.c:56
#define fr_assert(_expr)
Definition rad_assert.h:38
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
Convert a timeval (wallclock time) to a fr_time_t (internal time)
Definition time.h:896
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_eq(_a, _b)
Definition time.h:241
static fr_time_t fr_time_from_timespec(struct timespec const *when_ts)
Convert a timespec (wallclock time) to a fr_time_t (internal time)
Definition time.h:878
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:50
#define FR_TIMER_DELETE(_ev_p)
Definition timer.h:103
#define fr_timer_in(...)
Definition timer.h:87
static fr_event_list_t * el
static fr_slen_t head
Definition xlat.h:420
static fr_slen_t parent
Definition pair.h:858
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static size_t char ** out
Definition value.h:1030