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