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