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