The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.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: 6898de53fc3cfe848d74a44cdafb2087ba0f42d8 $
19 * @file lib/bio/base.c
20 * @brief Binary IO abstractions.
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/bio/bio_priv.h>
26#include <freeradius-devel/bio/null.h>
27#include <freeradius-devel/util/syserror.h>
28
29#ifndef NDEBUG
30/** Free this bio.
31 *
32 * The bio can only be freed if it is not in any chain.
33 */
35{
38
39 /*
40 * It's safe to free this bio.
41 */
42 return 0;
43}
44#endif
45
46/** Internal bio function which just reads from the "next" bio.
47 *
48 * It is mainly used when the current bio needs to modify the write
49 * path, but does not need to do anything on the read path.
50 */
51ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
52{
53 ssize_t rcode;
54 fr_bio_t *next;
55
56 next = fr_bio_next(bio);
57 fr_assert(next != NULL);
58
59 rcode = next->read(next, packet_ctx, buffer, size);
60 if (rcode >= 0) return rcode;
61
62 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
63
66 return rcode;
67}
68
69/** Internal bio function which just writes to the "next" bio.
70 *
71 * It is mainly used when the current bio needs to modify the read
72 * path, but does not need to do anything on the write path.
73 */
74ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
75{
76 ssize_t rcode;
77 fr_bio_t *next;
78
79 next = fr_bio_next(bio);
80 fr_assert(next != NULL);
81
82 rcode = next->write(next, packet_ctx, buffer, size);
83 if (rcode >= 0) return rcode;
84
85 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
86
89 return rcode;
90}
91
92/** Free this bio, and everything it calls.
93 *
94 * We unlink the bio chain, and then free it individually. If there's an error, the bio chain is relinked.
95 * That way the error can be addressed (somehow) and this function can be called again.
96 *
97 * Note that we do not support talloc_free() for the bio chain. Each individual bio has to be unlinked from
98 * the chain before the destructor will allow it to be freed. This functionality is by design.
99 *
100 * We want to have an API where bios are created "bottom up", so that it is impossible for an application to
101 * create an incorrect chain. However, creating the chain bottom up means that the lower bios not parented
102 * from the higher bios, and therefore talloc_free() won't free them. As a result, we need an explicit
103 * bio_free() function.
104 */
106{
107 fr_bio_t *next = fr_bio_next(bio);
108
109 /*
110 * We cannot free a bio in the middle of a chain. It has to be unlinked first.
111 */
112 if (fr_bio_prev(bio)) return -1;
113
114 /*
115 * Unlink our bio, and recurse to free the next one. If we can't free it, re-chain it, but reset
116 * the read/write functions to do nothing.
117 */
118 if (next) {
119 next->entry.prev = NULL;
120 if (fr_bio_free(next) < 0) {
121 next->entry.prev = &bio->entry;
122 bio->read = fr_bio_fail_read;
124 return -1;
125 }
126
127 bio->entry.next = NULL;
128 }
129
130 /*
131 * It's now safe to free this bio.
132 */
133 return talloc_free(bio);
134}
135
136static ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
137{
138 return fr_bio_error(SHUTDOWN);
139}
140
141static ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
142{
143 return fr_bio_error(SHUTDOWN);
144}
145
146/** Shut down a set of BIOs
147 *
148 * We shut down the BIOs from the top to the bottom. This gives the TLS BIO an opportunity to
149 * call the SSL_shutdown() routine, which should then write to the FD BIO.
150 */
152{
153 fr_bio_t *this, *first;
155
156 /*
157 * Find the first bio in the chain.
158 */
159 for (this = bio; fr_bio_prev(this) != NULL; this = fr_bio_prev(this)) {
160 /* nothing */
161 }
162 first = this;
163
164 /*
165 * We're in the process of shutting down, don't call ourselves recursively.
166 */
167 my = (fr_bio_common_t *) this;
168 if (my->bio.read == fr_bio_shutdown_read) return 0;
169
170 /*
171 * Walk back down the chain, calling the shutdown functions.
172 */
173 for (/* nothing */; this != NULL; this = fr_bio_next(this)) {
174 my = (fr_bio_common_t *) this;
175
176 if (my->priv_cb.shutdown) {
177 my->priv_cb.shutdown(&my->bio);
178 my->priv_cb.shutdown = NULL;
179 }
180
182 my->bio.write = fr_bio_shutdown_write;
183 talloc_set_destructor(my, NULL);
184 }
185
186 /*
187 * Call the application shutdown routine
188 */
189 my = (fr_bio_common_t *) first;
190
191 if (my->cb.shutdown) my->cb.shutdown(first);
192 my->cb.shutdown = NULL;
193
194 return 0;
195}
196
197/** Like fr_bio_shutdown(), but can be called by anyone in the chain.
198 *
199 */
201{
202 fr_bio_common_t *prev;
203
204 while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
205 bio = (fr_bio_t *) prev;
206 }
207
208 return fr_bio_shutdown(bio);
209}
210
211char const *fr_bio_strerror(ssize_t error)
212{
213 switch (error) {
214 case fr_bio_error(NONE):
215 return "";
216
217 case fr_bio_error(IO_WOULD_BLOCK):
218 return "IO operation would block";
219
220 case fr_bio_error(IO):
221 return fr_syserror(errno);
222
223 case fr_bio_error(GENERIC):
224 return fr_strerror();
225
226 case fr_bio_error(VERIFY):
227 return "Packet fails verification";
228
229 case fr_bio_error(BUFFER_FULL):
230 return "Output buffer is full";
231
232 case fr_bio_error(BUFFER_TOO_SMALL):
233 return "Output buffer is too small to cache the data";
234
235 case fr_bio_error(SHUTDOWN):
236 return "The IO handler is not available. It has been shut down due to a previous error";
237
238 default:
239 return "<unknown>";
240 }
241}
242
244{
246
247 if (!cb) {
248 memset(&my->cb, 0, sizeof(my->cb));
249 } else {
250 my->cb = *cb;
251 }
252}
253
254/** Internal BIO function to run EOF callbacks.
255 *
256 * When a BIO hits EOF, it MUST call this function. This function will take care of changing the read()
257 * function to return nothing. It will also take care of walking back up the hierarchy, and calling any
258 * BIO EOF callbacks.
259 *
260 * Once all of the BIOs have been marked as blocked, it will call the application EOF callback.
261 */
263{
264 fr_bio_common_t *this = (fr_bio_common_t *) bio;
265
266 /*
267 * This BIO is at EOF. So we can't call read() any more.
268 */
269 this->bio.read = fr_bio_null_read;
270
271 while (true) {
272 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
273
274 /*
275 * There are no more BIOs. Tell the application that the entire BIO chain is at EOF.
276 */
277 if (!prev) {
278 if (this->cb.eof) {
279 this->cb.eof(&this->bio);
280 this->cb.eof = NULL;
281 }
282 break;
283 }
284
285 /*
286 * Go to the previous BIO. If it doesn't have an EOF handler, then keep going back up
287 * the chain until we're at the top.
288 */
289 this = prev;
290 if (!this->priv_cb.eof) continue;
291
292 /*
293 * The EOF handler said it's NOT at EOF, so we stop processing here.
294 */
295 if (this->priv_cb.eof((fr_bio_t *) this) == 0) break;
296
297 /*
298 * Don't run the EOF callback multiple times, and continue the loop.
299 */
300 this->priv_cb.eof = NULL;
301 }
302}
303
304/** Internal BIO function to tell all BIOs that it's blocked.
305 *
306 * When a BIO blocks on write, it MUST call this function. This function will take care of walking back up
307 * the hierarchy, and calling any write_blocked callbacks.
308 *
309 * Once all of the BIOs have been marked as blocked, it will call the application write_blocked callback.
310 */
312{
313 fr_bio_common_t *this = (fr_bio_common_t *) bio;
314 int is_blocked = 1;
315
316 while (true) {
317 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
318 int rcode;
319
320 /*
321 * There are no more BIOs. Tell the application that the entire BIO chain is blocked.
322 */
323 if (!prev) {
324 if (this->cb.write_blocked) {
325 rcode = this->cb.write_blocked(&this->bio);
326 if (rcode < 0) return rcode;
327 is_blocked &= (rcode == 1);
328 }
329 break;
330 }
331
332 /*
333 * Go to the previous BIO. If it doesn't have a write_blocked handler, then keep going
334 * back up the chain until we're at the top.
335 */
336 this = prev;
337 if (!this->priv_cb.write_blocked) continue;
338
339 /*
340 * The EOF handler said it's NOT at EOF, so we stop processing here.
341 */
342 rcode = this->priv_cb.write_blocked((fr_bio_t *) this);
343 if (rcode < 0) return rcode;
344 is_blocked &= (rcode == 1);
345 }
346
347 return is_blocked;
348}
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:117
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition base.h:122
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:116
fr_dlist_t _CONST entry
in the linked list of multiple bios
Definition base.h:119
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:131
#define fr_bio_error(_x)
Definition base.h:193
#define UNUSED
Definition build.h:317
fr_dlist_t * next
Definition dlist.h:43
fr_dlist_t * prev
Definition dlist.h:42
fr_bio_shutdown & my
Definition fd_errno.h:70
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
Definition base.c:105
static 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:141
char const * fr_bio_strerror(ssize_t error)
Definition base.c:211
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:311
static 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:136
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:243
int fr_bio_shutdown_intermediate(fr_bio_t *bio)
Like fr_bio_shutdown(), but can be called by anyone in the chain.
Definition base.c:200
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:262
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition base.c:34
ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Internal bio function which just reads from the "next" bio.
Definition base.c:51
ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Internal bio function which just writes to the "next" bio.
Definition base.c:74
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:151
talloc_free(reap)
long int ssize_t
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
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define VERIFY(_x)
Definition trie.c:130
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553