The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
dbuff_tests.c
Go to the documentation of this file.
2#include "acutest_helpers.h"
3#include <float.h>
4
5#include <freeradius-devel/util/dbuff.h>
6
7#include <sys/mman.h>
8#include <unistd.h>
9
10/*
11 * The clang static analyser does not inline acutest_check_(), which
12 * is variadic and large, so the analyser cannot see that TEST_ASSERT()
13 * aborts the test. The analyser then follows the path where the
14 * allocation failed into the rest of the test and reports arithmetic
15 * on the zeroed buffer. MEM() exits through a function that the
16 * analyser models as never returning, so MEM() wraps the talloc
17 * buffer inits below instead of TEST_ASSERT().
18 */
19
20/*
21 * Type for a function with the internals of a test of fd flavored dbuffs.
22 */
23typedef void (*fr_dbuff_fd_test_body)(fr_dbuff_t *dbuff, uint8_t const data[]);
24
25static void test_dbuff_init(void)
26{
27 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
28 fr_dbuff_t dbuff;
29
30 TEST_CASE("Parse init with size");
31 fr_dbuff_init(&dbuff, in, sizeof(in));
32
33 TEST_CHECK(dbuff.start == in);
34 TEST_CHECK(dbuff.p == in);
35 TEST_CHECK(dbuff.end == in + sizeof(in));
36
37 TEST_CASE("Parse init with end");
38 fr_dbuff_init(&dbuff, in, in + sizeof(in));
39
40 TEST_CHECK(dbuff.start == in);
41 TEST_CHECK(dbuff.p == in);
42 TEST_CHECK(dbuff.end == in + sizeof(in));
43
44 TEST_CASE("Parse init with const end");
45 fr_dbuff_init(&dbuff, in, (uint8_t const *)(in + sizeof(in)));
46
47 TEST_CHECK(dbuff.start == in);
48 TEST_CHECK(dbuff.p == in);
49 TEST_CHECK(dbuff.end == in + sizeof(in));
50}
51
52/** A zero length output buffer accepts nothing, and nothing is written to the buffer
53 *
54 * The buffer sits against an unwritable page, so a write of even one byte past the end
55 * faults rather than landing on whatever follows the buffer.
56 */
58{
59 fr_dbuff_t dbuff;
60 size_t pagesz = test_page_size();
61 uint8_t *base, *data;
62
63 base = mmap(NULL, pagesz * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
64 TEST_ASSERT(base != MAP_FAILED);
65 TEST_ASSERT(mprotect(base + pagesz, pagesz, PROT_NONE) == 0);
66
67 data = base + pagesz; /* zero bytes, and the next byte is unwritable */
68
69 TEST_CASE("FR_DBUFF_INIT on a zero length buffer");
70 FR_DBUFF_INIT(&dbuff, data, (size_t) 0);
71
72 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 0);
73 TEST_CHECK(fr_dbuff_extend_lowat(NULL, &dbuff, 1) == 0);
74
75 TEST_CASE("Every write to a zero length buffer fails");
76 TEST_CHECK(fr_dbuff_in_bytes(&dbuff, 0x01) == -1);
77 TEST_CHECK(fr_dbuff_in_memcpy(&dbuff, (uint8_t const *)"ab", (size_t) 2) == -2);
78 TEST_CHECK(fr_dbuff_in(&dbuff, (uint16_t) 0x1234) == -2);
79 TEST_CHECK(fr_dbuff_memset(&dbuff, 0x00, 1) == -1);
80
81 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
82
83 munmap(base, pagesz * 2);
84}
85
87{ uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04 };
88 fr_dbuff_t dbuff;
89
90 TEST_CASE("Confirm init returns parentless dbuff");
91 fr_dbuff_init(&dbuff, in, sizeof(in));
92
93 TEST_CHECK(dbuff.parent == NULL);
94}
95
96static void test_dbuff_max(void)
97{
98 uint8_t const in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
99 fr_dbuff_t dbuff;
100 fr_dbuff_t max_dbuff;
101
102 TEST_CASE("Confirm max constrains available space");
103 fr_dbuff_init(&dbuff, in, sizeof(in));
104
105 max_dbuff = FR_DBUFF_MAX_BIND_CURRENT(&dbuff, 4);
106 TEST_CHECK(fr_dbuff_remaining(&max_dbuff) == 4);
107
108 max_dbuff = FR_DBUFF_MAX_BIND_CURRENT(&dbuff, 2 * sizeof(in));
109 TEST_CHECK(fr_dbuff_remaining(&max_dbuff) == sizeof(in));
110}
111
112
113/** Test the various dbuff_net_encode() functions and macros
114 *
115 * @note Passing constants to fr_dbuff_in() as it is written results in
116 * warnings about narrowing casts on the constants--but those casts are in
117 * the underlying inlined fr_nbo_from*() functions. They have to be there;
118 * that's how those functions work. (The tests worked despite the warnings.)
119 * Using variables avoids the warnings, at least with the compile options
120 * the build system uses by default.
121 */
122static void test_dbuff_net_encode(void)
123{
124 uint8_t buff[sizeof(uint64_t)];
125 fr_dbuff_t dbuff;
126 fr_dbuff_marker_t marker;
127 uint16_t u16val = 0x1234;
128 uint16_t u16val2 = 0xcdef;
129 uint32_t u32val = 0x12345678;
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;
135 float float_out = 0;
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
141 };
142
143 TEST_CASE("Generate wire format unsigned 16-bit value");
144 memset(buff, 0, sizeof(buff));
145 fr_dbuff_init(&dbuff, buff, sizeof(buff));
146 fr_dbuff_marker(&marker, &dbuff);
147
148 TEST_CHECK(fr_dbuff_in(&dbuff, u16val) == sizeof(uint16_t));
149 TEST_CHECK(*((uint16_t *)buff) == htons(u16val));
150
151 TEST_CASE("Generate wire format unsigned 16-bit value using marker");
152 fr_dbuff_set_to_start(&dbuff);
153 TEST_CHECK(fr_dbuff_in(&marker, u16val2) == sizeof(uint16_t));
154 TEST_CHECK(*((uint16_t *)buff) == htons(u16val2));
155 TEST_CHECK(fr_dbuff_used(&marker) == sizeof(uint16_t));
156 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
157
158 TEST_CASE("Generate wire format unsigned 32-bit value");
159 memset(buff, 0, sizeof(buff));
160 fr_dbuff_init(&dbuff, buff, sizeof(buff));
161
162 TEST_CHECK(fr_dbuff_in(&dbuff, u32val) == sizeof(uint32_t));
163 TEST_CHECK(*((uint32_t *)buff) == htonl(u32val));
164
165 TEST_CASE("Generate wire format unsigned 64-bit value");
166 memset(buff, 0, sizeof(buff));
167 fr_dbuff_init(&dbuff, buff, sizeof(buff));
168
169 TEST_CHECK(fr_dbuff_in(&dbuff, u64val) == sizeof(uint64_t));
170 TEST_CHECK(*((uint64_t *)buff) == htonll(u64val));
171
172 TEST_CASE("Generate wire format signed 16-bit value");
173 memset(buff, 0, sizeof(buff));
174 fr_dbuff_init(&dbuff, buff, sizeof(buff));
175
176 TEST_CHECK(fr_dbuff_in(&dbuff, i16val) == sizeof(int16_t));
177 TEST_CHECK(*((uint16_t *)buff) == htons((uint16_t) i16val));
178
179 TEST_CASE("Generate wire format signed 32-bit value");
180 memset(buff, 0, sizeof(buff));
181 fr_dbuff_init(&dbuff, buff, sizeof(buff));
182
183 TEST_CHECK(fr_dbuff_in(&dbuff, i32val) == sizeof(int32_t));
184 TEST_CHECK(*((uint32_t *)buff) == htonl((uint32_t) i32val));
185
186 TEST_CASE("Generate wire format signed 64-bit value");
187 memset(buff, 0, sizeof(buff));
188 fr_dbuff_init(&dbuff, buff, sizeof(buff));
189
190 TEST_CHECK(fr_dbuff_in(&dbuff, i64val) == sizeof(int64_t));
191 TEST_CHECK(*((uint64_t *)buff) == htonll((uint64_t) i64val));
192
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];
196 int num_bytes;
197
198 fr_dbuff_set_to_start(&dbuff);
199 for (num_bytes = 1; (val & ~((uint64_t) 0xff)) != 0; num_bytes++) val >>= 8;
200 TEST_CHECK(fr_dbuff_in_uint64v(&dbuff, u64v_vals[i]) == num_bytes);
201 val = u64v_vals[i];
202 fr_dbuff_set_to_start(&dbuff);
203 for (int j = num_bytes; --j >= 0; ) {
204 uint8_t byte = 0;
205
206 TEST_CHECK(fr_dbuff_out(&byte, &dbuff) == 1);
207 TEST_CHECK(byte == (uint8_t) (val >> (8 * j)));
208 }
209 }
210
211 TEST_CASE("Generate wire-format float");
212 memset(buff, 0, sizeof(buff));
213 fr_dbuff_init(&dbuff, buff, sizeof(buff));
214 TEST_CHECK(fr_dbuff_in(&dbuff, float_in) == 4);
215 fr_dbuff_set_to_start(&dbuff);
216 TEST_CHECK(fr_dbuff_out(&float_out, &dbuff) == 4);
217 TEST_CHECK(memcmp(&float_out, &float_in, sizeof(float)) == 0);
218
219 TEST_CASE("Generate wire-format double");
220 memset(buff, 0, sizeof(buff));
221 fr_dbuff_init(&dbuff, buff, sizeof(buff));
222 TEST_CHECK(fr_dbuff_in(&dbuff, double_in) == 8);
223 fr_dbuff_set_to_start(&dbuff);
224 TEST_CHECK(fr_dbuff_out(&double_out, &dbuff) == 8);
225 TEST_CHECK(memcmp(&double_out, &double_in, sizeof(double)) == 0);
226
227 TEST_CASE("Refuse to write to too-small space");
228 fr_dbuff_init(&dbuff, buff, sizeof(uint32_t));
229
230 TEST_CHECK(fr_dbuff_in(&dbuff, u64val) == -(ssize_t)(sizeof(uint64_t) - sizeof(uint32_t)));
231
232 TEST_CASE("Input bytes using dbuff current position");
233 memset(buff, 0, sizeof(buff));
234 fr_dbuff_init(&dbuff, buff, sizeof(buff));
235 fr_dbuff_marker(&marker, &dbuff);
236 TEST_CHECK(fr_dbuff_in_bytes(&dbuff, 0xf0, 0xed, 0xcb) == 3);
237 TEST_CHECK(buff[0] == 0xf0);
238 TEST_CHECK(buff[1] == 0xed);
239 TEST_CHECK(buff[2] == 0xcb);
240 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
241 TEST_CASE("Input bytes using marker");
242 TEST_CHECK(fr_dbuff_in_bytes(&marker, 0x01, 0x23) == 2);
243 TEST_CHECK(buff[0] == 0x01);
244 TEST_CHECK(buff[1] == 0x23);
245 TEST_CHECK(fr_dbuff_used(&marker) == 2);
246}
247
248static void test_dbuff_no_advance(void)
249{
250 uint8_t in[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
251 fr_dbuff_t dbuff;
252 fr_dbuff_t no_advance_dbuff;
253 size_t init_remaining;
254
255 TEST_CASE("Confirm no-advance dbuff operations don't affect ancestors' position");
256 fr_dbuff_init(&dbuff, in, sizeof(in));
257
258 no_advance_dbuff = FR_DBUFF(&dbuff);
259 init_remaining = fr_dbuff_remaining(&dbuff);
260 TEST_CHECK(fr_dbuff_in_bytes(&no_advance_dbuff, 0x11, 0x12, 0x13) == 3);
261 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
262 fr_dbuff_advance(&no_advance_dbuff, 2);
263 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
264 fr_dbuff_set_to_end(&no_advance_dbuff);
265 TEST_CHECK(init_remaining == fr_dbuff_remaining(&dbuff));
266}
267
268static void test_dbuff_move(void)
269{
270 uint8_t buff1[26], buff2[26], buff3[10];
271 fr_dbuff_t dbuff1, dbuff2, dbuff3;
272 fr_dbuff_marker_t marker1, marker2;
273
274 memcpy(buff1, "abcdefghijklmnopqrstuvwxyz", sizeof(buff1));
275 memcpy(buff2, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sizeof(buff2));
276 memcpy(buff3, "0123456789", sizeof(buff3));
277 fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
278 fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
279 fr_dbuff_init(&dbuff3, buff3, sizeof(buff3));
280 fr_dbuff_marker(&marker1, &dbuff1);
281 fr_dbuff_marker(&marker2, &dbuff2);
282
283 TEST_CASE("move dbuff to dbuff");
284 TEST_CHECK_LEN(fr_dbuff_move(&dbuff1, &dbuff2, 13), 13);
285 TEST_CHECK_LEN(fr_dbuff_used(&dbuff1), 13);
286 TEST_CHECK_LEN(fr_dbuff_used(&dbuff2), 13);
287 TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMnopqrstuvwxyz", 26) == 0);
288
289 TEST_CASE("move dbuff to marker");
290 TEST_CHECK_SLEN(fr_dbuff_advance(&marker2, 4), 4);
291 TEST_CHECK_LEN(fr_dbuff_move(&marker2, &dbuff3, 10), 10);
292 TEST_CHECK_LEN(fr_dbuff_used(&marker2), 14);
293 TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789OPQRSTUVWXYZ", 26) == 0);
294
295 TEST_CASE("move marker to dbuff");
296 TEST_CHECK_SLEN(fr_dbuff_advance(&marker1, 7), 7);
297 TEST_CHECK_LEN(fr_dbuff_move(&dbuff1, &marker1, 6), 6);
298 TEST_CHECK_LEN(fr_dbuff_used(&dbuff1), 19);
299 TEST_CHECK_LEN(fr_dbuff_used(&marker1), 13);
300 TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMHIJKLMtuvwxyz", 26) == 0);
301
302 TEST_CASE("move marker to marker");
303 TEST_CHECK_LEN(fr_dbuff_move(&marker2, &marker1, 8), 8);
304 TEST_CHECK_LEN(fr_dbuff_used(&marker1), 21);
305 TEST_CHECK_LEN(fr_dbuff_used(&marker2), 22);
306 TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789HIJKLMtuWXYZ", 26) == 0);
307}
308
309/** Test extensible dbuffs
310 *
311 */
312
314{
315 fr_dbuff_t dbuff1, dbuff2;
316 fr_dbuff_uctx_talloc_t tctx1, tctx2;
317 fr_dbuff_marker_t marker1;
318 uint8_t const value[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
319
320 TEST_CASE("Initial allocation");
321 MEM(fr_dbuff_init_talloc(NULL, &dbuff1, &tctx1, 4, 14));
322 TEST_CHECK(fr_dbuff_used(&dbuff1) == 0);
323 TEST_CHECK(fr_dbuff_remaining(&dbuff1) == 4);
324 fr_dbuff_marker(&marker1, &dbuff1);
325
326 TEST_CASE("Extension");
327 TEST_CHECK(fr_dbuff_in(&dbuff1, (uint64_t) 0x123456789abcdef0) == sizeof(uint64_t));
328 TEST_CASE("Markers track extended buffer");
329 TEST_CHECK(marker1.p == dbuff1.start);
330 TEST_CASE("Already-written content stays with the buffer");
331 TEST_CHECK(memcmp(fr_dbuff_current(&marker1), value, sizeof(value)) == 0);
332 TEST_CASE("Refuse to extend past specified maximum");
333 TEST_CHECK(fr_dbuff_in(&dbuff1, (uint64_t) 0x123456789abcdef0) == -2);
334 TEST_CASE("Extend move destination if possible and input length demands");
335 MEM(fr_dbuff_init_talloc(NULL, &dbuff2, &tctx2, 4, 14));
336 fr_dbuff_set_to_start(&dbuff1);
337 TEST_CHECK(fr_dbuff_move(&dbuff2, &dbuff1, sizeof(value)) == sizeof(value));
338 TEST_CHECK(fr_dbuff_used(&dbuff2) == sizeof(value));
339 /*
340 * @todo: the analogous test for extensible source.
341 */
342
343 talloc_free(dbuff1.buff);
344 talloc_free(dbuff2.buff);
345}
346
348{
349 fr_dbuff_t dbuff1, dbuff2;
350 fr_dbuff_uctx_talloc_t tctx;
351
352 TEST_CASE("Initial allocation");
353 MEM(fr_dbuff_init_talloc(NULL, &dbuff1, &tctx, 0, 32));
354 TEST_CHECK(fr_dbuff_used(&dbuff1) == 0);
355 TEST_CHECK(fr_dbuff_remaining(&dbuff1) == 0);
356
357 dbuff2 = FR_DBUFF(&dbuff1);
358 TEST_CASE("Check that dbuff2 inherits extend fields");
359 TEST_CHECK(dbuff2.extend == dbuff1.extend);
360 TEST_CHECK(dbuff2.uctx == dbuff1.uctx);
361 TEST_CHECK(fr_dbuff_used(&dbuff2) == 0);
362 TEST_CHECK(fr_dbuff_remaining(&dbuff2) == 0);
363
364 dbuff2 = FR_DBUFF_MAX_BIND_CURRENT(&dbuff1, 8);
365 TEST_CASE("Check that FR_DBUFF_MAX_BIND_CURRENT() is not extensible");
366 TEST_CHECK(dbuff2.extend == NULL);
367 TEST_CHECK(dbuff2.uctx == NULL);
368 TEST_CHECK(fr_dbuff_used(&dbuff2) == 0);
369 TEST_CHECK(fr_dbuff_remaining(&dbuff2) == 0);
370 TEST_CHECK(fr_dbuff_in(&dbuff2, (uint64_t) 0x123456789abcdef0) == -8);
371
372 talloc_free(dbuff1.buff);
373}
374
375/*
376 * test_dbuff_fd_shell() puts setup and teardown of a fd flavored dbuff in one place
377 * so jscpd won't complain about copy/paste.
378 */
379static void test_dbuff_fd_shell(fr_dbuff_fd_test_body body, uint8_t const data[], size_t datasize,
380 uint8_t buff[], size_t buffsize, size_t max)
381{
382 int fd[2];
383 fr_dbuff_t dbuff;
384 fr_dbuff_uctx_fd_t fctx;
385
386 TEST_CASE("Initial allocation");
387 TEST_CHECK(pipe(fd) == 0);
388 TEST_CHECK(write(fd[1], data, datasize) == (ssize_t) datasize);
389 close(fd[1]);
390 TEST_CHECK(fr_dbuff_init_fd(&dbuff, &fctx, buff, buffsize, fd[0], max) == &dbuff);
391
392 body(&dbuff, data);
393
394 close(fd[0]);
395}
396
397static void fd_body(fr_dbuff_t *dbuff, uint8_t const data[])
398{
399 uint8_t output[8] = { 0x00 };
400
401 TEST_CASE("Initial extend");
402 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 1) == 1);
403 TEST_CHECK(memcmp(output, data, 1) == 0);
404 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 2) == 2);
405 TEST_CHECK(memcmp(output, &data[1], 2) == 0);
406 TEST_CASE("Leftover byte plus data from next extend");
407 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == 4);
408 TEST_CHECK(memcmp(output, &data[3], 4) == 0);
409 TEST_CASE("Multiple extends");
410 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 8) == 8);
411 TEST_CHECK(memcmp(output, &data[7], 8) == 0);
412 TEST_CASE("EOF");
413 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == -3);
414}
415
416static void test_dbuff_fd(void)
417{
418 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
419 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
420 uint8_t buff[4];
421
422 test_dbuff_fd_shell(fd_body, data, sizeof(data), buff, sizeof(buff), 24);
423}
424
425
426static void max_body(fr_dbuff_t *dbuff, uint8_t const data[])
427{
428 uint8_t output[8];
429
430 TEST_CASE("Initial extend");
431 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 2) == 2);
432 TEST_CHECK(memcmp(output, data, 2) == 0);
433 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 1) == 1);
434 TEST_CHECK(memcmp(output, &data[2], 1) == 0);
435 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 4) == 4);
436 TEST_CHECK(memcmp(output, &data[3], 4) == 0);
437 TEST_CASE("Confirm that max precludes another shift/extend");
438 TEST_CHECK(fr_dbuff_out_memcpy(output, dbuff, 8) == -7);
439}
440
441static void test_dbuff_fd_max(void)
442{
443 uint8_t const data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
444 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
445 uint8_t buff[4];
446
447
448 test_dbuff_fd_shell(max_body, data, sizeof(data), buff, sizeof(buff), 8);
449}
450
451/** Test functions that read from dbuffs.
452 *
453 */
454static void test_dbuff_out(void)
455{
456 uint8_t const buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
457 uint8_t buff2[8];
458 uint8_t buff3[8];
459 fr_dbuff_t dbuff1;
460 fr_dbuff_t dbuff2;
461 fr_dbuff_marker_t marker1;
462 uint8_t u8val = 0;
463 uint16_t u16val = 0;
464 uint32_t u32val = 0;
465 uint64_t u64val = 0;
466 uint64_t u64val2 = 0;
467 int8_t i8val = 0;
468 int16_t i16val = 0;
469 int32_t i32val = 0;
470 int64_t i64val = 0;
471 float fval1 = 1.5, fval2 = 0;
472 double dval1 = 2048.0625, dval2 = 0;
473
474 fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
475 fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
476
477 TEST_CASE("Check dbuff reads of unsigned integers");
478 TEST_CHECK(fr_dbuff_out(&u8val, &dbuff1) == 1);
479 TEST_CHECK(u8val == 0x01);
480 TEST_CHECK(fr_dbuff_out(&u16val, &dbuff1) == 2);
481 TEST_CHECK(u16val == 0x2345);
482 TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == 4);
483 TEST_CHECK(u32val == 0x6789abcd);
484 fr_dbuff_set_to_start(&dbuff1);
485 TEST_CHECK(fr_dbuff_out(&u64val, &dbuff1) == 8);
486 TEST_CHECK(u64val == 0x0123456789abcdef);
487
488 TEST_CASE("Don't walk off the end of the buffer");
489 TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == -4);
490
491 TEST_CASE("Check dbuff reads using markers");
492 fr_dbuff_set_to_start(&dbuff1);
493 fr_dbuff_marker(&marker1, &dbuff1);
494 TEST_CHECK(fr_dbuff_out(&u64val, &marker1) == 8);
495 TEST_CHECK(fr_dbuff_out(&u64val2, &dbuff1) == 8);
496 TEST_CHECK(u64val == u64val2);
497 TEST_CHECK(fr_dbuff_current(&dbuff1) == fr_dbuff_current(&marker1));
498
499 TEST_CASE("Check dbuff reads of signed integers");
500 fr_dbuff_set_to_start(&dbuff1);
501 TEST_CHECK(fr_dbuff_out(&i8val, &dbuff1) == 1);
502 TEST_CHECK(i8val == 0x01);
503 TEST_CHECK(fr_dbuff_out(&i16val, &dbuff1) == 2);
504 TEST_CHECK(i16val == 0x2345);
505 TEST_CHECK(fr_dbuff_out(&i32val, &dbuff1) == 4);
506 TEST_CHECK(i32val == 0x6789abcd);
507 fr_dbuff_set_to_start(&dbuff1);
508 TEST_CHECK(fr_dbuff_out(&i64val, &dbuff1) == 8);
509 TEST_CHECK(i64val == 0x0123456789abcdef);
510
511 TEST_CASE("Check dbuff reads of floating point values");
512 TEST_CHECK(fr_dbuff_in(&dbuff2, *(uint32_t *)&fval1) == 4);
513 fr_dbuff_set_to_start(&dbuff2);
514 TEST_CHECK(fr_dbuff_out(&fval2, &dbuff2) == 4);
515 TEST_CHECK(memcmp(&fval1, &fval2, sizeof(fval1)) == 0);
516 fr_dbuff_set_to_start(&dbuff2);
517 TEST_CHECK(fr_dbuff_in(&dbuff2, *(uint64_t *)&dval1) == 8);
518 fr_dbuff_set_to_start(&dbuff2);
519 TEST_CHECK(fr_dbuff_out(&dval2, &dbuff2) == 8);
520 TEST_CHECK(memcmp(&dval1, &dval2, sizeof(dval1)) == 0);
521
522 TEST_CASE("Check variable length uint64_t read");
523 fr_dbuff_set_to_start(&dbuff1);
524 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 2) == 2);
525 TEST_CHECK(u64val == 0x0123);
526 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 4) == 4);
527 TEST_CHECK(u64val == 0x456789ab);
528 fr_dbuff_set_to_start(&dbuff1);
529 TEST_CHECK(fr_dbuff_out_uint64v(&u64val, &dbuff1, 8) == 8);
530 TEST_CHECK(u64val == 0x0123456789abcdef);
531
532 TEST_CASE("fr_dbuff_out_memcpy");
533 fr_dbuff_set_to_start(&dbuff1);
534 fr_dbuff_set_to_start(&dbuff2);
535 fr_dbuff_marker(&marker1, &dbuff1);
536 memset(buff3, 0, sizeof(buff3));
537 TEST_CHECK(fr_dbuff_out_memcpy(buff3, &dbuff1, 7) == 7);
538 TEST_CHECK(memcmp(buff3, fr_dbuff_start(&dbuff1), 7) == 0 && buff3[7] == 0);
539 TEST_CHECK(fr_dbuff_current(&dbuff1) - fr_dbuff_current(&marker1) == 7);
540 fr_dbuff_set_to_start(&dbuff1);
541 TEST_CHECK(fr_dbuff_out_memcpy(&dbuff2, &dbuff1, 4) == 4);
542 fr_dbuff_set_to_start(&dbuff1);
543 fr_dbuff_advance(&dbuff1, 3);
544 fr_dbuff_advance(&dbuff2, 2);
545 TEST_CHECK(fr_dbuff_out_memcpy(&dbuff2, &dbuff1, 4) == 4);
546 TEST_CHECK(memcmp(fr_dbuff_start(&dbuff2), fr_dbuff_start(&dbuff1), 2) == 0 &&
547 memcmp(fr_dbuff_start(&dbuff2) + 2, fr_dbuff_start(&dbuff1) + 3, 4) == 0);
548 memset(buff3, 0, sizeof(buff3));
549 fr_dbuff_set_to_start(&marker1);
550 TEST_CHECK(fr_dbuff_out_memcpy(buff3, &marker1, 4) == 4);
551 TEST_CHECK(memcmp(buff3, buff1, 4) == 0);
552 TEST_CHECK(fr_dbuff_current(&marker1) - fr_dbuff_start(&dbuff1) == 4);
553}
554
555/** Test the child-dbuff macros: FR_DBUFF, FR_DBUFF_ABS, FR_DBUFF_BIND_CURRENT,
556 * FR_DBUFF_BIND_CURRENT_ABS, FR_DBUFF_BIND_END_ABS and FR_DBUFF_MAX.
557 *
558 * These differ only in where the child's 'start' pointer is set (parent
559 * 'current' vs parent 'start') and whether writing to the child advances the
560 * parent's 'current' pointer, 'end' pointer, or neither.
561 */
562static void test_dbuff_child(void)
563{
564 fr_dbuff_t dbuff;
565 fr_dbuff_t child;
566 uint8_t buff[16] = "";
567
568 TEST_CASE("FR_DBUFF: start bound to parent 'current', parent not advanced");
569 fr_dbuff_init(&dbuff, buff, sizeof(buff));
570 fr_dbuff_advance(&dbuff, 4);
571 child = FR_DBUFF(&dbuff);
572 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_current(&dbuff));
573 TEST_CHECK(fr_dbuff_current(&child) == fr_dbuff_current(&dbuff));
574 TEST_CHECK(fr_dbuff_used(&child) == 0);
575 TEST_CHECK(fr_dbuff_remaining(&child) == sizeof(buff) - 4);
576 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb) == 2);
577 TEST_CHECK(fr_dbuff_used(&dbuff) == 4); /* parent NOT advanced */
578
579 TEST_CASE("FR_DBUFF_ABS: start bound to parent 'start', parent not advanced");
580 fr_dbuff_init(&dbuff, buff, sizeof(buff));
581 fr_dbuff_advance(&dbuff, 4);
582 child = FR_DBUFF_ABS(&dbuff);
583 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_start(&dbuff));
584 TEST_CHECK(fr_dbuff_current(&child) == fr_dbuff_current(&dbuff));
585 TEST_CHECK(fr_dbuff_used(&child) == 4); /* current - start */
586 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa) == 1);
587 TEST_CHECK(fr_dbuff_used(&dbuff) == 4); /* parent NOT advanced */
588
589 TEST_CASE("FR_DBUFF_BIND_CURRENT: writes advance parent 'current'");
590 fr_dbuff_init(&dbuff, buff, sizeof(buff));
591 fr_dbuff_advance(&dbuff, 4);
592 child = FR_DBUFF_BIND_CURRENT(&dbuff);
593 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_current(&dbuff));
594 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb, 0xcc) == 3);
595 TEST_CHECK(fr_dbuff_used(&dbuff) == 7); /* 4 + 3 */
596
597 TEST_CASE("FR_DBUFF_BIND_CURRENT_ABS: start bound to parent 'start', writes advance parent 'current'");
598 fr_dbuff_init(&dbuff, buff, sizeof(buff));
599 fr_dbuff_advance(&dbuff, 4);
600 child = FR_DBUFF_BIND_CURRENT_ABS(&dbuff);
601 TEST_CHECK(fr_dbuff_start(&child) == fr_dbuff_start(&dbuff));
602 TEST_CHECK(fr_dbuff_used(&child) == 4);
603 TEST_CHECK(fr_dbuff_in_bytes(&child, 0xaa, 0xbb) == 2);
604 TEST_CHECK(fr_dbuff_used(&dbuff) == 6); /* 4 + 2 */
605 TEST_CHECK(fr_dbuff_used(&child) == 6); /* child start == parent start */
606
607 TEST_CASE("FR_DBUFF_BIND_END_ABS: writes advance parent 'end' (producer side)");
608 fr_dbuff_init(&dbuff, buff, sizeof(buff));
609 child = FR_DBUFF_BIND_END_ABS(&dbuff);
610 TEST_CHECK(fr_dbuff_end(&dbuff) == buff); /* consumer starts empty */
611 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 0); /* nothing produced yet */
612 TEST_CHECK(fr_dbuff_remaining(&child) == sizeof(buff)); /* producer has the whole buffer */
613 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x01, 0x02, 0x03, 0x04, 0x05) == 5);
614 TEST_CHECK(fr_dbuff_end(&dbuff) == buff + 5); /* parent 'end' pulled back to producer position */
615 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 5); /* consumer can now read what was produced */
616
617 TEST_CASE("FR_DBUFF_MAX: caps available space, non-bind variant leaves parent alone");
618 fr_dbuff_init(&dbuff, buff, sizeof(buff));
619 child = FR_DBUFF_MAX(&dbuff, 4);
620 TEST_CHECK(fr_dbuff_remaining(&child) == 4);
621 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x01, 0x02, 0x03, 0x04) == 4);
622 TEST_CHECK(fr_dbuff_in_bytes(&child, 0x05) == -1); /* capped: 1 byte short */
623 TEST_CHECK(fr_dbuff_used(&dbuff) == 0); /* parent NOT advanced */
624
625 TEST_CASE("FR_DBUFF_MAX: _max larger than remaining is clamped to remaining");
626 child = FR_DBUFF_MAX(&dbuff, 2 * sizeof(buff));
627 TEST_CHECK(fr_dbuff_remaining(&child) == sizeof(buff));
628}
629
630/** Test the measurement / accessor macros against both a dbuff and a marker.
631 *
632 * Covers fr_dbuff_len, fr_dbuff_buff, fr_dbuff_end, fr_dbuff_ptr,
633 * fr_dbuff_behind and fr_dbuff_ahead, which the existing tests never touch.
634 */
635static void test_dbuff_measure(void)
636{
637 fr_dbuff_t dbuff;
639 uint8_t buff[10] = "";
640
641 fr_dbuff_init(&dbuff, buff, sizeof(buff));
642
643 TEST_CASE("dbuff accessors");
644 TEST_CHECK(fr_dbuff_len(&dbuff) == sizeof(buff));
645 TEST_CHECK(fr_dbuff_buff(&dbuff) == buff);
646 TEST_CHECK(fr_dbuff_start(&dbuff) == buff);
647 TEST_CHECK(fr_dbuff_current(&dbuff) == buff);
648 TEST_CHECK(fr_dbuff_end(&dbuff) == buff + sizeof(buff));
649 TEST_CHECK(fr_dbuff_ptr(&dbuff) == &dbuff);
650
651 TEST_CASE("marker behind then ahead of parent");
652 fr_dbuff_marker(&m, &dbuff);
653 fr_dbuff_advance(&dbuff, 6);
654 TEST_CHECK(fr_dbuff_behind(&m) == 6); /* marker 6 bytes behind parent */
655 TEST_CHECK(fr_dbuff_ahead(&m) == 0);
656 fr_dbuff_advance(&m, 8);
657 TEST_CHECK(fr_dbuff_ahead(&m) == 2); /* marker now 2 bytes ahead */
658 TEST_CHECK(fr_dbuff_behind(&m) == 0);
659
660 TEST_CASE("marker accessors resolve through parent");
663 TEST_CHECK(fr_dbuff_end(&m) == buff + sizeof(buff));
664 TEST_CHECK(fr_dbuff_len(&m) == sizeof(buff));
665 TEST_CHECK(fr_dbuff_ptr(&m) == &dbuff);
666 TEST_CHECK(fr_dbuff_current(&m) == buff + 8);
667 TEST_CHECK(fr_dbuff_used(&m) == 8);
669}
670
671/** Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
672 *
673 * The backing array is deliberately larger than the dbuff window so that we
674 * can form a pointer past the dbuff 'end' without forming a pointer outside
675 * the real allocation (which would be undefined behaviour).
676 */
677static void test_dbuff_set(void)
678{
679 uint8_t backing[32];
680 fr_dbuff_t dbuff;
682
683 TEST_CASE("fr_dbuff_set by size_t offset, pointer, and out-of-range");
684 fr_dbuff_init(&dbuff, backing, 10);
685 TEST_CHECK(fr_dbuff_set(&dbuff, (size_t)5) == 5);
686 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 5);
687 TEST_CHECK(fr_dbuff_set(&dbuff, backing + 2) == -3); /* moving backwards returns the signed diff */
688 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 2);
689 TEST_CHECK(fr_dbuff_set(&dbuff, backing + 20) == -10); /* past 'end': bytes over, no move */
690 TEST_CHECK(fr_dbuff_current(&dbuff) == backing + 2);
691
692 TEST_CASE("fr_dbuff_set from a marker");
693 fr_dbuff_set_to_start(&dbuff);
694 fr_dbuff_marker(&m, &dbuff);
695 fr_dbuff_advance(&m, 7);
696 TEST_CHECK(fr_dbuff_set(&dbuff, &m) == 7);
698
699 TEST_CASE("fr_dbuff_set_end trims the 'end' pointer");
700 fr_dbuff_init(&dbuff, backing, 10);
701 fr_dbuff_advance(&dbuff, 3);
702 fr_dbuff_set_end(&dbuff, backing + 6);
703 TEST_CHECK(fr_dbuff_end(&dbuff) == backing + 6);
704 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 3);
705#ifdef NDEBUG
706 fr_dbuff_set_end(&dbuff, backing + 8); /* beyond current 'end': asserts in debug builds */
707#endif
708 TEST_CHECK(fr_dbuff_end(&dbuff) == backing + 6);
709}
710
711/** Test fr_dbuff_advance_extend against a talloc-backed (extensible) dbuff. */
713{
714 fr_dbuff_t dbuff;
715 fr_dbuff_uctx_talloc_t tctx;
716
717 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 16));
718
719 TEST_CASE("advance within the initial allocation");
720 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 2) == 2);
721 TEST_CHECK(fr_dbuff_used(&dbuff) == 2);
722
723 TEST_CASE("advance past the current size triggers an extend");
724 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 10) == 10);
725 TEST_CHECK(fr_dbuff_used(&dbuff) == 12);
726
727 TEST_CASE("advance past max fails and does not advance");
728 TEST_CHECK(fr_dbuff_advance_extend(&dbuff, 10) < 0);
729 TEST_CHECK(fr_dbuff_used(&dbuff) == 12);
730
731 fr_dbuff_free_talloc(&dbuff);
732}
733
734/** Test fr_dbuff_memset. */
735static void test_dbuff_memset(void)
736{
737 fr_dbuff_t dbuff;
738 uint8_t buff[8] = "";
739
740 fr_dbuff_init(&dbuff, buff, sizeof(buff));
741
742 TEST_CASE("memset writes and advances");
743 TEST_CHECK(fr_dbuff_memset(&dbuff, 0xa5, 5) == 5);
744 TEST_CHECK(fr_dbuff_used(&dbuff) == 5);
745 for (size_t i = 0; i < 5; i++) TEST_CHECK(buff[i] == 0xa5);
746
747 TEST_CASE("memset that does not fit returns bytes needed and does not advance");
748 TEST_CHECK(fr_dbuff_memset(&dbuff, 0x00, 5) == -2); /* only 3 left, need 5 */
749 TEST_CHECK(fr_dbuff_used(&dbuff) == 5);
750}
751
752/** Test fr_dbuff_in_memcpy, fr_dbuff_in_memcpy_partial and fr_dbuff_in_bytes_partial. */
753static void test_dbuff_in_memcpy(void)
754{
755 uint8_t buff[8] = "";
756 uint8_t const src[] = { 0x11, 0x22, 0x33, 0x44 };
757 uint8_t sbuf[4] = { 0x0a, 0x0b, 0x0c, 0x0d };
758 char const *str = "abc";
759 fr_dbuff_t dbuff;
760 fr_dbuff_t src_dbuff;
761
762 TEST_CASE("exact copy from a byte buffer");
763 fr_dbuff_init(&dbuff, buff, sizeof(buff));
764
765 /*
766 * Note _fr_dbuff_in_memcpy(), to avoid false positive complaints with -Werror=stringop-overread
767 *
768 * We could suppress the warn
769 */
770 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == 4);
771 TEST_CHECK(fr_dbuff_used(&dbuff) == 4);
772 TEST_CHECK(memcmp(buff, src, 4) == 0);
773
774 TEST_CASE("copy from a C string with SIZE_MAX uses strlen");
775 fr_dbuff_init(&dbuff, buff, sizeof(buff));
776 TEST_CHECK(fr_dbuff_in_memcpy(&dbuff, str, SIZE_MAX) == 3);
777 TEST_CHECK(memcmp(buff, str, 3) == 0);
778
779 TEST_CASE("copy that does not fit fails entirely and does not advance");
780 fr_dbuff_init(&dbuff, buff, 2);
781 TEST_CHECK(_fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == -2);
782 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
783
784 TEST_CASE("copy from another dbuff, source is not advanced");
785 fr_dbuff_init(&dbuff, buff, sizeof(buff));
786 fr_dbuff_init(&src_dbuff, sbuf, sizeof(sbuf));
787 TEST_CHECK(fr_dbuff_in_memcpy(&dbuff, &src_dbuff, 3) == 3);
788 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
789 TEST_CHECK(fr_dbuff_used(&src_dbuff) == 0);
790 TEST_CHECK(memcmp(buff, sbuf, 3) == 0);
791
792 TEST_CASE("SIZE_MAX with a dbuff source copies the source's remaining bytes");
793 fr_dbuff_init(&dbuff, buff, sizeof(buff));
794 fr_dbuff_init(&src_dbuff, sbuf, sizeof(sbuf));
795 TEST_CHECK(_fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(&dbuff), &dbuff, &src_dbuff.p, &src_dbuff, SIZE_MAX) == 4);
796 TEST_CHECK(fr_dbuff_used(&dbuff) == 4);
797
798 TEST_CASE("partial copy writes as much as fits and reports it");
799 fr_dbuff_init(&dbuff, buff, 2);
800 TEST_CHECK(_fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(&dbuff), &dbuff, src, sizeof(src)) == 2);
801 TEST_CHECK(fr_dbuff_used(&dbuff) == 2);
802 TEST_CHECK(memcmp(buff, src, 2) == 0);
803
804 TEST_CASE("in_bytes_partial truncates to the available space");
805 fr_dbuff_init(&dbuff, buff, 3);
806 TEST_CHECK(fr_dbuff_in_bytes_partial(&dbuff, 0xde, 0xad, 0xbe, 0xef) == 3);
807 TEST_CHECK(fr_dbuff_used(&dbuff) == 3);
808}
809
810/** Test fr_dbuff_marker_release, fr_dbuff_marker_release_behind and _ahead. */
812{
813 uint8_t buff[16];
814 fr_dbuff_t dbuff;
815 fr_dbuff_marker_t m1, m2;
816
817 TEST_CASE("plain release trims the marker list back to the previous marker");
818 fr_dbuff_init(&dbuff, buff, sizeof(buff));
819 fr_dbuff_marker(&m1, &dbuff);
820 fr_dbuff_marker(&m2, &dbuff);
821 TEST_CHECK(dbuff.m == &m2); /* newest marker at the head */
823 TEST_CHECK(dbuff.m == &m1);
825 TEST_CHECK(dbuff.m == NULL);
826
827 TEST_CASE("release_behind returns how far the marker trailed the parent");
828 fr_dbuff_init(&dbuff, buff, sizeof(buff));
829 fr_dbuff_marker(&m1, &dbuff);
830 fr_dbuff_advance(&dbuff, 4);
831 fr_dbuff_marker(&m2, &dbuff);
832 fr_dbuff_advance(&dbuff, 3); /* parent at 7, m2 at 4 */
834 TEST_CHECK(dbuff.m == &m1);
835
836 TEST_CASE("release_ahead returns how far the marker led the parent");
837 fr_dbuff_set(&m1, (size_t)10); /* m1 at 10, parent at 7 */
839 TEST_CHECK(dbuff.m == NULL);
840}
841
842/** Test fr_dbuff_out_int64v, which sign-extends based on the most significant bit. */
843static void test_dbuff_out_int64v(void)
844{
845 uint8_t const pos[] = { 0x7f, 0xff }; /* MSB clear -> positive */
846 uint8_t const neg[] = { 0xff, 0x00 }; /* MSB set -> negative */
847 fr_dbuff_t dbuff;
848 int64_t val;
849
850 TEST_CASE("positive two-byte value");
851 fr_dbuff_init(&dbuff, pos, sizeof(pos));
852 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == 2);
853 TEST_CHECK(val == 0x7fff);
854
855 TEST_CASE("negative two-byte value is sign extended");
856 fr_dbuff_init(&dbuff, neg, sizeof(neg));
857 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == 2);
858 TEST_CHECK(val == -256);
859
860 TEST_CASE("single positive byte");
861 fr_dbuff_init(&dbuff, pos, sizeof(pos));
862 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 1) == 1);
863 TEST_CHECK(val == 0x7f);
864
865 TEST_CASE("not enough data returns bytes needed");
866 fr_dbuff_init(&dbuff, pos, 1);
867 TEST_CHECK(fr_dbuff_out_int64v(&val, &dbuff, 2) == -1);
868}
869
870/** Test fr_dbuff_shift moves unconsumed content to the front of the buffer. */
871static void test_dbuff_shift(void)
872{
873 uint8_t buff[8] = "";
874 fr_dbuff_t dbuff;
875
876 memcpy(buff, "ABCDEFGH", sizeof(buff));
877 fr_dbuff_init(&dbuff, buff, sizeof(buff));
878 fr_dbuff_advance(&dbuff, 3); /* consume "ABC" */
879
880 TEST_CASE("shift discards consumed bytes and moves the rest down");
881 TEST_CHECK(fr_dbuff_shift(&dbuff, 3) == 3);
882 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
883 TEST_CHECK(memcmp(buff, "DEFGH", 5) == 0);
884 TEST_CHECK(fr_dbuff_remaining(&dbuff) == 5); /* 'end' pulled down by the shift */
885}
886
887/** Test fr_dbuff_update repoints the dbuff and its markers after a buffer move. */
888static void test_dbuff_update(void)
889{
890 uint8_t buff[8] = "";
891 uint8_t newbuff[8] = "";
892 fr_dbuff_t dbuff;
894
895 fr_dbuff_init(&dbuff, buff, sizeof(buff));
896 fr_dbuff_advance(&dbuff, 4);
897 fr_dbuff_marker(&m, &dbuff); /* marker at offset 4 */
898 fr_dbuff_set_to_start(&dbuff);
899 fr_dbuff_advance(&dbuff, 2); /* dbuff 'current' at offset 2 */
900
901 TEST_CASE("relative offsets are preserved against the new buffer");
902 fr_dbuff_update(&dbuff, newbuff, sizeof(newbuff));
903 TEST_CHECK(fr_dbuff_buff(&dbuff) == newbuff);
904 TEST_CHECK(fr_dbuff_start(&dbuff) == newbuff);
905 TEST_CHECK(fr_dbuff_current(&dbuff) == newbuff + 2);
906 TEST_CHECK(fr_dbuff_end(&dbuff) == newbuff + sizeof(newbuff));
907 TEST_CHECK(fr_dbuff_current(&m) == newbuff + 4); /* marker offset preserved */
908}
909
910/** Test fr_dbuff_trim_talloc, fr_dbuff_reset_talloc and fr_dbuff_free_talloc. */
912{
913 fr_dbuff_t dbuff;
914 fr_dbuff_uctx_talloc_t tctx;
915
916 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 32, 128));
917 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
918 TEST_CHECK(fr_dbuff_in_bytes(&dbuff, 0x01, 0x02, 0x03, 0x04) == 4);
919
920 TEST_CASE("trim to content length (SIZE_MAX)");
921 TEST_CHECK(fr_dbuff_trim_talloc(&dbuff, SIZE_MAX) == 0);
922 TEST_CHECK(talloc_array_length(dbuff.buff) == 4);
923 TEST_CHECK(fr_dbuff_len(&dbuff) == 4);
924
925 TEST_CASE("trim to an explicit length");
926 TEST_CHECK(fr_dbuff_trim_talloc(&dbuff, 2) == 0);
927 TEST_CHECK(talloc_array_length(dbuff.buff) == 2);
928
929 TEST_CASE("reset restores the initial length and clears the position");
930 TEST_CHECK(fr_dbuff_reset_talloc(&dbuff) == 0);
931 TEST_CHECK(talloc_array_length(dbuff.buff) == 32);
932 TEST_CHECK(fr_dbuff_used(&dbuff) == 0);
933
934 TEST_CASE("free_talloc releases the buffer");
935 fr_dbuff_free_talloc(&dbuff);
936 TEST_CHECK(dbuff.buff == NULL);
937}
938
939/** Test FR_DBUFF_TMP, the compound-literal dbuff. */
940static void test_dbuff_tmp(void)
941{
942 uint8_t buff[8] = "";
943 fr_dbuff_t tmp = FR_DBUFF_TMP(buff, sizeof(buff));
944
945 TEST_CASE("compound literal points at the supplied buffer and is writable");
948 TEST_CHECK(fr_dbuff_end(&tmp) == buff + sizeof(buff));
949 TEST_CHECK(fr_dbuff_in_bytes(&tmp, 0x01, 0x02) == 2);
950 TEST_CHECK(buff[0] == 0x01);
951 TEST_CHECK(buff[1] == 0x02);
952}
953
954/** Test the extension-request API: fr_dbuff_extend, fr_dbuff_extend_lowat,
955 * fr_dbuff_is_extendable and fr_dbuff_was_extended.
956 */
957static void test_dbuff_extend(void)
958{
959 uint8_t buff[8];
960 fr_dbuff_t dbuff;
961 fr_dbuff_uctx_talloc_t tctx;
963
964 TEST_CASE("fixed buffer: extend returns remaining and never grows");
965 fr_dbuff_init(&dbuff, buff, sizeof(buff));
966 TEST_CHECK(fr_dbuff_extend(&dbuff) == sizeof(buff));
967
968 TEST_CASE("fixed buffer at end: cannot satisfy lowat");
969 status = FR_DBUFF_EXTENDABLE;
970 fr_dbuff_advance(&dbuff, sizeof(buff));
971 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 4) == 0);
973 TEST_CHECK(fr_dbuff_was_extended(status) == 0);
974
975 TEST_CASE("talloc buffer: extend grows and flags report it");
976 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 64));
977 status = FR_DBUFF_EXTENDABLE;
978 fr_dbuff_advance(&dbuff, 4); /* remaining now 0 */
979 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 8) >= 8);
982
983 fr_dbuff_free_talloc(&dbuff);
984}
985
986/** A const dbuff must never extend
987 *
988 * A dbuff extends to make room to write. A const dbuff cannot be written to,
989 * so a request to extend one is always a caller asking to read more than the
990 * dbuff holds. _fr_dbuff_extend_lowat() answers with what is there, rather
991 * than reallocating the buffer.
992 */
994{
995 fr_dbuff_t dbuff;
996 fr_dbuff_uctx_talloc_t tctx;
998 uint8_t *buff_before;
999
1000 TEST_CASE("a writable talloc dbuff extends");
1001 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 64));
1002 fr_dbuff_advance(&dbuff, 4); /* remaining now 0 */
1003 status = FR_DBUFF_EXTENDABLE;
1004 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 8) >= 8);
1006 fr_dbuff_free_talloc(&dbuff);
1007
1008 TEST_CASE("the same dbuff marked const does not");
1009 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 4, 64));
1010 fr_dbuff_advance(&dbuff, 4); /* remaining now 0 */
1011 buff_before = dbuff.buff;
1012 dbuff.is_const = 1;
1013 status = FR_DBUFF_EXTENDABLE;
1014 TEST_CHECK(fr_dbuff_extend_lowat(&status, &dbuff, 8) == 0);
1015 TEST_CHECK(fr_dbuff_was_extended(status) == 0);
1016 TEST_CHECK(fr_dbuff_is_extendable(status) == 0);
1017 TEST_CHECK(dbuff.buff == buff_before); /* no realloc happened */
1018 TEST_CHECK(fr_dbuff_len(&dbuff) == 4); /* and no growth */
1019
1020 dbuff.is_const = 0; /* so the free below is honest */
1021 fr_dbuff_free_talloc(&dbuff);
1022}
1023
1024/** A producer and a consumer sharing one talloc buffer
1025 *
1026 * fr_tls_bio_dbuff_t in src/lib/tls/bio.c builds its two cursors this way, so
1027 * that OpenSSL and the caller share one allocation per direction. The
1028 * consumer is the parent and the producer is the child.
1029 *
1030 * Only the producer may extend. fr_dbuff_update() repairs the dbuff which was
1031 * extended and that dbuff's ancestors, and never its children, so extending
1032 * through the consumer would leave the producer addressing the old buffer.
1033 * Marking the consumer const is what stops that, which is what this test
1034 * pins.
1035 */
1037{
1038 fr_dbuff_t consumer, producer;
1039 fr_dbuff_uctx_talloc_t tctx;
1041 uint8_t *buff_before;
1042 uint8_t out[8];
1043 uint8_t const expected[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
1044
1045 TEST_CASE("the consumer starts empty, the producer holds the whole buffer");
1046 MEM(fr_dbuff_init_talloc(NULL, &consumer, &tctx, 4, 64));
1047 producer = FR_DBUFF_BIND_END_ABS(&consumer); /* the bind marks the consumer const */
1048 TEST_CHECK(fr_dbuff_remaining(&consumer) == 0);
1049 TEST_CHECK(fr_dbuff_remaining(&producer) == 4);
1050
1051 TEST_CASE("a write through the producer is what the consumer reads");
1052 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x01, 0x02, 0x03) == 3);
1053 TEST_CHECK(fr_dbuff_remaining(&consumer) == 3);
1054
1055 TEST_CASE("extending through the producer repairs both cursors");
1056 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x04, 0x05, 0x06, 0x07, 0x08) == 5);
1057 TEST_CHECK(producer.buff == consumer.buff); /* the consumer followed the realloc */
1058 TEST_CHECK(fr_dbuff_remaining(&consumer) == 8);
1059
1060 TEST_CASE("an over-large read on the consumer extends nothing");
1061 buff_before = consumer.buff;
1062 status = FR_DBUFF_EXTENDABLE;
1063 TEST_CHECK(fr_dbuff_extend_lowat(&status, &consumer, 64) == 8);
1064 TEST_CHECK(fr_dbuff_was_extended(status) == 0);
1065 TEST_CHECK(consumer.buff == buff_before);
1066 TEST_CHECK(producer.buff == consumer.buff); /* the producer is still valid */
1067
1068 TEST_CASE("the consumer reads back what the producer wrote");
1069 TEST_CHECK(fr_dbuff_out_memcpy(out, &consumer, sizeof(out)) == (ssize_t) sizeof(out));
1070 TEST_CHECK(memcmp(out, expected, sizeof(expected)) == 0);
1071 TEST_CHECK(fr_dbuff_remaining(&consumer) == 0);
1072
1073 consumer.is_const = 0; /* so the free below is honest */
1074 fr_dbuff_free_talloc(&consumer);
1075}
1076
1077/** Draining a buffer without knowing in advance how much is in it
1078 *
1079 * fr_tls_record_to_buff() used to clamp a request to what the record held.
1080 * Callers now reach for a dbuff primitive instead, and the two differ:
1081 * fr_dbuff_move() copies what both sides allow and advances both, while
1082 * fr_dbuff_out_memcpy() advances only the source and reports a shortfall.
1083 */
1084static void test_dbuff_drain(void)
1085{
1086 uint8_t const src_buff[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
1087 uint8_t small[4] = { 0x00 };
1088 uint8_t out[8] = { 0x00 } ;
1089 fr_dbuff_t src, dst;
1090
1091 TEST_CASE("fr_dbuff_move: a request larger than the source copies what is there");
1092 fr_dbuff_init(&src, src_buff, sizeof(src_buff));
1093 fr_dbuff_init(&dst, out, sizeof(out));
1094 TEST_CHECK(fr_dbuff_move(&dst, &src, 64) == sizeof(src_buff));
1095 TEST_CHECK(fr_dbuff_used(&src) == sizeof(src_buff)); /* the source advanced */
1096 TEST_CHECK(fr_dbuff_used(&dst) == sizeof(src_buff)); /* so did the destination */
1097 TEST_CHECK(fr_dbuff_remaining(&src) == 0); /* a drain loop therefore ends */
1098 TEST_CHECK(memcmp(out, src_buff, sizeof(src_buff)) == 0);
1099
1100 TEST_CASE("fr_dbuff_move: the destination clamps the copy too");
1101 fr_dbuff_init(&src, src_buff, sizeof(src_buff));
1102 fr_dbuff_init(&dst, small, sizeof(small));
1103 TEST_CHECK(fr_dbuff_move(&dst, &src, sizeof(src_buff)) == sizeof(small));
1104 TEST_CHECK(fr_dbuff_used(&src) == sizeof(small));
1105 TEST_CHECK(memcmp(small, src_buff, sizeof(small)) == 0);
1106
1107 TEST_CASE("fr_dbuff_out_memcpy: an exact request advances the source");
1108 fr_dbuff_init(&src, src_buff, sizeof(src_buff));
1109 TEST_CHECK(fr_dbuff_out_memcpy(out, &src, 4) == 4);
1110 TEST_CHECK(fr_dbuff_used(&src) == 4);
1111 TEST_CHECK(memcmp(out, src_buff, 4) == 0);
1112
1113 TEST_CASE("fr_dbuff_out_memcpy: an over-large request copies, then reports the shortfall");
1114 TEST_CHECK(fr_dbuff_out_memcpy(out, &src, 8) == -4); /* 4 octets short */
1115 TEST_CHECK(fr_dbuff_remaining(&src) == 0); /* the 4 which were there moved */
1116 TEST_CHECK(memcmp(out, src_buff + 4, 4) == 0);
1117}
1118
1119/** FR_DBUFF_BIND_END_ABS hands the extend function to the producer
1120 *
1121 * The bind is what creates the producer/consumer relationship, so the bind is
1122 * where the rule belongs. Only the producer may extend, because
1123 * fr_dbuff_update() repairs the dbuff which was extended and that dbuff's
1124 * ancestors, and never its children. Extending through the consumer would
1125 * leave the producer addressing the old buffer.
1126 *
1127 * The producer's fields are copied out of the consumer while the consumer is
1128 * still writable, because the compound literal is a function argument and so
1129 * is evaluated before the bind runs. These checks pin that ordering, which
1130 * the whole scheme rests on.
1131 */
1133{
1134 fr_dbuff_t consumer, producer;
1135 fr_dbuff_t fixed, fixed_child;
1136 fr_dbuff_uctx_talloc_t tctx;
1138 uint8_t buff[8];
1139 uint8_t *buff_before;
1140
1141 TEST_CASE("the bind marks the consumer const and non-extendable");
1142 MEM(fr_dbuff_init_talloc(NULL, &consumer, &tctx, 4, 64));
1143 TEST_CHECK(consumer.is_const == 0); /* before the bind */
1144 TEST_CHECK(consumer.extend != NULL);
1145 producer = FR_DBUFF_BIND_END_ABS(&consumer);
1146 TEST_CHECK(consumer.is_const == 1);
1147 TEST_CHECK(consumer.extend == NULL);
1148
1149 TEST_CASE("the producer keeps what the consumer had");
1150 TEST_CHECK(producer.is_const == 0); /* copied before the bind cleared it */
1151 TEST_CHECK(producer.extend != NULL);
1152 TEST_CHECK(producer.uctx == consumer.uctx);
1153 TEST_CHECK(producer.parent == &consumer);
1154
1155 TEST_CASE("the producer can still extend, and the consumer follows");
1156 buff_before = consumer.buff;
1157 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x01, 0x02, 0x03, 0x04, 0x05) == 5);
1158 TEST_CHECK(fr_dbuff_len(&producer) > 4); /* grew past the initial size */
1159 TEST_CHECK(producer.buff == consumer.buff); /* the consumer was repaired */
1160 TEST_CHECK(consumer.start == producer.buff);
1161 TEST_CHECK(fr_dbuff_remaining(&consumer) == 5);
1162 (void) buff_before;
1163
1164 TEST_CASE("the consumer refuses to extend however much is asked for");
1165 buff_before = consumer.buff;
1166 status = FR_DBUFF_EXTENDABLE;
1167 TEST_CHECK(fr_dbuff_extend_lowat(&status, &consumer, 1024) == 5);
1168 TEST_CHECK(fr_dbuff_is_extendable(status) == 0);
1169 TEST_CHECK(consumer.buff == buff_before); /* nothing was reallocated */
1170 TEST_CHECK(producer.buff == consumer.buff); /* so the producer is still valid */
1171
1172 consumer.is_const = 0; /* so the free below is honest */
1173 fr_dbuff_free_talloc(&consumer);
1174
1175 TEST_CASE("binding a fixed buffer leaves the producer writable and extendless");
1176 fr_dbuff_init(&fixed, buff, sizeof(buff));
1177 fixed_child = FR_DBUFF_BIND_END_ABS(&fixed);
1178 TEST_CHECK(fixed.is_const == 1);
1179 TEST_CHECK(fixed.extend == NULL);
1180 TEST_CHECK(fixed_child.is_const == 0);
1181 TEST_CHECK(fixed_child.extend == NULL); /* the parent had none to give */
1182 TEST_CHECK(fr_dbuff_in_bytes(&fixed_child, 0xaa, 0xbb) == 2);
1183 TEST_CHECK(fr_dbuff_remaining(&fixed) == 2);
1184}
1185
1186/** A consumer which is drained, refilled, and drained again
1187 *
1188 * fr_tls_bio_dbuff_t is used this way for a whole TLS handshake, so the
1189 * cursors have to survive more than one round. A read leaves the consumer
1190 * empty without any reset, which is what lets a caller loop on
1191 * fr_dbuff_remaining() rather than tracking a fill and drain phase.
1192 */
1194{
1195 fr_dbuff_t consumer, producer;
1196 fr_dbuff_uctx_talloc_t tctx;
1197 uint8_t out[4] = {};
1198
1199 MEM(fr_dbuff_init_talloc(NULL, &consumer, &tctx, 8, 64));
1200 producer = FR_DBUFF_BIND_END_ABS(&consumer);
1201
1202 TEST_CASE("first round");
1203 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x11, 0x22) == 2);
1204 TEST_CHECK(fr_dbuff_remaining(&consumer) == 2);
1205 TEST_CHECK(fr_dbuff_out_memcpy(out, &consumer, 2) == 2);
1206 TEST_CHECK(out[0] == 0x11 && out[1] == 0x22);
1207 TEST_CHECK(fr_dbuff_remaining(&consumer) == 0); /* empty without a reset */
1208
1209 TEST_CASE("second round: a write after a full read is visible");
1210 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x33, 0x44, 0x55) == 3);
1211 TEST_CHECK(fr_dbuff_remaining(&consumer) == 3);
1212 TEST_CHECK(fr_dbuff_out_memcpy(out, &consumer, 3) == 3);
1213 TEST_CHECK(out[0] == 0x33 && out[1] == 0x44 && out[2] == 0x55);
1214
1215 TEST_CASE("a partial read leaves the rest for the next pass");
1216 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x66, 0x77, 0x88) == 3);
1217 TEST_CHECK(fr_dbuff_out_memcpy(out, &consumer, 1) == 1);
1218 TEST_CHECK(out[0] == 0x66);
1219 TEST_CHECK(fr_dbuff_remaining(&consumer) == 2);
1220 TEST_CHECK(fr_dbuff_out_memcpy(out, &consumer, 2) == 2);
1221 TEST_CHECK(out[0] == 0x77 && out[1] == 0x88);
1222 TEST_CHECK(fr_dbuff_remaining(&consumer) == 0);
1223
1224 TEST_CASE("fr_dbuff_shift through the producer reclaims what was read");
1225 TEST_CHECK(fr_dbuff_used(&consumer) == 8); /* 2 + 3 + 3 read so far */
1226 TEST_CHECK(fr_dbuff_shift(&producer, fr_dbuff_used(&consumer)) == 8);
1227 TEST_CHECK(fr_dbuff_used(&consumer) == 0); /* consumer back at the start */
1228 TEST_CHECK(fr_dbuff_remaining(&consumer) == 0); /* and still empty */
1229 TEST_CHECK(fr_dbuff_in_bytes(&producer, 0x99) == 1);
1230 TEST_CHECK(fr_dbuff_remaining(&consumer) == 1);
1231
1232 consumer.is_const = 0; /* so the free below is honest */
1233 fr_dbuff_free_talloc(&consumer);
1234}
1235
1237 /*
1238 * Basic tests
1239 */
1240 { "fr_dbuff_init", test_dbuff_init },
1241 { "fr_dbuff_init_no_parent", test_dbuff_init_no_parent },
1242 { "fr_dbuff_max", test_dbuff_max },
1243 { "fr_dbuff_in", test_dbuff_net_encode },
1244 { "fr_dbuff_no_advance", test_dbuff_no_advance },
1245 { "fr_dbuff_move", test_dbuff_move },
1246 { "fr_dbuff_talloc_extend", test_dbuff_talloc_extend },
1247 { "fr_dbuff_talloc_extend_multi_level", test_dbuff_talloc_extend_multi_level },
1248 { "fr_dbuff_fd", test_dbuff_fd },
1249 { "fr_dbuff_fd_max", test_dbuff_fd_max },
1250 { "fr_dbuff_out", test_dbuff_out },
1251
1252 /*
1253 * Child dbuffs, accessors, positioning and lifecycle
1254 */
1255 { "fr_dbuff_child", test_dbuff_child },
1256 { "fr_dbuff_measure", test_dbuff_measure },
1257 { "fr_dbuff_set", test_dbuff_set },
1258 { "fr_dbuff_advance_extend", test_dbuff_advance_extend },
1259 { "fr_dbuff_memset", test_dbuff_memset },
1260 { "fr_dbuff_in_memcpy", test_dbuff_in_memcpy },
1261 { "fr_dbuff_marker_release", test_dbuff_marker_release },
1262 { "fr_dbuff_out_int64v", test_dbuff_out_int64v },
1263 { "fr_dbuff_shift", test_dbuff_shift },
1264 { "fr_dbuff_update", test_dbuff_update },
1265 { "fr_dbuff_trim_reset_talloc", test_dbuff_trim_reset_talloc },
1266 { "fr_dbuff_tmp", test_dbuff_tmp },
1267 { "fr_dbuff_extend", test_dbuff_extend },
1268 { "fr_dbuff_const_no_extend", test_dbuff_const_no_extend },
1269 { "fr_dbuff_producer_consumer", test_dbuff_producer_consumer },
1270 { "fr_dbuff_drain", test_dbuff_drain },
1271 { "fr_dbuff_bind_end_abs_extend", test_dbuff_bind_end_abs_extend },
1272 { "fr_dbuff_producer_consumer_rounds", test_dbuff_producer_consumer_rounds },
1273 { "fr_dbuff_init_zero_length", test_dbuff_init_zero_length },
1274
1276};
1277
#define TEST_CHECK(cond)
Definition acutest.h:101
#define TEST_CASE(name)
Definition acutest.h:203
#define TEST_ASSERT(cond)
Definition acutest.h:125
#define TEST_TERMINATOR
Definition acutest.h:77
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.
Definition dbuff.c:332
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.
Definition dbuff.c:297
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.
Definition dbuff.c:79
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.
Definition dbuff.c:116
#define fr_dbuff_in_bytes_partial(_dbuff,...)
Copy a partial byte sequence into a dbuff.
Definition dbuff.h:1508
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
Definition dbuff.h:838
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1121
#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...
Definition dbuff.h:819
#define FR_DBUFF_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:239
#define fr_dbuff_ptr(_dbuff_or_marker)
Return a pointer to the dbuff.
Definition dbuff.h:910
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:495
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.
Definition dbuff.h:527
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
Definition dbuff.h:828
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.
Definition dbuff.h:1284
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
#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.
Definition dbuff.h:1904
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:963
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1056
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:387
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:950
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
Definition dbuff.h:632
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
Definition dbuff.h:639
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
Definition dbuff.h:1208
#define fr_dbuff_was_extended(_status)
Check if the dbuff was extended during the last extend call.
Definition dbuff.h:656
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:934
#define FR_DBUFF_INIT(_out, _start, _len_or_end)
Initialise a dbuff for encoding, and define the first byte of the output buffer.
Definition dbuff.h:420
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1785
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:248
#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c.
Definition dbuff.h:1554
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:712
#define fr_dbuff_advance_extend(_dbuff_or_marker, _len)
Advance current'position in dbuff or marker by _len bytes (extending if necessary)
Definition dbuff.h:1188
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
Definition dbuff.h:990
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition dbuff.h:757
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:795
#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:257
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
Definition dbuff.h:1518
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.
Definition dbuff.h:1245
#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num)
Copy an integer value into a dbuff or marker using our internal variable length encoding.
Definition dbuff.h:1665
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1403
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1620
#define fr_dbuff_set_to_end(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'end' of the buffer.
Definition dbuff.h:1214
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:230
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
Definition dbuff.h:1263
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition dbuff.h:334
#define fr_dbuff_is_extendable(_status)
Check if a dbuff can be extended again.
Definition dbuff.h:652
#define fr_dbuff_move(_out, _in, _len)
Copy in as many bytes as possible from one dbuff or marker to another.
Definition dbuff.h:1709
#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:268
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
Definition dbuff.h:848
#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.
Definition dbuff.h:351
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.
Definition dbuff.h:1303
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.
Definition dbuff.h:453
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1852
#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.
Definition dbuff.h:1944
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
Definition dbuff.h:1099
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:556
static void test_dbuff_set(void)
Test fr_dbuff_set (by size_t, pointer, marker) and fr_dbuff_set_end.
TEST_LIST
static void test_dbuff_init_no_parent(void)
Definition dbuff_tests.c:86
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[])
Definition dbuff_tests.c:23
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)
Definition dbuff_tests.c:96
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)
Definition dbuff_tests.c:25
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.
Definition dbuff_tests.c:57
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.
#define MEM(x)
Definition debug.h:38
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061