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