The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
fd_errno.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/**
19 * $Id: 9a884b08baabab3c5ae5f44246186e28456b9ad1 $
20 * @file lib/bio/fd_errno.h
21 * @brief Common errno handling for FD bio reads and writes.
22 *
23 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSIDH(lib_bio_fd_errno_h, "$Id: 9a884b08baabab3c5ae5f44246186e28456b9ad1 $")
26
27#include <freeradius-devel/bio/fd_priv.h>
28
29/** Turn a failed read / write into a bio return code.
30 *
31 * Only called when the syscall failed, i.e. when rcode is negative.
32 *
33 * @param my the FD bio.
34 * @param[in,out] rcode_p in: the failed syscall return code. out: what to return to the application.
35 * @param[in,out] tries_p how many times we have retried on EINTR.
36 * @param is_write true for the write path, false for the read path.
37 * @return
38 * - false return *rcode_p to the application.
39 * - true the syscall was interrupted, redo it.
40 */
41static inline CC_HINT(always_inline) bool fr_bio_fd_errno_retry(fr_bio_fd_t *my, ssize_t *rcode_p, int *tries_p, bool is_write)
42{
43 bool *blocked = is_write ? &my->info.write_blocked : &my->info.read_blocked;
44 fr_bio_io_t blocked_cb = is_write ? my->cb.write_blocked : my->cb.read_blocked;
45
46 switch (errno) {
47 case EINTR:
48 /*
49 * Try a few times before giving up.
50 */
51 (*tries_p)++;
52 if (*tries_p <= my->max_tries) return true;
53
54 *rcode_p = fr_bio_error(IO);
55 return false;
56
57#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
58 case EWOULDBLOCK:
59#endif
60 case EAGAIN:
61 /*
62 * The operation would block, return that.
63 */
64 if (!*blocked) {
65 *blocked = true;
66
67 if (blocked_cb) {
68 int error;
69
70 error = blocked_cb((fr_bio_t *) my);
71 if (error < 0) {
72 *rcode_p = error;
73 return false;
74 }
75 }
76 }
77
78 *rcode_p = fr_bio_error(IO_WOULD_BLOCK);
79 return false;
80
81 /*
82 * We're reading / writing a connected UDP socket, and the other end has gone away.
83 */
84 case ENOTCONN:
85
86 /*
87 * The other end of a socket has closed the connection.
88 */
89 case ECONNRESET:
90
91 /*
92 * The other end of a pipe has closed the connection.
93 */
94 case EPIPE:
95 /*
96 * The connection is no longer usable, so we call shutdown, rather than just marking it
97 * as being at EOF.
98 */
99 (void) fr_bio_shutdown(&my->bio);
100 *rcode_p = 0;
101 return false;
102
103 /*
104 * PMTU has been exceeded. Return a generic IO error.
105 *
106 * Only a write can exceed the PMTU, so a read which somehow reports EMSGSIZE is fatal.
107 *
108 * @todo - do this only for connected UDP sockets.
109 *
110 * However, recvmsg() can also return EMSGSIZE, if the msg_iovlen field has a bad value.
111 */
112 case EMSGSIZE:
113 *rcode_p = fr_bio_error(IO);
114 return false;
115
116 /*
117 * The underlying network has gone away. This is a fatal error for connected sockets,
118 * but a recoverable one for unconnected sockets.
119 */
120 case ENETDOWN:
121 case ENETUNREACH:
122 *rcode_p = fr_bio_error(IO);
123 return false;
124
125 default:
126 /*
127 * Some other error, it's fatal.
128 */
129 break;
130 }
131
132 /*
133 * Shut down the BIO. It's no longer useable.
134 */
135 (void) fr_bio_shutdown(&my->bio);
136
137 *rcode_p = fr_bio_error(IO);
138 return false;
139}
140
141/*
142 * Common code to suppress network failures on sendto / sendfromto for unconnected UDP sockets.
143 *
144 * If the destination network is down or is unreachable, we want to simply discard the packet. The error
145 * isn't fatal, so we don't close the socket.
146 */
147#define FD_ENET_SUPPRESS \
148 do { \
149 if ((rcode == fr_bio_error(IO)) && ((errno == ENETDOWN) || (errno == ENETUNREACH))) return 0; \
150 } while (0)
int(* fr_bio_io_t)(fr_bio_t *bio)
Definition base.h:84
#define fr_bio_error(_x)
Definition base.h:200
#define RCSIDH(h, id)
Definition build.h:604
bool read_blocked
did we block on read?
Definition fd.h:152
bool write_blocked
did we block on write?
Definition fd.h:153
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
fr_bio_fd_info_t info
Definition fd_priv.h:38
Our FD bio structure.
Definition fd_priv.h:35
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:158
long int ssize_t