The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
bio_mem_tests.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Tests for the memory bio
18 *
19 * @file src/lib/bio/test/bio_mem_tests.c
20 *
21 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
22 */
23#include <freeradius-devel/util/test/acutest_common_init.h>
24#include <freeradius-devel/util/test/acutest_helpers.h>
25
26#define _BIO_PRIVATE 1
27#include <freeradius-devel/bio/bio_priv.h>
28#include <freeradius-devel/bio/mem.h>
29#include <freeradius-devel/bio/null.h>
30#include <freeradius-devel/bio/pipe.h>
31
32static int cb_noop(fr_bio_t *bio) { (void) bio; return 0; }
33static void cb_noop_void(fr_bio_t *bio) { (void) bio; }
34
37 .write_resume = cb_noop,
38 .read_blocked = cb_noop,
39 .write_blocked = cb_noop,
40 .eof = cb_noop_void,
41};
42
43/** Framing for the tests: the first byte of a packet is its total length.
44 */
45typedef struct {
46 bool fail; //!< return ERROR_CLOSE for the next packet
48
50 const void *buffer, size_t *size)
51{
52 test_verify_ctx_t *tctx = verify_ctx;
53 uint8_t const *p = buffer;
54
55 if (tctx->fail) return FR_BIO_VERIFY_ERROR_CLOSE;
56
57 if (*size < 1) {
58 *size = 1;
60 }
61
62 if (*size < (size_t) p[0]) {
63 *size = p[0];
65 }
66
67 *size = p[0];
68 return FR_BIO_VERIFY_OK;
69}
70
71/** Put bytes where the memory bio's reads will find them.
72 *
73 * fr_bio_write() requires the head of a chain, and the source is the tail, so this calls the
74 * source's own write routine.
75 */
76static ssize_t test_source_write(fr_bio_t *source, char const *data, size_t size)
77{
78 return source->write(source, NULL, data, size);
79}
80
81/** A memory bio in front of a pipe, which stands in for the network.
82 *
83 * Writing to the pipe puts bytes where the memory bio's reads will find them.
84 */
85static fr_bio_t *test_mem_alloc(TALLOC_CTX *ctx, fr_bio_t **source_p, test_verify_ctx_t *tctx)
86{
87 fr_bio_t *mem, *source;
88
89 source = fr_bio_pipe_alloc(ctx, &test_cb, 1024);
90 if (!source) return NULL;
91
92 mem = fr_bio_mem_alloc(ctx, 1024, 0, source);
93 if (!mem) return NULL;
94
95 if (tctx && (fr_bio_mem_set_verify(mem, test_verify, tctx, false) < 0)) return NULL;
96
97 if (source_p) *source_p = source;
98 return mem;
99}
100
101/** A complete packet is returned, and only one packet at a time.
102 */
103static void test_verify_one_packet(void)
104{
105 TALLOC_CTX *ctx = talloc_init_const("test");
106 test_verify_ctx_t tctx = {};
107 fr_bio_t *mem, *source;
108 uint8_t buf[64];
109 ssize_t slen;
110
111 mem = test_mem_alloc(ctx, &source, &tctx);
112 TEST_CHECK(mem != NULL);
113 if (!mem) goto done;
114
115 TEST_CHECK_RET((int) test_source_write(source, "\x05""abcd", 5), 5);
116
117 TEST_CASE("one whole packet comes back");
118 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
119 TEST_CHECK_RET((int) slen, 5);
120 if (slen == 5) TEST_CHECK(memcmp(buf, "\x05""abcd", 5) == 0);
121
122 TEST_CASE("there is nothing else to read");
123 TEST_CHECK_RET((int) fr_bio_read(mem, NULL, buf, sizeof(buf)), 0);
124
125done:
126 talloc_free(ctx);
127}
128
129/** A packet split across two reads is reassembled.
130 */
132{
133 TALLOC_CTX *ctx = talloc_init_const("test");
134 test_verify_ctx_t tctx = {};
135 fr_bio_t *mem, *source;
136 uint8_t buf[64];
137 ssize_t slen;
138
139 mem = test_mem_alloc(ctx, &source, &tctx);
140 TEST_CHECK(mem != NULL);
141 if (!mem) goto done;
142
143 TEST_CASE("half a packet is not a packet");
144 TEST_CHECK_RET((int) test_source_write(source, "\x05""ab", 3), 3);
145 TEST_CHECK_RET((int) fr_bio_read(mem, NULL, buf, sizeof(buf)), 0);
146
147 TEST_CASE("the rest of it completes the packet");
148 TEST_CHECK_RET((int) test_source_write(source, "cd", 2), 2);
149 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
150 TEST_CHECK_RET((int) slen, 5);
151 if (slen == 5) TEST_CHECK(memcmp(buf, "\x05""abcd", 5) == 0);
152
153done:
154 talloc_free(ctx);
155}
156
157/** Pipelined packets: a buffer holding more than one packet must still return the first.
158 *
159 * mem.md finding 1. The second path used to compare the whole buffer against the caller's size,
160 * and return BUFFER_TOO_SMALL although a complete packet was sitting at the front.
161 */
162static void test_verify_pipelined(void)
163{
164 TALLOC_CTX *ctx = talloc_init_const("test");
165 test_verify_ctx_t tctx = {};
166 fr_bio_t *mem, *source;
167 uint8_t buf[5];
168 ssize_t slen;
169
170 mem = test_mem_alloc(ctx, &source, &tctx);
171 TEST_CHECK(mem != NULL);
172 if (!mem) goto done;
173
174 TEST_CASE("two packets arrive in one go");
175 TEST_CHECK_RET((int) test_source_write(source, "\x05""abcd" "\x05""efgh", 10), 10);
176
177 TEST_CASE("a one-packet buffer gets the first packet, not an error");
178 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
179 TEST_MSG("returned %zd (%s)", slen, slen < 0 ? fr_bio_strerror(slen) : "no error");
180 TEST_CHECK_RET((int) slen, 5);
181 if (slen == 5) TEST_CHECK(memcmp(buf, "\x05""abcd", 5) == 0);
182
183 TEST_CASE("and the second packet on the next read");
184 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
185 TEST_CHECK_RET((int) slen, 5);
186 if (slen == 5) TEST_CHECK(memcmp(buf, "\x05""efgh", 5) == 0);
187
188done:
189 talloc_free(ctx);
190}
191
192/** A caller buffer smaller than the packet is an error, and loses nothing.
193 */
195{
196 TALLOC_CTX *ctx = talloc_init_const("test");
197 test_verify_ctx_t tctx = {};
198 fr_bio_t *mem, *source;
199 uint8_t small[3], big[64];
200 ssize_t slen;
201
202 mem = test_mem_alloc(ctx, &source, &tctx);
203 TEST_CHECK(mem != NULL);
204 if (!mem) goto done;
205
206 TEST_CHECK_RET((int) test_source_write(source, "\x05""abcd", 5), 5);
207
208 TEST_CASE("too small a buffer is reported as such");
209 TEST_CHECK(fr_bio_read(mem, NULL, small, sizeof(small)) == fr_bio_error(BUFFER_TOO_SMALL));
210
211 TEST_CASE("and the packet is still there for a bigger one");
212 slen = fr_bio_read(mem, NULL, big, sizeof(big));
213 TEST_CHECK_RET((int) slen, 5);
214 if (slen == 5) TEST_CHECK(memcmp(big, "\x05""abcd", 5) == 0);
215
216done:
217 talloc_free(ctx);
218}
219
220/** A verify function which says "close" shuts the chain down.
221 */
222static void test_verify_error_close(void)
223{
224 TALLOC_CTX *ctx = talloc_init_const("test");
225 test_verify_ctx_t tctx = {};
226 fr_bio_t *mem, *source;
227 uint8_t buf[64];
228
229 mem = test_mem_alloc(ctx, &source, &tctx);
230 TEST_CHECK(mem != NULL);
231 if (!mem) goto done;
232
233 TEST_CHECK_RET((int) test_source_write(source, "\x05""abcd", 5), 5);
234 tctx.fail = true;
235
236 TEST_CASE("a verify failure is reported as one");
237 TEST_CHECK(fr_bio_read(mem, NULL, buf, sizeof(buf)) == fr_bio_error(VERIFY));
238
239 TEST_CASE("and the chain is shut down");
240 TEST_CHECK(fr_bio_read(mem, NULL, buf, sizeof(buf)) == fr_bio_error(SHUTDOWN));
241
242done:
243 talloc_free(ctx);
244}
245
246/** Without a verify function the bio is a plain buffer, and hands back what it has.
247 *
248 * mem.md finding 9. A zero from the next bio means no more is coming, and the bytes already
249 * buffered still belong to the application.
250 */
252{
253 TALLOC_CTX *ctx = talloc_init_const("test");
254 fr_bio_t *mem, *source;
255 uint8_t buf[64];
256 ssize_t slen;
257
258 mem = test_mem_alloc(ctx, &source, NULL);
259 TEST_CHECK(mem != NULL);
260 if (!mem) goto done;
261
262 TEST_CHECK_RET((int) test_source_write(source, "abcde", 5), 5);
263
264 TEST_CASE("a small read buffers the rest");
265 slen = fr_bio_read(mem, NULL, buf, 2);
266 TEST_CHECK_RET((int) slen, 2);
267 if (slen == 2) TEST_CHECK(memcmp(buf, "ab", 2) == 0);
268
269 TEST_CASE("asking for more than is left still returns what is left");
270 TEST_MSG("the source has nothing more, but three bytes are buffered");
271 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
272 TEST_CHECK_RET((int) slen, 3);
273 if (slen == 3) TEST_CHECK(memcmp(buf, "cde", 3) == 0);
274
275 TEST_CASE("and then there is nothing");
276 TEST_CHECK_RET((int) fr_bio_read(mem, NULL, buf, sizeof(buf)), 0);
277
278done:
279 talloc_free(ctx);
280}
281
282/** A stub transport which fails recoverably or fatally, as each test chooses.
283 *
284 * On a recoverable failure, the stub returns an error and changes nothing else. On a fatal failure,
285 * the stub first shuts the chain down, as the fd bio does. Only the failing bio decides whether a
286 * failure is recoverable or fatal.
287 */
288typedef struct {
290 bool data_sent; //!< the first read has returned "abcde"
291 bool fatal; //!< shut the chain down before failing
292} stub_t;
293
294static int shutdown_count;
295
296static int cb_shutdown(fr_bio_t *bio) { (void) bio; shutdown_count++; return 0; }
297
300 .write_resume = cb_noop,
301 .read_blocked = cb_noop,
302 .write_blocked = cb_noop,
303 .eof = cb_noop_void,
304 .shutdown = cb_shutdown,
305};
306
307/** Return "abcde" once, and fail every read after that.
308 */
309static ssize_t stub_read(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
310{
311 stub_t *stub = (stub_t *) bio;
312
313 if (stub->data_sent || (size < 5)) {
314 if (stub->fatal) (void) fr_bio_shutdown(bio);
315
316 fr_strerror_const("stub read failure");
317 return fr_bio_error(GENERIC);
318 }
319
320 stub->data_sent = true;
321 memcpy(buffer, "abcde", 5);
322 return 5;
323}
324
325static ssize_t stub_write_fail(fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
326{
327 stub_t *stub = (stub_t *) bio;
328
329 if (stub->fatal) (void) fr_bio_shutdown(bio);
330
331 fr_strerror_const("stub write failure");
332 return fr_bio_error(GENERIC);
333}
334
335/** Accept one byte of each write, so the memory bio buffers the rest.
336 */
337static ssize_t stub_write_one(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
338{
339 return 1;
340}
341
342/** Accept every write in full.
343 */
344static ssize_t stub_write_all(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, size_t size)
345{
346 return size;
347}
348
349static fr_bio_t *stub_alloc(TALLOC_CTX *ctx)
350{
351 stub_t *stub;
352
353 shutdown_count = 0;
354
355 stub = talloc_zero(ctx, stub_t);
356 if (!stub) return NULL;
357
358 stub->bio.read = stub_read;
359 stub->bio.write = stub_write_fail;
360
361 return &stub->bio;
362}
363
364/** The memory bio passes a recoverable write error up to the application, and keeps working.
365 */
367{
368 TALLOC_CTX *ctx = talloc_init_const("test");
369 fr_bio_t *mem, *stub;
370
371 stub = stub_alloc(ctx);
372 TEST_CHECK(stub != NULL);
373 if (!stub) goto done;
374
375 mem = fr_bio_mem_alloc(ctx, 1024, 1024, stub);
376 TEST_CHECK(mem != NULL);
377 if (!mem) goto done;
378
379 fr_bio_cb_set(mem, &stub_cb);
380
381 TEST_CASE("the write gets the error from the stub");
382 TEST_CHECK(fr_bio_write(mem, NULL, "x", 1) == fr_bio_error(GENERIC));
383
384 TEST_CASE("the memory bio does not shut the chain down");
386
387 TEST_CASE("the next write reaches the stub again");
388 stub->write = stub_write_all;
389 TEST_CHECK_RET((int) fr_bio_write(mem, NULL, "x", 1), 1);
390
391done:
392 talloc_free(ctx);
393}
394
395/** The memory bio passes a recoverable flush error up to the application, and keeps the buffered data.
396 */
398{
399 TALLOC_CTX *ctx = talloc_init_const("test");
400 fr_bio_t *mem, *stub;
401
402 stub = stub_alloc(ctx);
403 TEST_CHECK(stub != NULL);
404 if (!stub) goto done;
405
406 mem = fr_bio_mem_alloc(ctx, 1024, 1024, stub);
407 TEST_CHECK(mem != NULL);
408 if (!mem) goto done;
409
410 fr_bio_cb_set(mem, &stub_cb);
411
412 TEST_CASE("a partial write leaves data in the write buffer");
413 stub->write = stub_write_one;
414 TEST_CHECK_RET((int) fr_bio_write(mem, NULL, "hello", 5), 5);
415
416 TEST_CASE("the flush gets the error from the stub");
417 stub->write = stub_write_fail;
418 TEST_CHECK(fr_bio_write(mem, NULL, NULL, SIZE_MAX) == fr_bio_error(GENERIC));
419
420 TEST_CASE("the memory bio does not shut the chain down");
422
423 TEST_CASE("a later flush sends the rest of the buffered data");
424 stub->write = stub_write_all;
425 TEST_CHECK_RET((int) fr_bio_write(mem, NULL, NULL, SIZE_MAX), 4);
426
427done:
428 talloc_free(ctx);
429}
430
431/** After a fatal read error in the next bio, the application still gets the buffered data.
432 *
433 * The stub decides that the error is fatal, and calls fr_bio_shutdown(). The memory bio passes
434 * the error up, and fr_bio_mem_eof() keeps the buffered data for the application.
435 */
436static void test_fatal_read_drains(void)
437{
438 TALLOC_CTX *ctx = talloc_init_const("test");
439 fr_bio_t *mem, *stub;
440 uint8_t buf[64];
441 ssize_t slen;
442
443 stub = stub_alloc(ctx);
444 TEST_CHECK(stub != NULL);
445 if (!stub) goto done;
446
447 mem = fr_bio_mem_alloc(ctx, 1024, 0, stub);
448 TEST_CHECK(mem != NULL);
449 if (!mem) goto done;
450
451 fr_bio_cb_set(mem, &stub_cb);
452
453 TEST_CASE("a small read buffers the rest");
454 slen = fr_bio_read(mem, NULL, buf, 2);
455 TEST_CHECK_RET((int) slen, 2);
456
457 TEST_CASE("the next read fails in the stub, which shuts the chain down");
458 ((stub_t *) stub)->fatal = true;
459 TEST_CHECK(fr_bio_read(mem, NULL, buf, sizeof(buf)) < 0);
460
461 TEST_CASE("writes stop at once, but the teardown waits for the drain");
462 TEST_CHECK(fr_bio_write(mem, NULL, "x", 1) == fr_bio_error(SHUTDOWN));
464
465 TEST_CASE("the application still gets the buffered data");
466 slen = fr_bio_read(mem, NULL, buf, sizeof(buf));
467 TEST_CHECK_RET((int) slen, 3);
468 if (slen == 3) TEST_CHECK(memcmp(buf, "cde", 3) == 0);
469
470 TEST_CASE("an empty buffer completes the shutdown");
471 TEST_CHECK_RET((int) fr_bio_read(mem, NULL, buf, sizeof(buf)), 0);
473
474 TEST_CASE("the chain reports SHUTDOWN once it is torn down");
475 TEST_CHECK(fr_bio_read(mem, NULL, buf, sizeof(buf)) == fr_bio_error(SHUTDOWN));
476
477done:
478 talloc_free(ctx);
479}
480
481/** With the datagram verify reader, the memory bio passes a recoverable read error up to the application.
482 */
484{
485 TALLOC_CTX *ctx = talloc_init_const("test");
486 fr_bio_t *mem, *stub;
487 test_verify_ctx_t tctx = { .fail = false };
488 uint8_t buf[64];
489
490 stub = stub_alloc(ctx);
491 TEST_CHECK(stub != NULL);
492 if (!stub) goto done;
493
494 ((stub_t *) stub)->data_sent = true;
495
496 mem = fr_bio_mem_alloc(ctx, 0, 0, stub);
497 TEST_CHECK(mem != NULL);
498 if (!mem) goto done;
499
500 TEST_CHECK(fr_bio_mem_set_verify(mem, test_verify, &tctx, true) == 0);
501 fr_bio_cb_set(mem, &stub_cb);
502
503 TEST_CASE("the read gets the error from the stub");
504 TEST_CHECK(fr_bio_read(mem, NULL, buf, sizeof(buf)) == fr_bio_error(GENERIC));
505
506 TEST_CASE("the memory bio does not shut the chain down");
508
509done:
510 talloc_free(ctx);
511}
512
514 { "verify_one_packet", test_verify_one_packet },
515 { "verify_partial_packet", test_verify_partial_packet },
516 { "verify_pipelined", test_verify_pipelined },
517 { "verify_buffer_too_small", test_verify_buffer_too_small },
518 { "verify_error_close", test_verify_error_close },
519 { "buffered_read_drains", test_buffered_read_drains },
520 { "recoverable_write_passes_up", test_recoverable_write_passes_up },
521 { "recoverable_flush_passes_up", test_recoverable_flush_passes_up },
522 { "fatal_read_drains", test_fatal_read_drains },
523 { "recoverable_read_datagram", test_recoverable_read_datagram },
525};
static int const char char buffer[256]
Definition acutest.h:635
#define TEST_CHECK(cond)
Definition acutest.h:101
#define TEST_CASE(name)
Definition acutest.h:203
#define TEST_TERMINATOR
Definition acutest.h:77
#define TEST_MSG(...)
Definition acutest.h:234
#define TEST_CHECK_RET(_got, _exp)
fr_bio_write_t _CONST write
write to the underlying bio
Definition base.h:117
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 ssize_t fr_bio_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read raw data from a bio.
Definition base.h:161
fr_bio_io_t read_resume
"unblocked" is too similar to "blocked"
Definition base.h:97
#define fr_bio_error(_x)
Definition base.h:200
static int packet_ctx
the tests pass only the address of packet_ctx
static void test_verify_one_packet(void)
A complete packet is returned, and only one packet at a time.
TEST_LIST
static void test_recoverable_flush_passes_up(void)
The memory bio passes a recoverable flush error up to the application, and keeps the buffered data.
static void test_recoverable_read_datagram(void)
With the datagram verify reader, the memory bio passes a recoverable read error up to the application...
static void cb_noop_void(fr_bio_t *bio)
static ssize_t test_source_write(fr_bio_t *source, char const *data, size_t size)
Put bytes where the memory bio's reads will find them.
static fr_bio_cb_funcs_t test_cb
static fr_bio_t * test_mem_alloc(TALLOC_CTX *ctx, fr_bio_t **source_p, test_verify_ctx_t *tctx)
A memory bio in front of a pipe, which stands in for the network.
static ssize_t stub_read(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Return "abcde" once, and fail every read after that.
static ssize_t stub_write_one(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Accept one byte of each write, so the memory bio buffers the rest.
static ssize_t stub_write_all(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, size_t size)
Accept every write in full.
static void test_recoverable_write_passes_up(void)
The memory bio passes a recoverable write error up to the application, and keeps working.
static void test_verify_error_close(void)
A verify function which says "close" shuts the chain down.
static void test_buffered_read_drains(void)
Without a verify function the bio is a plain buffer, and hands back what it has.
static void test_fatal_read_drains(void)
After a fatal read error in the next bio, the application still gets the buffered data.
static void test_verify_pipelined(void)
Pipelined packets: a buffer holding more than one packet must still return the first.
static int cb_shutdown(fr_bio_t *bio)
static fr_bio_verify_action_t test_verify(UNUSED fr_bio_t *bio, void *verify_ctx, UNUSED void *packet_ctx, const void *buffer, size_t *size)
static fr_bio_t * stub_alloc(TALLOC_CTX *ctx)
static void test_verify_buffer_too_small(void)
A caller buffer smaller than the packet is an error, and loses nothing.
static ssize_t stub_write_fail(fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
static int shutdown_count
bool fail
return ERROR_CLOSE for the next packet
static int cb_noop(fr_bio_t *bio)
static fr_bio_cb_funcs_t stub_cb
static void test_verify_partial_packet(void)
A packet split across two reads is reassembled.
Framing for the tests: the first byte of a packet is its total length.
bool fatal
shut the chain down before failing
bool data_sent
the first read has returned "abcde"
A stub transport which fails recoverably or fatally, as each test chooses.
#define UNUSED
Definition build.h:384
talloc_free(hp)
char const * fr_bio_strerror(ssize_t error)
Definition base.c:225
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:260
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:158
fr_bio_t * fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
Allocate a memory buffer bio.
Definition mem.c:679
int fr_bio_mem_set_verify(fr_bio_t *bio, fr_bio_verify_t verify, void *verify_ctx, bool datagram)
Set the verification function for memory bios.
Definition mem.c:856
fr_bio_verify_action_t
Status returned by the verification callback.
Definition mem.h:32
@ FR_BIO_VERIFY_ERROR_CLOSE
fatal error, the bio should be closed.
Definition mem.h:36
@ FR_BIO_VERIFY_OK
packet is OK
Definition mem.h:33
@ FR_BIO_VERIFY_WANT_MORE
not enough data for one packet
Definition mem.h:35
long int ssize_t
unsigned char uint8_t
fr_bio_t * fr_bio_pipe_alloc(TALLOC_CTX *ctx, fr_bio_cb_funcs_t *cb, size_t buffer_size)
Allocate a thread-safe pipe which can be used for both reads and writes.
Definition pipe.c:187
static bool done
Definition radclient.c:80
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:127
#define VERIFY(_x)
Definition trie.c:130
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1366