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