5#include <freeradius-devel/util/dbuff.h>
27 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
63 base = mmap(NULL, pagesz * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
65 TEST_ASSERT(mprotect(base + pagesz, pagesz, PROT_NONE) == 0);
69 TEST_CASE(
"FR_DBUFF_INIT on a zero length buffer");
75 TEST_CASE(
"Every write to a zero length buffer fails");
83 munmap(base, pagesz * 2);
87{
uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
90 TEST_CASE(
"Confirm init returns parentless dbuff");
98 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
102 TEST_CASE(
"Confirm max constrains available space");
130 uint64_t u64val = 0x123456789abcdef0;
131 int16_t i16val = 0x1234;
132 int32_t i32val = 0xd34d;
133 int64_t i64val = 0x123456789abcdef0;
134 float float_in = 1.0f + FLT_EPSILON;
136 double double_in = 1.0 + DBL_EPSILON;
137 double double_out = 0;
138 uint64_t u64v_vals[] = {
139 0, 0x12, 0x3412, 0x563412, 0x78563412, 0x9a78563412,
140 0xbc9a78563412, 0xdebc9a78563412, 0xf0debc9a78563412
143 TEST_CASE(
"Generate wire format unsigned 16-bit value");
151 TEST_CASE(
"Generate wire format unsigned 16-bit value using marker");
158 TEST_CASE(
"Generate wire format unsigned 32-bit value");
165 TEST_CASE(
"Generate wire format unsigned 64-bit value");
172 TEST_CASE(
"Generate wire format signed 16-bit value");
179 TEST_CASE(
"Generate wire format signed 32-bit value");
186 TEST_CASE(
"Generate wire format signed 64-bit value");
193 TEST_CASE(
"Generate wire format variable-width");
194 for (
size_t i = 0; i < (
sizeof(u64v_vals) /
sizeof(uint64_t)); i++) {
195 uint64_t val = u64v_vals[i];
199 for (num_bytes = 1; (val & ~((uint64_t) 0xff)) != 0; num_bytes++) val >>= 8;
203 for (
int j = num_bytes; --j >= 0; ) {
217 TEST_CHECK(memcmp(&float_out, &float_in,
sizeof(
float)) == 0);
219 TEST_CASE(
"Generate wire-format double");
225 TEST_CHECK(memcmp(&double_out, &double_in,
sizeof(
double)) == 0);
227 TEST_CASE(
"Refuse to write to too-small space");
232 TEST_CASE(
"Input bytes using dbuff current position");
250 uint8_t in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
253 size_t init_remaining;
255 TEST_CASE(
"Confirm no-advance dbuff operations don't affect ancestors' position");
258 no_advance_dbuff =
FR_DBUFF(&dbuff);
270 uint8_t buff1[26], buff2[26], buff3[10];
274 memcpy(buff1,
"abcdefghijklmnopqrstuvwxyz",
sizeof(buff1));
275 memcpy(buff2,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
sizeof(buff2));
276 memcpy(buff3,
"0123456789",
sizeof(buff3));
287 TEST_CHECK(memcmp(dbuff1.start,
"ABCDEFGHIJKLMnopqrstuvwxyz", 26) == 0);
293 TEST_CHECK(memcmp(dbuff2.start,
"ABCD0123456789OPQRSTUVWXYZ", 26) == 0);
300 TEST_CHECK(memcmp(dbuff1.start,
"ABCDEFGHIJKLMHIJKLMtuvwxyz", 26) == 0);
306 TEST_CHECK(memcmp(dbuff2.start,
"ABCD0123456789HIJKLMtuWXYZ", 26) == 0);
316 fr_dbuff_uctx_talloc_t tctx1, tctx2;
318 uint8_t const value[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
328 TEST_CASE(
"Markers track extended buffer");
330 TEST_CASE(
"Already-written content stays with the buffer");
332 TEST_CASE(
"Refuse to extend past specified maximum");
334 TEST_CASE(
"Extend move destination if possible and input length demands");
350 fr_dbuff_uctx_talloc_t tctx;
358 TEST_CASE(
"Check that dbuff2 inherits extend fields");
365 TEST_CASE(
"Check that FR_DBUFF_MAX_BIND_CURRENT() is not extensible");
384 fr_dbuff_uctx_fd_t fctx;
406 TEST_CASE(
"Leftover byte plus data from next extend");
418 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
419 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
437 TEST_CASE(
"Confirm that max precludes another shift/extend");
443 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
444 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
456 uint8_t const buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
466 uint64_t u64val2 = 0;
471 float fval1 = 1.5, fval2 = 0;
472 double dval1 = 2048.0625, dval2 = 0;
477 TEST_CASE(
"Check dbuff reads of unsigned integers");
488 TEST_CASE(
"Don't walk off the end of the buffer");
491 TEST_CASE(
"Check dbuff reads using markers");
499 TEST_CASE(
"Check dbuff reads of signed integers");
511 TEST_CASE(
"Check dbuff reads of floating point values");
515 TEST_CHECK(memcmp(&fval1, &fval2,
sizeof(fval1)) == 0);
520 TEST_CHECK(memcmp(&dval1, &dval2,
sizeof(dval1)) == 0);
522 TEST_CASE(
"Check variable length uint64_t read");
536 memset(buff3, 0,
sizeof(buff3));
548 memset(buff3, 0,
sizeof(buff3));
568 TEST_CASE(
"FR_DBUFF: start bound to parent 'current', parent not advanced");
579 TEST_CASE(
"FR_DBUFF_ABS: start bound to parent 'start', parent not advanced");
589 TEST_CASE(
"FR_DBUFF_BIND_CURRENT: writes advance parent 'current'");
597 TEST_CASE(
"FR_DBUFF_BIND_CURRENT_ABS: start bound to parent 'start', writes advance parent 'current'");
607 TEST_CASE(
"FR_DBUFF_BIND_END_ABS: writes advance parent 'end' (producer side)");
617 TEST_CASE(
"FR_DBUFF_MAX: caps available space, non-bind variant leaves parent alone");
625 TEST_CASE(
"FR_DBUFF_MAX: _max larger than remaining is clamped to remaining");
651 TEST_CASE(
"marker behind then ahead of parent");
660 TEST_CASE(
"marker accessors resolve through parent");
683 TEST_CASE(
"fr_dbuff_set by size_t offset, pointer, and out-of-range");
699 TEST_CASE(
"fr_dbuff_set_end trims the 'end' pointer");
715 fr_dbuff_uctx_talloc_t tctx;
719 TEST_CASE(
"advance within the initial allocation");
723 TEST_CASE(
"advance past the current size triggers an extend");
727 TEST_CASE(
"advance past max fails and does not advance");
747 TEST_CASE(
"memset that does not fit returns bytes needed and does not advance");
756 uint8_t const src[] = { 0x11, 0x22, 0x33, 0x44 };
757 uint8_t sbuf[4] = { 0x0a, 0x0b, 0x0c, 0x0d };
758 char const *str =
"abc";
762 TEST_CASE(
"exact copy from a byte buffer");
770 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == 4);
774 TEST_CASE(
"copy from a C string with SIZE_MAX uses strlen");
779 TEST_CASE(
"copy that does not fit fails entirely and does not advance");
781 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == -2);
784 TEST_CASE(
"copy from another dbuff, source is not advanced");
792 TEST_CASE(
"SIZE_MAX with a dbuff source copies the source's remaining bytes");
795 TEST_CHECK(_fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(&dbuff), &dbuff, &src_dbuff.p, &src_dbuff, SIZE_MAX) == 4);
798 TEST_CASE(
"partial copy writes as much as fits and reports it");
800 TEST_CHECK(_fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(&dbuff), &dbuff, src,
sizeof(src)) == 2);
804 TEST_CASE(
"in_bytes_partial truncates to the available space");
817 TEST_CASE(
"plain release trims the marker list back to the previous marker");
827 TEST_CASE(
"release_behind returns how far the marker trailed the parent");
836 TEST_CASE(
"release_ahead returns how far the marker led the parent");
845 uint8_t const pos[] = { 0x7f, 0xff };
846 uint8_t const neg[] = { 0xff, 0x00 };
855 TEST_CASE(
"negative two-byte value is sign extended");
865 TEST_CASE(
"not enough data returns bytes needed");
876 memcpy(
buff,
"ABCDEFGH",
sizeof(
buff));
880 TEST_CASE(
"shift discards consumed bytes and moves the rest down");
901 TEST_CASE(
"relative offsets are preserved against the new buffer");
914 fr_dbuff_uctx_talloc_t tctx;
917 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
920 TEST_CASE(
"trim to content length (SIZE_MAX)");
922 TEST_CHECK(talloc_array_length(dbuff.buff) == 4);
927 TEST_CHECK(talloc_array_length(dbuff.buff) == 2);
929 TEST_CASE(
"reset restores the initial length and clears the position");
931 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
934 TEST_CASE(
"free_talloc releases the buffer");
945 TEST_CASE(
"compound literal points at the supplied buffer and is writable");
961 fr_dbuff_uctx_talloc_t tctx;
964 TEST_CASE(
"fixed buffer: extend returns remaining and never grows");
968 TEST_CASE(
"fixed buffer at end: cannot satisfy lowat");
975 TEST_CASE(
"talloc buffer: extend grows and flags report it");
996 fr_dbuff_uctx_talloc_t tctx;
1000 TEST_CASE(
"a writable talloc dbuff extends");
1008 TEST_CASE(
"the same dbuff marked const does not");
1011 buff_before = dbuff.buff;
1039 fr_dbuff_uctx_talloc_t tctx;
1043 uint8_t const expected[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
1045 TEST_CASE(
"the consumer starts empty, the producer holds the whole buffer");
1051 TEST_CASE(
"a write through the producer is what the consumer reads");
1055 TEST_CASE(
"extending through the producer repairs both cursors");
1060 TEST_CASE(
"an over-large read on the consumer extends nothing");
1061 buff_before = consumer.buff;
1068 TEST_CASE(
"the consumer reads back what the producer wrote");
1073 consumer.is_const = 0;
1086 uint8_t const src_buff[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
1091 TEST_CASE(
"fr_dbuff_move: a request larger than the source copies what is there");
1100 TEST_CASE(
"fr_dbuff_move: the destination clamps the copy too");
1105 TEST_CHECK(memcmp(small, src_buff,
sizeof(small)) == 0);
1107 TEST_CASE(
"fr_dbuff_out_memcpy: an exact request advances the source");
1113 TEST_CASE(
"fr_dbuff_out_memcpy: an over-large request copies, then reports the shortfall");
1136 fr_dbuff_uctx_talloc_t tctx;
1141 TEST_CASE(
"the bind marks the consumer const and non-extendable");
1149 TEST_CASE(
"the producer keeps what the consumer had");
1155 TEST_CASE(
"the producer can still extend, and the consumer follows");
1156 buff_before = consumer.buff;
1164 TEST_CASE(
"the consumer refuses to extend however much is asked for");
1165 buff_before = consumer.buff;
1172 consumer.is_const = 0;
1175 TEST_CASE(
"binding a fixed buffer leaves the producer writable and extendless");
1196 fr_dbuff_uctx_talloc_t tctx;
1209 TEST_CASE(
"second round: a write after a full read is visible");
1215 TEST_CASE(
"a partial read leaves the rest for the next pass");
1224 TEST_CASE(
"fr_dbuff_shift through the producer reclaims what was read");
1232 consumer.is_const = 0;
#define TEST_ASSERT(cond)
Common initialisation for acutest binaries.
#define TEST_CHECK_SLEN(_got, _exp)
#define TEST_CHECK_LEN(_got, _exp)
static size_t test_page_size(void)
Return the system page size, aborting the test if sysconf() fails.
int fr_dbuff_reset_talloc(fr_dbuff_t *dbuff)
Reset a talloced buffer to its initial length, clearing any data stored.
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len)
Update all markers and pointers in the set of dbuffs to point to new_buff.
size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift)
Shift the contents of the dbuff, returning the number of bytes we managed to shift.
#define fr_dbuff_in_bytes_partial(_dbuff,...)
Copy a partial byte sequence into a dbuff.
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define FR_DBUFF_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_ptr(_dbuff_or_marker)
Return a pointer to the dbuff.
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
static fr_dbuff_t * fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx, uint8_t *buff, size_t len, int fd, size_t max)
Initialise a special dbuff which automatically reads in more data as the buffer is exhausted.
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
static size_t fr_dbuff_marker_release_behind(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was behind p.
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
#define fr_dbuff_out_uint64v(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
#define fr_dbuff_was_extended(_status)
Check if the dbuff was extended during the last extend call.
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
#define FR_DBUFF_INIT(_out, _start, _len_or_end)
Initialise a dbuff for encoding, and define the first byte of the output buffer.
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c.
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
#define fr_dbuff_advance_extend(_dbuff_or_marker, _len)
Advance current'position in dbuff or marker by _len bytes (extending if necessary)
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num)
Copy an integer value into a dbuff or marker using our internal variable length encoding.
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
#define fr_dbuff_set_to_end(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'end' of the buffer.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
#define fr_dbuff_is_extendable(_status)
Check if a dbuff can be extended again.
#define fr_dbuff_move(_out, _in, _len)
Copy in as many bytes as possible from one dbuff or marker to another.
#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
static size_t fr_dbuff_marker_release_ahead(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p.
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
#define fr_dbuff_out_int64v(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order signed integer.
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static void test_dbuff_set(void)
Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
static void test_dbuff_init_no_parent(void)
static void test_dbuff_extend(void)
Test the extension-request API: fr_dbuff_extend, fr_dbuff_extend_lowat, fr_dbuff_is_extendable and fr...
static void fd_body(fr_dbuff_t *dbuff, uint8_t const data[])
static void test_dbuff_producer_consumer_rounds(void)
A consumer which is drained, refilled, and drained again.
static void test_dbuff_fd_shell(fr_dbuff_fd_test_body body, uint8_t const data[], size_t datasize, uint8_t buff[], size_t buffsize, size_t max)
static void test_dbuff_advance_extend(void)
Test fr_dbuff_advance_extend against a talloc-backed (extensible) dbuff.
void(* fr_dbuff_fd_test_body)(fr_dbuff_t *dbuff, uint8_t const data[])
static void test_dbuff_talloc_extend(void)
Test extensible dbuffs.
static void test_dbuff_out(void)
Test functions that read from dbuffs.
static void test_dbuff_max(void)
static void test_dbuff_drain(void)
Draining a buffer without knowing in advance how much is in it.
static void test_dbuff_talloc_extend_multi_level(void)
static void test_dbuff_in_memcpy(void)
Test fr_dbuff_in_memcpy, fr_dbuff_in_memcpy_partial and fr_dbuff_in_bytes_partial.
static void test_dbuff_init(void)
static void max_body(fr_dbuff_t *dbuff, uint8_t const data[])
static void test_dbuff_no_advance(void)
static void test_dbuff_tmp(void)
Test FR_DBUFF_TMP, the compound-literal dbuff.
static void test_dbuff_measure(void)
Test the measurement / accessor macros against both a dbuff and a marker.
static void test_dbuff_child(void)
Test the child-dbuff macros: FR_DBUFF, FR_DBUFF_ABS, FR_DBUFF_BIND_CURRENT, FR_DBUFF_BIND_CURRENT_ABS...
static void test_dbuff_memset(void)
Test fr_dbuff_memset.
static void test_dbuff_update(void)
Test fr_dbuff_update repoints the dbuff and its markers after a buffer move.
static void test_dbuff_trim_reset_talloc(void)
Test fr_dbuff_trim_talloc, fr_dbuff_reset_talloc and fr_dbuff_free_talloc.
static void test_dbuff_net_encode(void)
Test the various dbuff_net_encode() functions and macros.
static void test_dbuff_move(void)
static void test_dbuff_const_no_extend(void)
A const dbuff must never extend.
static void test_dbuff_fd(void)
static void test_dbuff_init_zero_length(void)
A zero length output buffer accepts nothing, and nothing is written to the buffer.
static void test_dbuff_producer_consumer(void)
A producer and a consumer sharing one talloc buffer.
static void test_dbuff_shift(void)
Test fr_dbuff_shift moves unconsumed content to the front of the buffer.
static void test_dbuff_fd_max(void)
static void test_dbuff_marker_release(void)
Test fr_dbuff_marker_release, fr_dbuff_marker_release_behind and _ahead.
static void test_dbuff_out_int64v(void)
Test fr_dbuff_out_int64v, which sign-extends based on the most significant bit.
static void test_dbuff_bind_end_abs_extend(void)
FR_DBUFF_BIND_END_ABS hands the extend function to the producer.
static char buff[sizeof("18446744073709551615")+3]
static fr_sbuff_err_t char size_t fr_sbuff_t * in
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
static fr_sbuff_err_t char ** out