The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
mem.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: 3562cc2cb59262a9c57b9b170f32824a26ae8080 $
19 * @file lib/bio/mem.c
20 * @brief BIO abstractions for memory buffers
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/bio/buf.h>
28
29#include <freeradius-devel/bio/mem.h>
30
31typedef enum {
33 FR_BIO_MEM_SOURCE, /* the application writes to it, something else reads */
34 FR_BIO_MEM_SINK, /* something else writes to it, the application reads */
35 FR_BIO_MEM_VERIFY, /* verification only, with no buffers */
36 FR_BIO_MEM_BUFFER, /* we manage local buffers */
38
39/** The memory buffer bio
40 *
41 * It is used to buffer reads / writes to a streaming socket.
42 */
43typedef struct fr_bio_mem_s {
45
46 fr_bio_mem_type_t type; //!< source, sink, etc.
47
48 fr_bio_verify_t verify; //!< verify data to see if we have a packet.
49 void *verify_ctx; //!< verify context
50
51 fr_bio_buf_t read_buffer; //!< buffering for reads
52 fr_bio_buf_t write_buffer; //!< buffering for writes
54
55static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size);
56
57static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size) CC_HINT(nonnull(1,3));
58
59/** At EOF, read data from the buffer until it is empty.
60 *
61 * When "next" bio returns EOF, there may still be pending data in the memory buffer. Return that until it's
62 * empty, and then EOF from then on.
63 */
64static ssize_t fr_bio_mem_read_eof(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
65{
66 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
67
68 /*
69 * No more data: return EOF from now on.
70 */
71 if (fr_bio_buf_used(&my->read_buffer) == 0) {
72
73 /*
74 * Don't call our EOF function. But do tell the other BIOs that we're at EOF.
75 */
76 my->priv_cb.eof = NULL;
77 fr_bio_eof(&my->bio);
78 return 0;
79 }
80
81 /*
82 * Return whatever data we have available. One the buffer is empty, the next read will get EOF.
83 */
84 return fr_bio_buf_read(&my->read_buffer, buffer, size);
85}
86
87static int fr_bio_mem_eof(fr_bio_t *bio)
88{
89 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
90
91 /*
92 * Nothing more for us to read, tell fr_bio_eof() that it can continue with poking other BIOs.
93 */
94 if (fr_bio_buf_used(&my->read_buffer) == 0) {
95 return 1;
96 }
97
98 my->bio.read = fr_bio_mem_read_eof;
99
100 return 0;
101}
102
103/** Read from a memory BIO
104 *
105 * This bio reads as much data as possible into the memory buffer. On the theory that a few memcpy() or
106 * memmove() calls are much cheaper than a system call.
107 *
108 * If the read buffer has enough data to satisfy the read, then it is returned.
109 *
110 * Otherwise the next bio is called to re-fill the buffer. The next read call will try to get as much data
111 * as possible into the buffer, even if that results in reading more than "size" bytes.
112 *
113 * Once the next read has been done, then the data from the buffer is returned, even if it is less than
114 * "size".
115 */
116static ssize_t fr_bio_mem_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
117{
118 ssize_t rcode;
119 size_t used, room;
120 uint8_t *p;
121 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
122 fr_bio_t *next;
123
124 /*
125 * We can satisfy the read from the memory buffer: do so.
126 */
127 used = fr_bio_buf_used(&my->read_buffer);
128 if (size <= used) {
129 return fr_bio_buf_read(&my->read_buffer, buffer, size);
130 }
131
132 /*
133 * There must be a next bio.
134 */
135 next = fr_bio_next(&my->bio);
136 fr_assert(next != NULL);
137
138 /*
139 * If there's no room to store more data in the buffer. Just return whatever data we have in the
140 * buffer.
141 */
142 room = fr_bio_buf_write_room(&my->read_buffer);
143 if (!room) return fr_bio_buf_read(&my->read_buffer, buffer, size);
144
145 /*
146 * We try to fill the buffer as much as possible from the network, even if that means reading
147 * more than "size" amount of data.
148 */
149 p = fr_bio_buf_write_reserve(&my->read_buffer, room);
150 fr_assert(p != NULL); /* otherwise room would be zero */
151
152 rcode = next->read(next, packet_ctx, p, room);
153
154 /*
155 * Ensure that whatever data we have read is marked as "used" in the buffer, and then return
156 * whatever data is available back to the caller.
157 */
158 if (rcode >= 0) {
159 if (rcode > 0) (void) fr_bio_buf_write_alloc(&my->read_buffer, (size_t) rcode);
160
161 return fr_bio_buf_read(&my->read_buffer, buffer, size);
162 }
163
164 /*
165 * The next bio returned an error. Whatever it is, it's fatal. We can read from the memory
166 * buffer until it's empty, but we can no longer write to the memory buffer. Any data written to
167 * the buffer is lost.
168 */
171 return rcode;
172}
173
174/** Return data only if we have a complete packet.
175 *
176 */
177static ssize_t fr_bio_mem_read_verify_stream(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
178{
179 ssize_t rcode;
180 size_t used, room, want;
181 uint8_t *p;
182 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
183 fr_bio_t *next;
184
185 /*
186 * We may be able to satisfy the read from the memory buffer.
187 */
188 used = fr_bio_buf_used(&my->read_buffer);
189 if (used) {
190 /*
191 * See if there are valid packets in the buffer.
192 */
193 rcode = fr_bio_mem_call_verify(bio, packet_ctx, &want);
194 if (rcode < 0) return fr_bio_error(VERIFY);
195
196 /*
197 * There's at least one valid packet, return it.
198 */
199 if (rcode == 1) {
200 /*
201 * This isn't a fatal error. The caller should check how much room is needed by calling
202 * fr_bio_mem_call_verify(), and retry.
203 *
204 * But in general, the caller should make sure that the output buffer has enough
205 * room for at least one packet. The verify() function should also ensure that
206 * the packet is no larger than our application maximum, even if the protocol
207 * allows for it to be larger.
208 */
209 if (want > size) return fr_bio_error(BUFFER_TOO_SMALL);
210
211 return fr_bio_buf_read(&my->read_buffer, buffer, want);
212 }
213
214 /*
215 * Else we need to read more data to have a complete packet.
216 */
217 }
218
219 /*
220 * There must be a next bio.
221 */
222 next = fr_bio_next(&my->bio);
223 fr_assert(next != NULL);
224
225 /*
226 * If there's no room to store more data in the buffer, try to make some room.
227 */
228 room = fr_bio_buf_write_room(&my->read_buffer);
229 if (!room) {
230 room = fr_bio_buf_make_room(&my->read_buffer);
231
232 /*
233 * We've tried to make room and failed. Which means that the buffer is full, AND there
234 * still isn't a complete packet in the buffer. This is therefore an error. The
235 * application has not supplied us with enough read_buffer space to store a complete
236 * packet.
237 *
238 * @todo - allow the application to increase the size of the buffer.
239 */
240 if (!room) return fr_bio_error(BUFFER_FULL);
241 }
242
243 /*
244 * We try to fill the buffer as much as possible from the network. The theory is that a few
245 * extra memcpy() or memmove()s are cheaper than a system call for reading each packet.
246 */
247 p = fr_bio_buf_write_reserve(&my->read_buffer, room);
248 fr_assert(p != NULL); /* otherwise room would be zero */
249
250 rcode = next->read(next, packet_ctx, p, room);
251
252 /*
253 * No data was read from the next bio, we still don't have a packet. Return nothing.
254 */
255 if (rcode == 0) return 0;
256
257 /*
258 * The next bio returned some data. See if it's a valid packet.
259 */
260 if (rcode > 0) {
261 (void) fr_bio_buf_write_alloc(&my->read_buffer, (size_t) rcode);
262
263 want = fr_bio_buf_used(&my->read_buffer);
264
265 if (want > size) return fr_bio_error(BUFFER_TOO_SMALL);
266
267 want = size;
268
269 /*
270 * See if there are valid packets in the buffer.
271 */
272 rcode = fr_bio_mem_call_verify(bio, packet_ctx, &want);
273 if (rcode < 0) return fr_bio_error(VERIFY);
274
275 /*
276 * There's at least one valid packet, return it.
277 */
278 if (rcode == 1) return fr_bio_buf_read(&my->read_buffer, buffer, want);
279
280 /*
281 * No valid packets. The next call to read will call verify again, which will return a
282 * partial packet. And then it will try to fill the buffer from the next bio.
283 */
284 return 0;
285 }
286
287 /*
288 * The other BIO returned an error. It could be transient or permanent. Return that to the
289 * application. If the error is permanent, then the other BIO is responsible for shutting down
290 * the BIO chain.
291 */
292 return rcode;
293}
294
295/** Return data only if we have a complete packet.
296 *
297 */
298static ssize_t fr_bio_mem_read_verify_datagram(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
299{
300 ssize_t rcode;
301 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
302 fr_bio_t *next;
303
304 /*
305 * There must be a next bio.
306 */
307 next = fr_bio_next(&my->bio);
308 fr_assert(next != NULL);
309
310 rcode = next->read(next, packet_ctx, buffer, size);
311
312 /*
313 * No data was read from the next bio, we still don't have a packet. Return nothing.
314 */
315 if (rcode == 0) return 0;
316
317 /*
318 * We have some data.
319 */
320 if (rcode > 0) {
321 size_t want = rcode;
322
323 /*
324 * It's a datagram socket, there can only be one packet in the buffer.
325 *
326 * @todo - if we're allowed more than one packet in the buffer, we should just call
327 * fr_bio_mem_read_verify(), or this function should call fr_bio_mem_call_verify().
328 */
329 switch (my->verify((fr_bio_t *) my, my->verify_ctx, packet_ctx, buffer, &want)) {
330 /*
331 * The data in the buffer is exactly a packet. Return that.
332 *
333 * @todo - if there are multiple packets, return the total size of packets?
334 */
335 case FR_BIO_VERIFY_OK:
336 fr_assert(want <= (size_t) rcode);
337 return want;
338
339 /*
340 * The data in the buffer doesn't make up a complete packet, discard it. The
341 * called verify function should take care of logging.
342 */
344 return 0;
345
347 return 0;
348
349 /*
350 * Some kind of fatal validation error.
351 */
353 break;
354 }
355
356 (void) fr_bio_shutdown(bio);
357 return fr_bio_error(VERIFY);
358 }
359
360 /*
361 * The other BIO returned an error. It could be transient or permanent. Return that to the
362 * application. If the error is permanent, then the other BIO is responsible for shutting down
363 * the BIO chain.
364 */
365 return rcode;
366}
367
368
369/** Pass writes to the next BIO
370 *
371 * For speed, we try to bypass the memory buffer and write directly to the next bio. However, if the next
372 * bio returns EWOULDBLOCK, we write the data to the memory buffer, even if it is partial data.
373 */
374static ssize_t fr_bio_mem_write_next(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
375{
376 int error;
377 ssize_t rcode;
378 size_t room, leftover;
379 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
380 fr_bio_t *next;
381
382 /*
383 * We can't call the next bio if there's still cached data to flush.
384 *
385 * There must be a next bio.
386 */
387 fr_assert(fr_bio_buf_used(&my->write_buffer) == 0);
388
389 next = fr_bio_next(&my->bio);
390 fr_assert(next != NULL);
391
392 /*
393 * The next bio may write all of the data. If so, we return that,
394 */
395 rcode = next->write(next, packet_ctx, buffer, size);
396 if ((size_t) rcode == size) return rcode;
397
398 /*
399 * The next bio returned an error. Anything other than WOULD BLOCK is fatal. We can read from
400 * the memory buffer until it's empty, but we can no longer write to the memory buffer.
401 */
402 if (rcode < 0) {
403 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
404
407 return rcode;
408 }
409
410 /*
411 * We were flushing the BIO, return however much data we managed to write.
412 *
413 * Note that flushes should never block.
414 */
415 if (!buffer) return rcode;
416
417 /*
418 * Tell previous BIOs in the chain that they are blocked.
419 */
420 error = fr_bio_write_blocked(bio);
421 if (error < 0) return error;
422
423 fr_assert(error != 0); /* what to do? */
424
425 /*
426 * We had WOULD BLOCK, or wrote partial bytes. Save the data to the memory buffer, and ensure
427 * that future writes are ordered. i.e. they write to the memory buffer before writing to the
428 * next bio.
429 */
431
432 /*
433 * Clamp the write to however much data is available in the buffer.
434 */
435 leftover = size - rcode;
436 room = fr_bio_buf_write_room(&my->write_buffer);
437
438 /*
439 * If we have "used == 0" above, then we must also have "room > 0".
440 */
441 fr_assert(room > 0);
442
443 if (room < leftover) leftover = room;
444
445 /*
446 * Since we've clamped the write, this call can never fail.
447 */
448 (void) fr_bio_buf_write(&my->write_buffer, ((uint8_t const *) buffer) + rcode, leftover);
449
450 /*
451 * Some of the data base been written to the next bio, and some to our cache. The caller has to
452 * ensure that the first subsequent write will send over the rest of the data.
453 *
454 * However, we tell the caller that we wrote the entire packet. Because we are now responsible
455 * for writing the remaining bytes.
456 */
457 return size;
458}
459
460/** Flush the memory buffer.
461 *
462 */
464{
465 int rcode;
466 size_t used;
467 fr_bio_t *next;
468
469 /*
470 * Nothing to flush, don't do any writes.
471 *
472 * Instead, set the write function to write next, where data will be sent directly to the next
473 * bio, and will bypass the write buffer.
474 */
475 used = fr_bio_buf_used(&my->write_buffer);
476 if (!used) {
477 my->bio.write = fr_bio_mem_write_next;
478 return 0;
479 }
480
481 next = fr_bio_next(&my->bio);
482 fr_assert(next != NULL);
483
484 /*
485 * Clamp the amount of data written. If the caller wants to write everything, it should
486 * pass SIZE_MAX.
487 */
488 if (used < size) size = used;
489
490 /*
491 * Flush the buffer to the next bio in line. That function will write as much data as possible,
492 * but may return a partial write.
493 */
494 rcode = next->write(next, NULL, my->write_buffer.read, size);
495
496 /*
497 * We didn't write anything, the bio is blocked.
498 */
499 if ((rcode == 0) || (rcode == fr_bio_error(IO_WOULD_BLOCK))) return fr_bio_error(IO_WOULD_BLOCK);
500
501 /*
502 * All other errors are fatal. We can read from the memory buffer until it's empty, but we can
503 * no longer write to the memory buffer.
504 */
505 if (rcode < 0) return rcode;
506
507 /*
508 * Tell the buffer that we've read a certain amount of data from it.
509 */
510 (void) fr_bio_buf_read(&my->write_buffer, NULL, (size_t) rcode);
511
512 /*
513 * We haven't emptied the buffer, any further IO is blocked.
514 */
515 if ((size_t) rcode < used) return fr_bio_error(IO_WOULD_BLOCK);
516
517 /*
518 * We've flushed all of the buffer. Revert back to "pass through" writing.
519 */
520 fr_assert(fr_bio_buf_used(&my->write_buffer) == 0);
521 my->bio.write = fr_bio_mem_write_next;
522 return rcode;
523}
524
525/** Write to the memory buffer.
526 *
527 * The special buffer pointer of NULL means flush(). On flush, we call next->read(), and if that succeeds,
528 * go back to "pass through" mode for the buffers.
529 */
530static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
531{
532 size_t room;
533 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
534
535 /*
536 * Flush the output buffer.
537 */
538 if (unlikely(!buffer)) return fr_bio_mem_write_flush(my, size);
539
540 /*
541 * Clamp the write to however much data is available in the buffer.
542 */
543 room = fr_bio_buf_write_room(&my->write_buffer);
544
545 /*
546 * The buffer is full, we can't write anything.
547 */
548 if (!room) return fr_bio_error(IO_WOULD_BLOCK);
549
550 /*
551 * If we're asked to write more bytes than are available in the buffer, then tell the caller that
552 * writes are now blocked, and we can't write any more data.
553 *
554 * Return an WOULD_BLOCK error instead of breaking our promise by writing part of the data,
555 * instead of accepting a full application write.
556 */
557 if (room < size) {
558 int rcode;
559
560 rcode = fr_bio_write_blocked(bio);
561 if (rcode < 0) return rcode;
562
563 return fr_bio_error(IO_WOULD_BLOCK);
564 }
565
566 /*
567 * As we have clamped the write, we know that this call must succeed.
568 */
569 (void) fr_bio_buf_write(&my->write_buffer, buffer, size);
570
571 /*
572 * If we've filled the buffer, tell the caller that writes are now blocked, and we can't write
573 * any more data. However, we still return the amount of data we wrote.
574 */
575 if (room == size) {
576 int rcode;
577
578 rcode = fr_bio_write_blocked(bio);
579 if (rcode < 0) return rcode;
580 }
581
582 return size;
583}
584
585/** Peek at the data in the read buffer
586 *
587 * Peeking at the data allows us to avoid many memory copies.
588 */
589uint8_t const *fr_bio_mem_read_peek(fr_bio_t *bio, size_t *size)
590{
591 size_t used;
592 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
593
594 used = fr_bio_buf_used(&my->read_buffer);
595
596 if (!used) return NULL;
597
598 *size = used;
599 return my->read_buffer.read;
600}
601
602/** Discard data from the read buffer.
603 *
604 * Discarding allows the caller to silently omit packets, so that
605 * they are not passed up to previous bios.
606 */
607void fr_bio_mem_read_discard(fr_bio_t *bio, size_t size)
608{
609 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
610
611 (void) fr_bio_buf_read(&my->read_buffer, NULL, size);
612}
613
614/** Verify that a packet is OK.
615 *
616 * @todo - have this as a parameter to the read routines, so that they only return complete packets?
617 *
618 * @param bio the #fr_bio_mem_t
619 * @param packet_ctx the packet ctx
620 * @param[out] size how big the verified packet is
621 * @return
622 * - <0 for FR_BIO_VERIFY_ERROR_CLOSE, the caller should close the bio.
623 * - 0 for "we have a partial packet", the size to read is in *size
624 * - 1 for "we have at least one good packet", the size of it is in *size
625 */
626static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size)
627{
628 uint8_t *packet, *end;
629 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
630
631 packet = my->read_buffer.read;
632 end = my->read_buffer.write;
633
634 while (packet < end) {
635 size_t want;
636#ifndef NDEBUG
637 size_t used;
638
639 used = end - packet;
640#endif
641
642 want = end - packet;
643
644 switch (my->verify((fr_bio_t *) my, my->verify_ctx, packet_ctx, packet, &want)) {
645 /*
646 * The data in the buffer is exactly a packet. Return that.
647 *
648 * @todo - if there are multiple packets, return the total size of packets?
649 */
650 case FR_BIO_VERIFY_OK:
651 fr_assert(want <= used);
652 *size = want;
653 return 1;
654
655 /*
656 * The packet needs more data. Return how much data we need for one packet.
657 */
659 fr_assert(want > used);
660 *size = want;
661 return 0;
662
664 /*
665 * We don't call fr_bio_buf_read(), because that will move the memory around, and
666 * we want to avoid that if at all possible.
667 */
668 fr_assert(want <= used);
669 fr_assert(packet == my->read_buffer.read);
670 packet = my->read_buffer.read += want;
671 continue;
672
673 /*
674 * Some kind of fatal validation error.
675 */
677 (void) fr_bio_shutdown(bio);
678 return -1;
679 }
680 }
681
682 /*
683 * We haven't returned a full packet, partial packet, or error. We must have discarded
684 * everything in the buffer.
685 */
686 if (my->read_buffer.read == my->read_buffer.write) fr_bio_buf_reset(&my->read_buffer);
687
688 *size = 0;
689 return 0;
690}
691
692/** Allocate a memory buffer bio for either reading or writing.
693 */
694static bool fr_bio_mem_buf_alloc(fr_bio_mem_t *my, fr_bio_buf_t *buf, size_t size)
695{
696 if (size < 1024) size = 1024;
697 if (size > (1 << 20)) size = 1 << 20;
698
699 if (fr_bio_buf_alloc(my, buf, size) < 0) {
701 return false;
702 }
703
704 return true;
705}
706
707/** Allocate a memory buffer bio
708 *
709 * The "read buffer" will cache reads from the next bio in the chain. If the next bio returns more data than
710 * the caller asked for, the extra data is cached in the read buffer.
711 *
712 * The "write buffer" will buffer writes to the next bio in the chain. If the caller writes more data than
713 * the next bio can process, the extra data is cached in the write buffer.
714 *
715 * When the bio is closed (or freed) any pending data in the buffers is lost. The same happens if the next
716 * bio returns a fatal error.
717 *
718 * At some point during a read, the next bio may return EOF. When that happens, the caller should not rely
719 * on the next FD being readable or writable. Instead, it should keep reading from the memory bio until it
720 * returns EOF. See fr_bio_fd_eof() for details.
721 *
722 * @param ctx the talloc ctx
723 * @param read_size size of the read buffer. Must be 1024..1^20
724 * @param write_size size of the write buffer. Can be zero. If non-zero, must be 1024..1^20
725 * @param next the next bio which will perform the underlying reads and writes.
726 * - NULL on error, memory allocation failed
727 * - !NULL the bio
728 */
729fr_bio_t *fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
730{
732
733 my = talloc_zero(ctx, fr_bio_mem_t);
734 if (!my) return NULL;
735
736 /*
737 * We can do 0-sized buffers for read, and the application should then set the verify function.
738 */
739 if (!read_size) {
740 my->type = FR_BIO_MEM_VERIFY;
741 my->bio.read = fr_bio_null_read; /* can't read anything until the verify routine is put in place */
742 my->bio.write = fr_bio_next_write;
743
744 if (write_size > 0) {
746 fr_strerror_const("Invalid write size. If read size is zero, then write size must also be zero");
747 return NULL;
748 }
749
750 } else {
751 /*
752 * We have a read buffer, and potentially a write buffer.
753 */
754 my->type = FR_BIO_MEM_BUFFER;
755
756 if (!fr_bio_mem_buf_alloc(my, &my->read_buffer, read_size)) {
757 oom:
758 fr_strerror_const("Out of memory");
759 return NULL;
760 }
761 my->bio.read = fr_bio_mem_read;
762
763 if (write_size) {
764 if (!fr_bio_mem_buf_alloc(my, &my->write_buffer, write_size)) goto oom;
765
766 /*
767 * Default to passing writes straight through, but buffer them locally if the
768 * write blocks.
769 *
770 * We also only need to resume writes if we're buffering data.
771 */
772 my->bio.write = fr_bio_mem_write_next;
773 my->priv_cb.write_resume = fr_bio_mem_write_resume;
774
775 } else {
776 my->bio.write = fr_bio_next_write;
777 }
778
779 /*
780 * EOF and shutdown are needed if there's a read buffer, but not when the memory bio is
781 * just doing packet verification/
782 */
783 my->priv_cb.eof = fr_bio_mem_eof;
784 }
785
786 fr_bio_chain(&my->bio, next);
787
788 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor); /* always use a common destructor */
789 return (fr_bio_t *) my;
790}
791
792
793/** Allocate a memory buffer which sources data from the callers application into the bio system.
794 *
795 * The caller writes data to the buffer, but never reads from it. This bio will call the "next" bio to write
796 * the data. somewhere.
797 */
798fr_bio_t *fr_bio_mem_source_alloc(TALLOC_CTX *ctx, size_t write_size, fr_bio_t *next)
799{
801
802 /*
803 * The caller has to state that the API is caching data.
804 */
805 if (!write_size) return NULL;
806
807 my = talloc_zero(ctx, fr_bio_mem_t);
808 if (!my) return NULL;
809
810 if (!fr_bio_mem_buf_alloc(my, &my->write_buffer, write_size)) {
811 return NULL;
812 }
813
814 my->type = FR_BIO_MEM_SOURCE;
815 my->bio.read = fr_bio_null_read; /* reading FROM this bio is not possible */
816 my->bio.write = fr_bio_mem_write_next;
817
818 /*
819 * @todo - have write pause / write resume callbacks?
820 */
821
822 fr_bio_chain(&my->bio, next);
823
824 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor);
825 return (fr_bio_t *) my;
826}
827
828/** Read from a buffer which a previous bio has filled.
829 *
830 * This function is called by the application which wants to read from a sink.
831 */
832static ssize_t fr_bio_mem_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
833{
834 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
835
836 return fr_bio_buf_read(&my->read_buffer, buffer, size);
837}
838
839/** Write to the read buffer.
840 *
841 * This function is called by an upstream function which writes into our local buffer.
842 */
843static ssize_t fr_bio_mem_write_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
844{
845 size_t room;
846 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
847
848 /*
849 * Clamp the write to however much data is available in the buffer.
850 */
851 room = fr_bio_buf_write_room(&my->read_buffer);
852
853 /*
854 * The buffer is full. We're now blocked.
855 */
856 if (!room) return fr_bio_error(IO_WOULD_BLOCK);
857
858 if (room < size) size = room;
859
860 /*
861 * As we have clamped the write, we know that this call must succeed.
862 */
863 return fr_bio_buf_write(&my->read_buffer, buffer, size);
864}
865
866/** Allocate a memory buffer which sinks data from a bio system into the callers application.
867 *
868 * The caller reads data from this bio, but never writes to it. Upstream BIOs will source the data.
869 */
870fr_bio_t *fr_bio_mem_sink_alloc(TALLOC_CTX *ctx, size_t read_size)
871{
873
874 /*
875 * The caller has to state that the API is caching data.
876 */
877 if (!read_size) return NULL;
878
879 my = talloc_zero(ctx, fr_bio_mem_t);
880 if (!my) return NULL;
881
882 if (!fr_bio_mem_buf_alloc(my, &my->read_buffer, read_size)) {
883 return NULL;
884 }
885
886 my->type = FR_BIO_MEM_SINK;
887 my->bio.read = fr_bio_mem_read_buffer;
888 my->bio.write = fr_bio_mem_write_read_buffer; /* the upstream will write to our read buffer */
889
890 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor); /* always use a common destructor */
891 return (fr_bio_t *) my;
892}
893
894/** Set the verification function for memory bios.
895 *
896 * It is possible to add a verification function. It is not currently possible to remove one.
897 *
898 * @param bio the binary IO handler
899 * @param verify the verification function
900 * @param verify_ctx to pass to the verification function
901 * @param datagram whether or not this bio is a datagram one.
902 * @return
903 * - <0 on error
904 * - 0 on success
905 */
906int fr_bio_mem_set_verify(fr_bio_t *bio, fr_bio_verify_t verify, void *verify_ctx, bool datagram)
907{
908 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
909
910 switch (my->type) {
912 fr_assert(0);
913 return -1;
914
916 case FR_BIO_MEM_SINK:
917 fr_strerror_const("Cannot add verify to this memory BIO");
918 return fr_bio_error(GENERIC);
919
921 fr_assert(my->bio.write == fr_bio_next_write);
922 if (!datagram) {
923 fr_strerror_const("Invalid memory BIO - we need a read buffer for verifying packets from a stream socket");
924 return -1;
925 }
927
929 break;
930 }
931
932 my->verify = verify;
933 my->verify_ctx = verify_ctx;
934
935 /*
936 * For reading datagrams, we just verify the packet in place. This works both when we have local
937 * buffers, and when we are verifying packets in the application-supplied buffer.
938 *
939 * For writing datagrams, then we cannot buffer individual datagrams. We must write
940 * either all of the datagram out, or none of it.
941 */
942 if (datagram) {
944 my->bio.write = fr_bio_next_write;
945
946 /*
947 * Might as well free the memory for the write buffer. It won't be used.
948 */
949 if (my->write_buffer.start) {
950 talloc_free(my->write_buffer.start);
951 my->write_buffer = (fr_bio_buf_t) {};
952 }
953 } else {
955 /* don't touch the write function or the write buffer. */
956 }
957
958 return 0;
959}
960
961/*
962 * There's no fr_bio_mem_write_blocked()
963 */
964
965/** See if we can resume writes to the memory bio.
966 *
967 * Note that there is no equivalent fr_bio_mem_write_blocked(), as that function wouldn't do anything.
968 * Perhaps it could swap the write function to fr_bio_mem_write_buffer(), but the fr_bio_mem_write_next()
969 * function should automatically do that when the write to the next bio only writes part of the data,
970 * or if it returns fr_bio_error(IO_WOULD_BLOCK)
971 */
973{
974 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
975 ssize_t rcode;
976
977 if (bio->write != fr_bio_mem_write_buffer) return 1;
978
980
981 /*
982 * Flush the buffer, and then reset the write routine if we were successful.
983 */
984 rcode = fr_bio_mem_write_flush(my, SIZE_MAX);
985 if (rcode <= 0) return rcode;
986
987 if (fr_bio_buf_used(&my->write_buffer) > 0) return 0;
988
989 /*
990 * Check for an application hook to check if we can resume writes.
991 */
992 if (!my->cb.write_resume) return 1;
993
994 return my->cb.write_resume(bio);
995}
996
997/** Pause writes.
998 *
999 * Calls to fr_bio_write() will write to the memory buffer, and not
1000 * to the next bio. You MUST call fr_bio_mem_write_resume() after
1001 * this to flush any data.
1002 */
1004{
1005 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
1006
1007 if (my->bio.write == fr_bio_mem_write_buffer) return 0;
1008
1009 /*
1010 * Sink only, can't pause.
1011 */
1012 if (my->bio.write == fr_bio_mem_write_read_buffer) return -1;
1013
1014 my->bio.write = fr_bio_mem_write_buffer;
1015
1016 return 0;
1017}
static int const char char buffer[256]
Definition acutest.h:578
fr_bio_write_t _CONST write
write to the underlying bio
Definition base.h:117
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:116
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:131
#define fr_bio_error(_x)
Definition base.h:200
static void fr_bio_chain(fr_bio_t *first, fr_bio_t *second)
Chain one bio after another.
Definition bio_priv.h:84
size_t fr_bio_buf_make_room(fr_bio_buf_t *bio_buf)
Definition buf.c:28
size_t fr_bio_buf_read(fr_bio_buf_t *bio_buf, void *buffer, size_t size)
Definition buf.c:48
int fr_bio_buf_alloc(TALLOC_CTX *ctx, fr_bio_buf_t *bio_buf, size_t size)
Definition buf.c:117
ssize_t fr_bio_buf_write(fr_bio_buf_t *bio_buf, const void *buffer, size_t size)
Definition buf.c:84
static size_t fr_bio_buf_write_room(fr_bio_buf_t const *bio_buf)
Definition buf.h:82
static size_t fr_bio_buf_used(fr_bio_buf_t const *bio_buf)
Definition buf.h:73
static void fr_bio_buf_reset(fr_bio_buf_t *bio_buf)
Definition buf.h:61
static uint8_t * fr_bio_buf_write_reserve(fr_bio_buf_t *bio_buf, size_t size)
Definition buf.h:89
static int fr_bio_buf_write_alloc(fr_bio_buf_t *bio_buf, size_t size)
Definition buf.h:98
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
void fr_bio_shutdown & my
Definition fd_errno.h:70
talloc_free(hp)
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:272
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:212
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition base.c:35
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:64
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
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:729
static ssize_t fr_bio_mem_write_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
Write to the read buffer.
Definition mem.c:843
static ssize_t fr_bio_mem_read_verify_stream(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return data only if we have a complete packet.
Definition mem.c:177
void * verify_ctx
verify context
Definition mem.c:49
void fr_bio_mem_read_discard(fr_bio_t *bio, size_t size)
Discard data from the read buffer.
Definition mem.c:607
fr_bio_t * fr_bio_mem_sink_alloc(TALLOC_CTX *ctx, size_t read_size)
Allocate a memory buffer which sinks data from a bio system into the callers application.
Definition mem.c:870
fr_bio_mem_type_t
Definition mem.c:31
@ FR_BIO_MEM_SINK
Definition mem.c:34
@ FR_BIO_MEM_INVALID
Definition mem.c:32
@ FR_BIO_MEM_SOURCE
Definition mem.c:33
@ FR_BIO_MEM_BUFFER
Definition mem.c:36
@ FR_BIO_MEM_VERIFY
Definition mem.c:35
fr_bio_buf_t read_buffer
buffering for reads
Definition mem.c:51
static int fr_bio_mem_eof(fr_bio_t *bio)
Definition mem.c:87
struct fr_bio_mem_s fr_bio_mem_t
The memory buffer bio.
static ssize_t fr_bio_mem_write_next(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Pass writes to the next BIO.
Definition mem.c:374
static ssize_t fr_bio_mem_read_verify_datagram(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return data only if we have a complete packet.
Definition mem.c:298
fr_bio_t * fr_bio_mem_source_alloc(TALLOC_CTX *ctx, size_t write_size, fr_bio_t *next)
Allocate a memory buffer which sources data from the callers application into the bio system.
Definition mem.c:798
static ssize_t fr_bio_mem_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Read from a buffer which a previous bio has filled.
Definition mem.c:832
int fr_bio_mem_write_resume(fr_bio_t *bio)
See if we can resume writes to the memory bio.
Definition mem.c:972
fr_bio_buf_t write_buffer
buffering for writes
Definition mem.c:52
fr_bio_verify_t verify
verify data to see if we have a packet.
Definition mem.c:48
FR_BIO_COMMON
Definition mem.c:44
static ssize_t fr_bio_mem_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a memory BIO.
Definition mem.c:116
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:906
fr_bio_mem_type_t type
source, sink, etc.
Definition mem.c:46
static ssize_t fr_bio_mem_read_eof(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
At EOF, read data from the buffer until it is empty.
Definition mem.c:64
static bool fr_bio_mem_buf_alloc(fr_bio_mem_t *my, fr_bio_buf_t *buf, size_t size)
Allocate a memory buffer bio for either reading or writing.
Definition mem.c:694
static ssize_t fr_bio_mem_write_flush(fr_bio_mem_t *my, size_t size)
Flush the memory buffer.
Definition mem.c:463
static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size))
Verify that a packet is OK.
Definition mem.c:626
int fr_bio_mem_write_pause(fr_bio_t *bio)
Pause writes.
Definition mem.c:1003
uint8_t const * fr_bio_mem_read_peek(fr_bio_t *bio, size_t *size)
Peek at the data in the read buffer.
Definition mem.c:589
static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
The memory buffer bio.
Definition mem.c:43
@ FR_BIO_VERIFY_ERROR_CLOSE
fatal error, the bio should be closed.
Definition mem.h:36
@ FR_BIO_VERIFY_DISCARD
the packet should be discarded
Definition mem.h:34
@ 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
fr_bio_verify_action_t(* fr_bio_verify_t)(fr_bio_t *bio, void *verify_ctx, void *packet_ctx, const void *buffer, size_t *size)
Verifies the packet.
Definition mem.h:51
long int ssize_t
unsigned char uint8_t
static size_t used
ssize_t fr_bio_null_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:39
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
#define fr_assert(_expr)
Definition rad_assert.h:38
#define VERIFY(_x)
Definition trie.c:130
#define fr_strerror_const(_msg)
Definition strerror.h:223
int nonnull(2, 5))