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: 7f2b086babc82fa38d572cb5648bd43c594737c8 $
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
136/** Shut down a set of BIOs
137 *
138 * We shut down the BIOs from the top to the bottom. This gives the TLS BIO an opportunity to
139 * call the SSL_shutdown() routine, which should then write to the FD BIO.
140 */
142{
143 fr_bio_t *this, *first;
145
146 fr_assert(!fr_bio_prev(bio));
147
148 /*
149 * Find the first bio in the chain.
150 */
151 for (this = bio; fr_bio_prev(this) != NULL; this = fr_bio_prev(this)) {
152 /* nothing */
153 }
154 first = this;
155
156 /*
157 * Walk back down the chain, calling the shutdown functions.
158 */
159 for (/* nothing */; this != NULL; this = fr_bio_next(this)) {
160 my = (fr_bio_common_t *) this;
161
162 if (!my->priv_cb.shutdown) continue;
163
164 /*
165 * The EOF handler said it's NOT at EOF, so we stop processing here.
166 */
167 my->priv_cb.shutdown(&my->bio);
168 my->priv_cb.shutdown = NULL;
169 }
170
171 /*
172 * Call the application shutdown routine
173 */
174 my = (fr_bio_common_t *) first;
175
176 if (my->cb.shutdown) my->cb.shutdown(first);
177 my->cb.shutdown = NULL;
178
179 return 0;
180}
181
182/** Like fr_bio_shutdown(), but can be called by anyone in the chain.
183 *
184 */
186{
187 fr_bio_common_t *prev;
188
189 while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
190 bio = (fr_bio_t *) prev;
191 }
192
193 return fr_bio_shutdown(bio);
194}
195
196char const *fr_bio_strerror(ssize_t error)
197{
198 switch (error) {
199 case fr_bio_error(NONE):
200 return "";
201
202 case fr_bio_error(IO_WOULD_BLOCK):
203 return "IO operation would block";
204
205 case fr_bio_error(IO):
206 return fr_syserror(errno);
207
208 case fr_bio_error(GENERIC):
209 return fr_strerror();
210
211 case fr_bio_error(VERIFY):
212 return "Packet fails verification";
213
214 case fr_bio_error(BUFFER_FULL):
215 return "Output buffer is full";
216
217 case fr_bio_error(BUFFER_TOO_SMALL):
218 return "Output buffer is too small to cache the data";
219
220 default:
221 return "<unknown>";
222 }
223}
224
226{
228
229 if (!cb) {
230 memset(&my->cb, 0, sizeof(my->cb));
231 } else {
232 my->cb = *cb;
233 }
234}
235
236/** Internal BIO function to run EOF callbacks.
237 *
238 * When a BIO hits EOF, it MUST call this function. This function will take care of changing the read()
239 * function to return nothing. It will also take care of walking back up the hierarchy, and calling any
240 * BIO EOF callbacks.
241 *
242 * Once all of the BIOs have been marked as blocked, it will call the application EOF callback.
243 */
245{
246 fr_bio_common_t *this = (fr_bio_common_t *) bio;
247
248 /*
249 * This BIO is at EOF. So we can't call read() any more.
250 */
251 this->bio.read = fr_bio_null_read;
252
253 while (true) {
254 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
255
256 /*
257 * There are no more BIOs. Tell the application that the entire BIO chain is at EOF.
258 */
259 if (!prev) {
260 if (this->cb.eof) {
261 this->cb.eof(&this->bio);
262 this->cb.eof = NULL;
263 }
264 break;
265 }
266
267 /*
268 * Go to the previous BIO. If it doesn't have an EOF handler, then keep going back up
269 * the chain until we're at the top.
270 */
271 this = prev;
272 if (!this->priv_cb.eof) continue;
273
274 /*
275 * The EOF handler said it's NOT at EOF, so we stop processing here.
276 */
277 if (this->priv_cb.eof((fr_bio_t *) this) == 0) break;
278
279 /*
280 * Don't run the EOF callback multiple times, and continue the loop.
281 */
282 this->priv_cb.eof = NULL;
283 }
284}
285
286/** Internal BIO function to tell all BIOs that it's blocked.
287 *
288 * When a BIO blocks on write, it MUST call this function. This function will take care of walking back up
289 * the hierarchy, and calling any write_blocked callbacks.
290 *
291 * Once all of the BIOs have been marked as blocked, it will call the application write_blocked callback.
292 */
294{
295 fr_bio_common_t *this = (fr_bio_common_t *) bio;
296 int is_blocked = 1;
297
298 while (true) {
299 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
300 int rcode;
301
302 /*
303 * There are no more BIOs. Tell the application that the entire BIO chain is blocked.
304 */
305 if (!prev) {
306 if (this->cb.write_blocked) {
307 rcode = this->cb.write_blocked(&this->bio);
308 if (rcode < 0) return rcode;
309 is_blocked &= (rcode == 1);
310 }
311 break;
312 }
313
314 /*
315 * Go to the previous BIO. If it doesn't have a write_blocked handler, then keep going
316 * back up the chain until we're at the top.
317 */
318 this = prev;
319 if (!this->priv_cb.write_blocked) continue;
320
321 /*
322 * The EOF handler said it's NOT at EOF, so we stop processing here.
323 */
324 rcode = this->priv_cb.write_blocked((fr_bio_t *) this);
325 if (rcode < 0) return rcode;
326 is_blocked &= (rcode == 1);
327 }
328
329 return is_blocked;
330}
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
fr_dlist_t _CONST entry
in the linked list of multiple bios
Definition base.h:118
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:130
#define fr_bio_error(_x)
Definition base.h:192
fr_dlist_t * next
Definition dlist.h:43
fr_dlist_t * prev
Definition dlist.h:42
fr_bio_shutdown & my
Definition fd_errno.h:59
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
Definition base.c:105
char const * fr_bio_strerror(ssize_t error)
Definition base.c:196
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:293
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:225
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:185
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:244
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:141
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:554