The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dbuff.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/** A generic data buffer structure for encoding and decoding
19 *
20 * Because doing manual length checks is error prone and a waste of everyone's time.
21 *
22 * @file src/lib/util/dbuff.h
23 *
24 * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25 */
26RCSIDH(dbuff_h, "$Id: 348a481e9e6eb2b98cfb3ff3847db2339c8f392a $")
27
28# ifdef __cplusplus
29extern "C" {
30# endif
31
32#include <errno.h>
33#include <freeradius-devel/missing.h>
34#include <freeradius-devel/util/debug.h>
35#include <freeradius-devel/util/nbo.h>
36#include <limits.h>
37#include <stdbool.h>
38#include <stdint.h>
39#include <sys/types.h>
40
41/** A dbuff
42 *
43 * dbuffs wrap an underlying buffer, maintaining 'start', 'current', and 'end'
44 * position pointers.
45 *
46 * dbuffs also contain information on if and how the underlying buffer can be
47 * extended.
48 *
49 * For encoding extending means reallocing the underlying buffer so that there's
50 * addition space to write data to.
51 *
52 * For stream decoding extending means shifting out existing data and refilling
53 * the underlying buffer from a data source.
54 *
55 * dbuffs are intended to be organised into hierarchies, with one dbuff per stack
56 * frame, initialised from a parent in a higher stack frame.
57 *
58 * Each time a dbuff is copied (using one of the provided FR_DBUFF_BIND_CURRENT_* macros),
59 * the copy's 'start' position is updated to be the 'current' position of its
60 * parent. This ensures length macros report only spaced used/available in the
61 * new dbuff and not its parent.
62 * Other copy macros may move the 'end' position, to artificially limit the
63 * amount of data available.
64 */
65typedef struct fr_dbuff_s fr_dbuff_t;
66
67/** A position marker associated with a dbuff
68 *
69 * Markers are used whenever the caller needs to access part of the underlying
70 * buffer other than the 'start', 'current' or 'end' positions described by
71 * a #fr_dbuff_t.
72 *
73 * Markers are needed because if a #fr_dbuff_t is extended, pointers into the
74 * underlying buffer may be invalidated by a realloc or memmove.
75 *
76 * Markers are intended to be allocated on the stack and associated with a
77 * stack-frame-local `fr_dbuff_t`. Using a stack-frame-local dbuff ensures
78 * markers are automatically released when the stack frame is popped so that
79 * markers are not leaked.
80 */
81typedef struct fr_dbuff_marker_s fr_dbuff_marker_t;
82
83/** dbuff extension callback
84 *
85 * This callback is used to extend the underlying buffer.
86 *
87 * - Where the buffer is being used to aggregate data, this callback will
88 * usually call realloc to extend the buffer.
89 *
90 * - Where the buffer is being used for stream decoding, this callback will
91 * usually shift the existing data in the buffer to the left, and read in more
92 * data from the stream.
93 *
94 * After performing an operation on the underlying buffer, this callback should
95 * call #fr_dbuff_update to fix position pointers in the current dbuff and its
96 * parents and markers.
97 *
98 * Generally the caller will request the minimum amount the buffer should be
99 * extended by. This callback may choose to ignore the request and extend the
100 * buffer by more than the requested amount.
101 *
102 * @param[in] dbuff to extend.
103 * @param[in] req_extension How much the caller wants to extend the buffer
104 * by.
105 * @return How much the buffer was extended by.
106 * @see fr_dbuff_update
107 */
108typedef size_t(*fr_dbuff_extend_t)(fr_dbuff_t *dbuff, size_t req_extension);
109
110/** A position marker associated with a dbuff
111 * @private
112 */
113struct fr_dbuff_marker_s {
114 /** @private
115 */
116 union {
117 uint8_t const *p_i; //!< Immutable position pointer.
118 uint8_t *p; //!< Mutable position pointer.
119 };
120 fr_dbuff_marker_t *next; //!< Next marker in the list.
121 fr_dbuff_t *parent; //!< Owner of the marker.
122};
123
124#define FR_DBUFF_ADV_PARENT_CURRENT 0x01 //!< Advance current position of parent.
125 //!< Useful for nested encoders/decoders.
126#define FR_DBUFF_ADV_PARENT_END 0x02 //!< Advance end pointer of parent.
127 ///< Useful for producer/consumer
128
129/** A dbuff
130 * @private
131 */
132struct fr_dbuff_s {
133 /** @private
134 */
135 union {
136 uint8_t const *buff_i; //!< Immutable 'buffer' pointer.
137 uint8_t *buff; //!< Mutable 'buffer' pointer.
138 };
139
140 /** @private
141 */
142 union {
143 uint8_t const *start_i; //!< Immutable 'start' pointer.
144 uint8_t *start; //!< Mutable 'start' pointer.
145 };
146
147 /** @private
148 */
149 union {
150 uint8_t const *end_i; //!< Immutable 'end' pointer.
151 uint8_t *end; //!< Mutable 'end' pointer.
152 };
153
154 /** @private
155 */
156 union {
157 uint8_t const *p_i; //!< Immutable 'current' pointer.
158 uint8_t *p; //!< Mutable 'current' pointer.
159 };
160
161 uint8_t is_const:1; //!< The buffer this dbuff wraps is const.
162 uint8_t adv_parent:2; //!< Whether we advance the parent
163 ///< of this dbuff.
164
165 size_t shifted; //!< How many bytes this sbuff has been
166 ///< shifted since its creation.
167
168 fr_dbuff_extend_t extend; //!< Function to re-populate or extend
169 ///< the buffer.
170 void *uctx; //!< Extend uctx data.
171
172 fr_dbuff_t *parent; //!< The #fr_dbuff_t this #fr_dbuff_t was
173 ///< created from.
174 ///< This will usually be the #fr_dbuff_t
175 ///< passed into a function.
176
177 fr_dbuff_marker_t *m; //!< Pointers to update if the underlying
178 ///< buffer changes.
179};
180
181/** Generic wrapper macro to return if there's insufficient memory to satisfy the request on the dbuff
182 *
183 */
184#define FR_DBUFF_RETURN(_func, ...) \
185do { \
186 ssize_t _slen = _func(__VA_ARGS__ ); \
187 if (_slen < 0) return _slen; \
188} while (0)
189
190/** @name Initialisers
191 * @{
192 */
193
194/** @cond */
195
196/** Copy another fr_dbuff_t, modifying it.
197 *
198 * @private
199 */
200#define _FR_DBUFF(_dbuff_or_marker, _start, _adv_parent) \
201((fr_dbuff_t){ \
202 .buff = fr_dbuff_buff(_dbuff_or_marker), \
203 .start = (_start), \
204 .end = fr_dbuff_end(_dbuff_or_marker), \
205 .p = fr_dbuff_current(_dbuff_or_marker), \
206 .is_const = fr_dbuff_ptr(_dbuff_or_marker)->is_const, \
207 .adv_parent = (_adv_parent), \
208 .shifted = fr_dbuff_ptr(_dbuff_or_marker)->shifted, \
209 .extend = fr_dbuff_ptr(_dbuff_or_marker)->extend, \
210 .uctx = fr_dbuff_ptr(_dbuff_or_marker)->uctx, \
211 .parent = fr_dbuff_ptr(_dbuff_or_marker) \
212})
213/* @endcond */
214
215/** Create a new dbuff pointing to the same underlying buffer
216 *
217 * - Parent will _NOT_ be advanced by operations on its child.
218 * - Child will have its `start` pointer set to the `p` pointer of the parent.
219 *
220 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
221 */
222#define FR_DBUFF(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_current(_dbuff_or_marker), 0x00)
223
224/** Create a new dbuff pointing to the same underlying buffer
225 *
226 * - Parent will _NOT_ be advanced by operations on its child.
227 * - Child will have its `start` pointer set to the `start` pointer of the parent.
228 *
229 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
230 */
231#define FR_DBUFF_ABS(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), 0x00)
232
233/** Create a new dbuff pointing to the same underlying buffer
234 *
235 * - Parent `p` pointer will be advanced with child's `p` pointer.
236 * - Child will have its `start` pointer set to the `p` pointer of the parent.
237 *
238 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
239 */
240#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_current(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_CURRENT)
241
242/** Create a new dbuff pointing to the same underlying buffer
243 *
244 * - Parent `p` pointer will be advanced with child's `p` pointer.
245 * - Child will have its `start` pointer set to the `start` pointer of the parent.
246 *
247 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
248 */
249#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker) FR_DBUFF_ABS(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_CURRENT)
250
251/** Create a new dbuff pointing to the same underlying buffer
252 *
253 * This is used to create the producer of a producer/consumer pairs of dbuffs.
254 *
255 * - Parent `end` pointer will be advanced with child's `p` pointer.
256 * - Child will have its `start` pointer set to the `start` pointer of the parent.
257 *
258 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
259 */
260#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_END)
261
262/** @cond */
263/** Limit available bytes in the dbuff to _max when passing it to another function
264 *
265 * @private
266 */
267#define _FR_DBUFF_MAX(_dbuff_or_marker, _max, _adv_parent) \
268((fr_dbuff_t){ \
269 .buff = fr_dbuff_buff(_dbuff_or_marker), \
270 .start = fr_dbuff_current(_dbuff_or_marker), \
271 .end = (((fr_dbuff_end(_dbuff_or_marker) - (_max) < fr_dbuff_current(_dbuff_or_marker))) ? fr_dbuff_end(_dbuff_or_marker) : (fr_dbuff_current(_dbuff_or_marker) + (_max))), \
272 .p = fr_dbuff_current(_dbuff_or_marker), \
273 .is_const = fr_dbuff_ptr(_dbuff_or_marker)->is_const, \
274 .adv_parent = _adv_parent, \
275 .shifted = fr_dbuff_ptr(_dbuff_or_marker)->shifted, \
276 .extend = NULL, \
277 .uctx = NULL, \
278 .parent = fr_dbuff_ptr(_dbuff_or_marker) \
279})
280/* @endcond */
281
282/** Limit the maximum number of bytes available in the dbuff when passing it to another function
283 *
284 @code{.c}
285 fr_dbuff_t tlv = FR_DBUFF_MAX(dbuff, UINT8_MAX);
286
287 if (my_child_encoder(&tlv, vp) < 0) return -1;
288
289 return fr_dbuff_advance(dbuff, fr_dbuff_used(tlv))
290 @endcode
291 *
292 * @note Do not use to re-initialise the contents of _dbuff, i.e. to
293 * permanently shrink the exiting dbuff. The parent pointer will loop.
294 *
295 * @note Do not modify the "child" dbuff directly. Use the functions
296 * supplied as part of this API.
297 *
298 * @param[in] _dbuff_or_marker to reserve bytes in.
299 * @param[in] _max The maximum number of bytes the caller is allowed to write to.
300 */
301#define FR_DBUFF_MAX(_dbuff_or_marker, _max) _FR_DBUFF_MAX(_dbuff_or_marker, _max, 0x00)
302
303/** Limit the maximum number of bytes available in the dbuff when passing it to another function
304 *
305 @code{.c}
306 my_child_encoder(&FR_DBUFF_MAX_BIND_CURRENT(dbuff, 253), vp);
307 @endcode
308 *
309 * @note Do not use to re-initialise the contents of _dbuff, i.e. to
310 * permanently shrink the exiting dbuff. The parent pointer will loop.
311 *
312 * @note Do not modify the "child" dbuff directly. Use the functions
313 * supplied as part of this API.
314 *
315 * @param[in] _dbuff_or_marker to reserve bytes in.
316 * @param[in] _max The maximum number of bytes the caller is allowed to write to.
317 */
318#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max) _FR_DBUFF_MAX(_dbuff_or_marker, _max, FR_DBUFF_ADV_PARENT_CURRENT)
319
320/*
321 * GCC is stupid and will warn about output variables
322 * being unnitialised, even if they're not dereferenced.
323 */
324#if defined(__GNUC__) && __GNUC__ >= 11
325DIAG_OFF(maybe-uninitialized)
326#endif
327/** Does the actual work of initialising a dbuff
328 * @private
329 */
330static inline
331#ifndef __COVERITY__
332CC_HINT(nonnull)
333#endif
334void _fr_dbuff_init(fr_dbuff_t *out, uint8_t const *start, uint8_t const *end, bool is_const)
335{
336 if (unlikely(end < start)) end = start; /* Could be an assert? */
337
338 *out = (fr_dbuff_t){
339 .buff_i = start,
340 .start_i = start,
341 .p_i = start,
342 .end_i = end,
343 .is_const = is_const
344 };
345}
346
347/** Initialise an dbuff for encoding or decoding
348 *
349 * @param[out] _out Pointer to buffer to parse
350 * @param[in] _start Start of the buffer to parse.
351 * @param[in] _len_or_end Either an end pointer or the length
352 * of the buffer we're decoding.
353 */
354#define fr_dbuff_init(_out, _start, _len_or_end) \
355_fr_dbuff_init(_out, \
356 (uint8_t const *)(_start), \
357 _Generic((_len_or_end), \
358 size_t : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
359 long : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
360 int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
361 unsigned int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
362 uint8_t * : (uint8_t const *)(_len_or_end), \
363 uint8_t const * : (uint8_t const *)(_len_or_end), \
364 char * : (uint8_t const *)(_len_or_end), \
365 char const * : (uint8_t const *)(_len_or_end) \
366 ), \
367 _Generic((_start), \
368 uint8_t * : false, \
369 uint8_t const * : true, \
370 char * : false, \
371 char const * : true \
372 ))
373#if defined(__GNUC__) && __GNUC__ >= 11
374DIAG_ON(maybe-uninitialized)
375#endif
376
377#define FR_DBUFF_INIT(_out, _start, _len_or_end) do { \
378 fr_dbuff_init(_out, _start, _len_or_end); \
379 *(unsigned char *) _start = '\0'; \
380 } while (0)
381
382size_t _fr_dbuff_extend_talloc(fr_dbuff_t *dbuff, size_t extension);
383
384int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len);
385
387
388/** Talloc extension structure use by #fr_dbuff_init_talloc
389 * @private
390 *
391 * Holds the data necessary for creating dynamically
392 * extensible buffers.
393 */
394typedef struct {
395 TALLOC_CTX *ctx; //!< Context to alloc new buffers in.
396 size_t init; //!< How much to allocate initially.
397 size_t max; //!< Maximum size of the buffer.
398} fr_dbuff_uctx_talloc_t;
399
400/** Initialise a special dbuff which automatically extends as additional data is written
401 *
402 * @param[in] ctx to allocate buffer in.
403 * @param[out] dbuff to initialise.
404 * @param[out] tctx to initialise. Must have a lifetime >= to the dbuff.
405 * @param[in] init The length of the initial buffer.
406 * @param[in] max The maximum length of the buffer.
407 * @return
408 * - The passed dbuff on success.
409 * - NULL on failure.
410 */
411static inline fr_dbuff_t *fr_dbuff_init_talloc(TALLOC_CTX *ctx,
412 fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx,
413 size_t init, size_t max)
414{
415 uint8_t *buff;
416
417 *tctx = (fr_dbuff_uctx_talloc_t){
418 .ctx = ctx,
419 .init = init,
420 .max = max
421 };
422
423 /*
424 * Allocate the initial buffer
425 *
426 * We always allocate a buffer so we don't trigger ubsan
427 * errors by performing arithmetic on NULL pointers.
428 *
429 * Note that unlike sbuffs, we don't need space for a trailing '\0'.
430 */
431 buff = talloc_zero_array(ctx, uint8_t, init);
432 if (!buff) {
433 fr_strerror_printf("Failed allocating buffer of %zu bytes", init);
434 memset(dbuff, 0, sizeof(*dbuff)); /* clang scan */
435 return NULL;
436 }
437
438 *dbuff = (fr_dbuff_t){
439 .buff = buff,
440 .start = buff,
441 .p = buff,
442 .end = buff + init,
443 .extend = _fr_dbuff_extend_talloc,
444 .uctx = tctx
445 };
446
447 return dbuff;
448}
449
450/** Free the talloc buffer associated with a dbuff
451 *
452 */
453static inline void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
454{
455 TALLOC_FREE(dbuff->buff);
456}
457
458size_t _fr_dbuff_extend_fd(fr_dbuff_t *dbuff, size_t extension);
459
460/** File sbuff extension structure use by #fr_dbuff_init_fd
461 * @private
462 *
463 * Holds the data necessary for creating dynamically
464 * extensible file buffers.
465 */
466typedef struct {
467 int fd; //!< fd of file we're reading from.
468 uint8_t *buff_end; //!< The true end of the buffer.
469 size_t max; //!< Maximum number of bytes to read.
470} fr_dbuff_uctx_fd_t;
471
472
473/** Initialise a special dbuff which automatically reads in more data as the buffer is exhausted
474 *
475 * @param[out] dbuff to initialise.
476 * @param[out] fctx to initialise. Must have a lifetime >= to the dbuff.
477 * @param[in] buff Temporary buffer to use for storing file contents.
478 * @param[in] len Length of the temporary buffer.
479 * @param[in] fd descriptor of an open file to read from.
480 * @param[in] max The maximum length of data to read from the file.
481 * @return
482 * - The passed dbuff on success.
483 * - NULL on failure.
484 */
485static inline fr_dbuff_t *fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx,
486 uint8_t *buff, size_t len, int fd, size_t max)
487{
488 *fctx = (fr_dbuff_uctx_fd_t){
489 .fd = fd,
490 .max = max,
491 .buff_end = buff + len //!< Store the real end
492 };
493
494 *dbuff = (fr_dbuff_t){
495 .buff = buff,
496 .start = buff,
497 .p = buff,
498 .end = buff, //!< Starts with 0 bytes available
499 .extend = _fr_dbuff_extend_fd,
500 .uctx = fctx
501 };
502
503 return dbuff;
504}
505
506/** Creates a compound literal to pass into functions which accept a dbuff
507 *
508 * @note The return value of the function should be used to determine how much
509 * data was written to the buffer.
510 *
511 * @param[in] _start of the buffer.
512 * @param[in] _len_or_end Length of the buffer or the end pointer.
513 */
514#define FR_DBUFF_TMP(_start, _len_or_end) \
515(fr_dbuff_t){ \
516 .buff_i = (uint8_t const *)(_start), \
517 .start_i = (uint8_t const *)(_start), \
518 .end_i = _Generic((_len_or_end), \
519 size_t : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
520 long : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
521 int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
522 unsigned int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
523 uint8_t * : (uint8_t const *)(_len_or_end), \
524 uint8_t const * : (uint8_t const *)(_len_or_end), \
525 char * : (uint8_t const *)(_len_or_end), \
526 char const * : (uint8_t const *)(_len_or_end) \
527 ), \
528 .p_i = _start, \
529 .is_const = _Generic((_start), \
530 uint8_t * : false, \
531 uint8_t const * : true, \
532 char * : false, \
533 char const * : true \
534 ) \
535}
536
537/** Structure to encapsulate a thread local dbuff information
538 *
539 */
540typedef struct {
541 fr_dbuff_t dbuff; //!< Thread local dbuff.
542 fr_dbuff_uctx_talloc_t tctx; //!< Thread local tctx.
544
545static inline int _dbuff_thread_local_free(void *dbtl)
546{
547 return talloc_free(dbtl);
548}
549
550/** Create a function local and thread local extensible dbuff
551 *
552 * @param[out] _out Where to write a pointer to the thread local dbuff
553 * @param[in] _init Initial size for the dbuff buffer.
554 * @param[in] _max Maximum size of the dbuff buffer.
555 */
556#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max) \
557do { \
558 static _Thread_local fr_dbuff_thread_local_t *_dbuff_t_local; \
559 if (!_dbuff_t_local) { \
560 fr_dbuff_thread_local_t *dbtl = talloc_zero(NULL, fr_dbuff_thread_local_t); \
561 fr_dbuff_init_talloc(dbtl, &dbtl->dbuff, &dbtl->tctx, _init, _max); \
562 fr_atexit_thread_local(_dbuff_t_local, _dbuff_thread_local_free, dbtl); \
563 *(_out) = &_dbuff_t_local->dbuff; \
564 } else { \
565 fr_dbuff_reset_talloc(&_dbuff_t_local->dbuff); \
566 *(_out) = &_dbuff_t_local->dbuff; \
567 } \
568} while (0)
569/** @} */
570
571/** @name Extension requests
572 *
573 * These functions/macros may be used to request that the underlying buffer is
574 * either extended to accommodate more data, or that data is shifted out of the
575 * buffer, and that the buffer is refilled.
576 *
577 * @{
578 */
579
580/** Flag indicating a dbuff is extendable
581 */
582#define FR_DBUFF_FLAG_EXTENDABLE 0x01
583
584/** Flag indicating that during the last extend call the dbuff was extended
585 */
586#define FR_DBUFF_FLAG_EXTENDED 0x02
587
588/** Whether the buffer is currently extendable and whether it was extended
589 */
590typedef enum {
591 /** dbuff cannot be extended
592 */
594
595 /** dbuff can be extended
596 */
598
599 /** dbuff was extended in the last extend call and may be extended again
600 */
602
603 /** dbuff was extended in the last extend call but cannot be extended again
604 */
607
608/** Check if a dbuff can be extended again
609 */
610#define fr_dbuff_is_extendable(_status) ((_status) & FR_DBUFF_FLAG_EXTENDABLE)
611
612/** Check if the dbuff was extended during the last extend call
613 */
614#define fr_dbuff_was_extended(_status) ((_status) & FR_DBUFF_FLAG_EXTENDED)
615
616/** Internal function - do not call directly
617 * @private
618 */
619static inline size_t _fr_dbuff_extend_lowat(fr_dbuff_extend_status_t *status, fr_dbuff_t *in,
620 size_t remaining, size_t lowat)
621{
622 size_t extended = 0;
623
624 if (status && !fr_dbuff_is_extendable(*status)) {
625 not_extendable:
626 if (status) *status = FR_DBUFF_NOT_EXTENDABLE;
627 return remaining;
628 }
629
630 if (remaining >= lowat) {
631 if (status) *status = FR_DBUFF_EXTENDABLE;
632 return remaining;
633 }
634
635 if (!in->extend || !(extended = in->extend(in, lowat - remaining))) goto not_extendable;
636
637 if (status) *status = FR_DBUFF_EXTENDABLE_EXTENDED;
638
639 return remaining + extended;
640}
641
642/** Extend if we're below _lowat
643 *
644 * @param[out] _status May be NULL. If fr_dbuff_extend_lowat is used
645 * in a copy loop, the caller should pass a pointer
646 * to a #fr_dbuff_extend_status_t. The initial
647 * value of the #fr_dbuff_extend_status_t variable
648 * should be #FR_DBUFF_EXTENDABLE, and will be updated
649 * to indicate whether the dbuff is extensible,
650 * whether it was extended, and whether it may be
651 * extended again. This information
652 * is used the loop condition to prevent spurious
653 * extension calls.
654 * @param[in] _dbuff_or_marker to extend.
655 * @param[in] _lowat If bytes remaining are below the amount, extend.
656 * @return
657 * - 0 if there are no bytes left in the buffer and we couldn't extend.
658 * - >0 the number of bytes in the buffer after extending.
659 */
660#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat) \
661 _fr_dbuff_extend_lowat(_status, \
662 fr_dbuff_ptr(_dbuff_or_marker), \
663 fr_dbuff_remaining(_dbuff_or_marker), _lowat)
664
665/** Extend if we're below _lowat and return if we can't extend above _lowat
666 *
667 * @param[in] _dbuff_or_marker to extend.
668 * @param[in] _lowat If bytes remaining are below the amount, extend.
669 * @return
670 * - 0 if there are no bytes left in the buffer and we couldn't extend.
671 * - >0 the number of bytes in the buffer after extending.
672 */
673#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat) \
674do { \
675 size_t _remaining = fr_dbuff_extend_lowat(NULL, _dbuff_or_marker, _lowat); \
676 if (_remaining < _lowat) return -(_lowat - _remaining); \
677} while (0)
678
679/** @cond */
680/** Extend if we're below _lowat and return if we can't extend above _lowat
681 *
682 * @private
683 *
684 * @param[in,out] _pos_p the position pointer to use.
685 * @param[in] _dbuff_or_marker to extend.
686 * @param[in] _lowat The minimum amount the dbuff should be extended by.
687 * @return The number of bytes we would need to satisfy _lowat as a negative integer.
688 */
689#define _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(_pos_p, _dbuff_or_marker, _lowat) \
690do { \
691 size_t _remaining = _fr_dbuff_extend_lowat(NULL, \
692 fr_dbuff_ptr(_dbuff_or_marker), \
693 fr_dbuff_end(_dbuff_or_marker) - (*(_pos_p)), _lowat); \
694 if (_remaining < _lowat) return -(_lowat - _remaining); \
695} while (0)
696/** @endcond */
697
698/** Extend if no space remains
699 *
700 * @param[in] _dbuff to extend.
701 * @return
702 * - 0 if there are no bytes left in the buffer and we couldn't extend.
703 * - >0 the number of bytes in the buffer after extending.
704 */
705#define fr_dbuff_extend(_dbuff) fr_dbuff_extend_lowat(NULL, _dbuff, 1)
706/** @} */
707
708/** @name Extension callback helpers
709 *
710 * These public functions are intended to be called by extension callbacks
711 * to fixup dbuffs after the underlying buffer or its contents has been altered.
712 * @{
713 */
714void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len);
715
716size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift);
717/** @} */
718
719/** @name Length checks
720 *
721 * These macros return the amount of data used/remaining relative to the dbuff
722 * or marker's 'start', 'current', and 'end' pointers.
723 *
724 * In the majority of cases these macros should not be used and the extension
725 * request functions should be used instead. The only exception to this is if
726 * the caller is certain the #fr_dbuff_t is not extensible.
727 *
728 * @{
729 */
730/** Return the number of bytes remaining between the dbuff or marker and the end of the buffer
731 *
732 * @note Do not use this in functions that may be used for stream decoding
733 * unless you're sure you know what you're doing.
734 * The value return does not reflect the number of bytes that may
735 * be potentially read from the stream, only the number of bytes
736 * until the end of the current chunk.
737 *
738 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
739 * @return
740 * - >0 the number of bytes remaining before we reach the end of the buffer.
741 * - -0 we're at the end of the buffer.
742 */
743#define fr_dbuff_remaining(_dbuff_or_marker) \
744 ((size_t)(fr_dbuff_end(_dbuff_or_marker) < fr_dbuff_current(_dbuff_or_marker) ? \
745 0 : (fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_current(_dbuff_or_marker))))
746
747/** Check if _len bytes are available in the dbuff and if not return the number of bytes we'd need
748 *
749 * @note Do not use this in functions that may be used for stream decoding
750 * unless you're sure you know what you're doing.
751 * The value return does not reflect the number of bytes that may
752 * be potentially read from the stream, only the number of bytes
753 * until the end of the current chunk.
754 *
755 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
756 * @param[in] _len Minimum remaining bytes.
757 * @return
758 * - >0 the number of bytes remaining before we reach the end of the buffer.
759 * - -0 we're at the end of the buffer.
760 */
761#define FR_DBUFF_REMAINING_RETURN(_dbuff_or_marker, _len) \
762 if ((_len) > fr_dbuff_remaining(_dbuff_or_marker)) return -((_len) - fr_dbuff_remaining(_dbuff_or_marker))
763
764/** Return the number of bytes remaining between the start of the dbuff or marker and the current position
765 *
766 */
767#define fr_dbuff_used(_dbuff_or_marker) \
768 ((size_t)(fr_dbuff_start(_dbuff_or_marker) > fr_dbuff_current(_dbuff_or_marker) ? \
769 0 : (fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker))))
770
771/** The length of the underlying buffer
772 *
773 * @param[in] _dbuff_or_marker to return the length of.
774 * @return The length of the underlying buffer.
775 */
776#define fr_dbuff_len(_dbuff_or_marker) \
777 ((size_t)(fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker)))
778
779/** How many bytes the dbuff or marker is behind its parent
780 *
781 * @param[in] _dbuff_or_marker
782 * @return
783 * - 0 the dbuff or marker is ahead of its parent.
784 * - >0 the number of bytes the marker is behind its parent.
785 */
786#define fr_dbuff_behind(_dbuff_or_marker) \
787 (fr_dbuff_current(_dbuff_or_marker) > fr_dbuff_current((_dbuff_or_marker)->parent) ? \
788 0 : fr_dbuff_current((_dbuff_or_marker)->parent) - fr_dbuff_current(_dbuff_or_marker))
789
790/** How many bytes the dbuff or marker is ahead of its parent
791 *
792 * @return
793 * - 0 the dbuff or marker is behind its parent.
794 * - >0 the number of bytes the marker is ahead of its parent.
795 */
796#define fr_dbuff_ahead(_dbuff_or_marker) \
797 (fr_dbuff_current((_dbuff_or_marker)->parent) > fr_dbuff_current(_dbuff_or_marker) ? \
798 0 : fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_current((_dbuff_or_marker)->parent))
799/** @} */
800
801/** @name Accessors
802 *
803 * Caching the pointers returned by the accessors is strongly discouraged.
804 * Cached pointers can become invalidated if the #fr_dbuff_t is extended, as
805 * the extensions callback may use realloc or memmove on the underlying buffer.
806 *
807 @code{.c}
808 fr_dbuff_t dbuff;
809 fr_dbuff_uctx_talloc_t tctx;
810 uint8_t *p;
811
812 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
813
814 p = fr_dbuff_current(&dbuff); // Cache the start pointer
815 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
816
817 printf("%s", p); // Should print an empty string but may
818 // SEGV as p may now be invalid.
819 @endcode
820 *
821 * If offsets of a #fr_dbuff_t need to be accessed, markers should be used.
822 * If a dbuff is extended all markers associated with it will be updated so that the
823 * content they point to remains constant.
824 *
825 @code{.c}
826 fr_dbuff_t dbuff;
827 fr_dbuff_uctx_talloc_t tctx;
828 fr_dbuff_marker_t m;
829
830 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
831 fr_dbuff_marker(&m, &dbuff);
832
833 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
834
835 printf("%s", fr_dbuff_current(&m)); // Marker was updated when the dbuff
836 // was extended. All is well.
837 @endcode
838 *
839 * Using offsets of the pointers returned by accessor functions is also strongly
840 * discouraged as it invalidates many of the protections dbuffs give.
841 *
842 @code{.c}
843 uint8_t buff[2];
844 fr_dbuff_t dbuff;
845
846 fr_dbuff_init(&dbuff, buff, sizeof(buff));
847 fr_dbuff_current(&dbuff)[2] = 0x00; // Write to invalid memory
848 @endcode
849 *
850 * @{
851 */
852
853/** Return a pointer to the dbuff
854 *
855 * @param[in] _dbuff_or_marker to return a pointer to.
856 * @return A pointer to the dbuff.
857 */
858#define fr_dbuff_ptr(_dbuff_or_marker) \
859 _Generic((_dbuff_or_marker), \
860 fr_dbuff_t * : ((fr_dbuff_t *)(_dbuff_or_marker)), \
861 fr_dbuff_marker_t * : (((fr_dbuff_marker_t *)(_dbuff_or_marker))->parent) \
862 )
863
864/** Return a const pointer to the dbuff
865 *
866 * @param[in] _dbuff_or_marker to return a pointer to.
867 * @return A pointer to the dbuff.
868 */
869#define fr_dbuff_ptr_const(_dbuff_or_marker) \
870 _Generic((_dbuff_or_marker), \
871 fr_dbuff_t * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
872 fr_dbuff_t const * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
873 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent), \
874 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent) \
875 )
876
877/** Return the underlying buffer in a dbuff or one of marker
878 *
879 * @param[in] _dbuff_or_marker to return the buffer for.
880 * @return A pointer to the start of the buffer.
881 */
882#define fr_dbuff_buff(_dbuff_or_marker) \
883 _Generic((_dbuff_or_marker), \
884 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
885 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
886 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff), \
887 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff) \
888 )
889
890/** Return the 'start' position of a dbuff or marker
891 *
892 * The start position is not necessarily the start of the buffer, and is
893 * advanced every time a dbuff is copied.
894 *
895 * @param[in] _dbuff_or_marker to return the start position of.
896 * @return A pointer to the start position of the buffer.
897 */
898#define fr_dbuff_start(_dbuff_or_marker) \
899 (_Generic((_dbuff_or_marker), \
900 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
901 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
902 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start), \
903 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start) \
904 ))
905
906/** Return the 'current' position of a dbuff or marker
907 *
908 * @param[in] _dbuff_or_marker to return the current position of.
909 * @return A pointer to the current position of the buffer or marker.
910 */
911#define fr_dbuff_current(_dbuff_or_marker) \
912 (_Generic((_dbuff_or_marker), \
913 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
914 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
915 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p), \
916 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p) \
917 ))
918
919/** @cond */
920/** Return a pointer to the 'current' position in a dbuff or marker
921 * @private
922 *
923 * @param[in] _dbuff_or_marker to return a pointer to the position pointer for.
924 * @return A pointer to the position pointer in the dbuff or marker.
925 */
926#define _fr_dbuff_current_ptr(_dbuff_or_marker) \
927 (_Generic((_dbuff_or_marker), \
928 fr_dbuff_t * : &(((fr_dbuff_t *)(_dbuff_or_marker))->p), \
929 fr_dbuff_marker_t * : &(((fr_dbuff_marker_t *)(_dbuff_or_marker))->p) \
930 ))
931/** @endcond */
932
933/** Return the current 'end' position of a dbuff or marker
934 *
935 * @param[in] _dbuff_or_marker to return the end position of.
936 * @return A pointer to the end position of the buffer or marker.
937 */
938#define fr_dbuff_end(_dbuff_or_marker) \
939 (_Generic((_dbuff_or_marker), \
940 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
941 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
942 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end), \
943 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end) \
944 ))
945/** @} */
946
947/** @name Position modification (recursive)
948 *
949 * Modify the 'current' position pointer of a dbuff or marker.
950 * @{
951 */
952
953/** Set a new 'current' position in a dbuff or marker
954 * @private
955 */
956static inline void _fr_dbuff_set_recurse(fr_dbuff_t *dbuff, uint8_t adv_parent_flags, uint8_t const *p)
957{
958 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_CURRENT) dbuff->p_i = p;
959 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_END) dbuff->end_i = p;
960
961 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
962}
963
964/** Set a new 'current' position in a dbuff or marker
965 * @private
966 *
967 * @param[in,out] pos_p position pointer to modify.
968 * @param[out] dbuff dbuff to use for constraints checks.
969 * @param[in] p Position to set.
970 * @return
971 * - 0 not advanced (p before dbuff start) or after dbuff end.
972 * - >0 the number of bytes the dbuff advanced by.
973 * - <0 the number of bytes the dbuff retreated by.
974 *
975 */
976static inline ssize_t _fr_dbuff_set(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t const *p)
977{
978 uint8_t *c;
979
980 if (unlikely(p > dbuff->end)) return -(p - dbuff->end);
981 if (unlikely(p < dbuff->start)) return 0;
982
983 c = *pos_p;
984 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
985 *pos_p = UNCONST(uint8_t *, p);
986
987 return p - c;
988}
989
990/** Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer, or a length value
991 *
992 * @param[in] _dst dbuff or marker to set the position for.
993 * @param[in] _src Variable to glean new position from. Behaviour here
994 * depends on the type of the variable.
995 * - dbuff, the current position of the dbuff.
996 * - marker, the current position of the marker.
997 * - pointer, the position of the pointer.
998 * - size_t, _dst->start + _src.
999 * @return
1000 * - 0 not advanced.
1001 * - >0 the number of bytes the dbuff was advanced by.
1002 * - <0 the number of bytes required to complete the advancement
1003 */
1004#define fr_dbuff_set(_dst, _src) \
1005_fr_dbuff_set(\
1006 _fr_dbuff_current_ptr(_dst), fr_dbuff_ptr(_dst), \
1007 _Generic((_src), \
1008 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_src)), \
1009 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_src)), \
1010 uint8_t const * : (uint8_t const *)(_src), \
1011 uint8_t * : (uint8_t const *)(_src), \
1012 size_t : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1013 long : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1014 int : (fr_dbuff_start(_dst) + (uintptr_t)(_src)) \
1015 ) \
1016)
1017
1018/** Set the 'current' position in a dbuff or marker returning if _src is out of range
1019 *
1020 * @copydetails fr_dbuff_set
1021 */
1022#define FR_DBUFF_SET_RETURN(_dst, _src) FR_DBUFF_RETURN(fr_dbuff_set, _dst, _src)
1023
1024/** Set a new 'end' position in a dbuff or marker
1025 * @private
1026 *
1027 * @param[out] dbuff dbuff to use for constraints checks.
1028 * @param[in] p Position to set.
1029 * @return
1030 * - 0 not advanced (p before dbuff start) or after dbuff end.
1031 * - >0 the number of bytes the dbuff was trimmed by.
1032 */
1033static inline ssize_t _fr_dbuff_set_end(fr_dbuff_t *dbuff, uint8_t const *p)
1034{
1035 if (unlikely(p > dbuff->end)) return -(p - dbuff->end);
1036 if (unlikely(p < dbuff->start)) return 0;
1037
1038 dbuff->end = UNCONST(uint8_t *, p);
1039
1040 return dbuff->end - p;
1041}
1042
1043/** Set a new 'end' position in a dbuff or marker
1044 *
1045 * @param[out] _dst dbuff to use for constraints checks.
1046 * @param[in] _end Position to set.
1047 * @return
1048 * - 0 not advanced (p before dbuff start) or after dbuff end.
1049 * - >0 the number of bytes the dbuff was trimmed by.
1050 */
1051#define fr_dbuff_set_end(_dst, _end) \
1052_fr_dbuff_set_end(\
1053 fr_dbuff_ptr(_dst), \
1054 _Generic((_end), \
1055 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_end)), \
1056 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_end)), \
1057 uint8_t const * : (uint8_t const *)(_end), \
1058 uint8_t * : (uint8_t const *)(_end) \
1059 ) \
1060)
1061
1062/** Advance 'current' position in dbuff or marker by _len bytes
1063 *
1064 * @param[in] _dbuff_or_marker to advance.
1065 * @param[in] _len How much to advance dbuff by.
1066 * Must be a positive integer.
1067 * @return
1068 * - 0 not advanced.
1069 * - >0 the number of bytes the dbuff or marker was advanced by.
1070 * - <0 the number of bytes required to complete the advancement
1071 */
1072#define fr_dbuff_advance(_dbuff_or_marker, _len) \
1073 fr_dbuff_set(_dbuff_or_marker, \
1074 (fr_dbuff_current(_dbuff_or_marker) + \
1075 (_Generic((_len), \
1076 unsigned char : (size_t)(_len), \
1077 unsigned short : (size_t)(_len), \
1078 unsigned int : (size_t)(_len), \
1079 unsigned long : (size_t)(_len), \
1080 unsigned long long : (size_t)(_len), \
1081 int : (size_t)(_len) \
1082 ))))
1083
1084/** Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range
1085 *
1086 * @copydetails fr_dbuff_advance
1087 */
1088#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance, _dbuff_or_marker, _len)
1089
1090/** Advance a dbuff or marker potentially extending it
1091 * @private
1092 *
1093 * @param[in,out] pos_p position pointer to modify.
1094 * @param[out] dbuff dbuff to use for constraints checks.
1095 * @param[in] len Number of bytes to advance by.
1096 * @return
1097 * - 0 not advanced, specified length would take us
1098 * past the end of the buffer, and we couldn't extend
1099 * by enough bytes.
1100 * - >0 the number of bytes the dbuff advanced by.
1101 * - <0 the number of bytes we'd need to complete the advance.
1102 *
1103 */
1104static inline ssize_t _fr_dbuff_advance_extend(uint8_t **pos_p, fr_dbuff_t *dbuff, size_t len)
1105{
1106 uint8_t *p = *pos_p + len;
1107
1108 if (p > dbuff->end) {
1109 size_t rel = p - dbuff->start; /* Get relative position to the start */
1110
1111 if (!dbuff->extend) {
1112 oos:
1113 return -((dbuff->start + rel) - dbuff->end);
1114 }
1115
1116 dbuff->extend(dbuff, p - dbuff->end); /* Try and extend by the number of bytes over */
1117 if ((dbuff->start + rel) > dbuff->end) goto oos;
1118
1119 *pos_p = dbuff->start + rel; /* Update pos_p */
1120 } else {
1121 *pos_p += len;
1122 }
1123
1124 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, *pos_p);
1125
1126 return len;
1127}
1128
1129/** Advance current'position in dbuff or marker by _len bytes (extending if necessary)
1130 *
1131 * @param[in] _dbuff_or_marker to advance.
1132 * @param[in] _len How much to advance dbuff by.
1133 * Must be a positive integer.
1134 * @return
1135 * - 0 not advanced.
1136 * - >0 the number of bytes the dbuff or marker was advanced by.
1137 * - <0 the number of bytes we'd need to complete the advance.
1138 */
1139#define fr_dbuff_advance_extend(_dbuff_or_marker, _len) \
1140 _fr_dbuff_advance(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), \
1141 (_Generic((_len), \
1142 unsigned char : (size_t)(_len), \
1143 unsigned short : (size_t)(_len), \
1144 unsigned int : (size_t)(_len), \
1145 unsigned long : (size_t)(_len), \
1146 unsigned long long : (size_t)(_len), \
1147 int : (size_t)(_len) \
1148 )))
1149
1150#define FR_DBUFF_BIND_EXTEND_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance_extend, _dbuff_or_marker, _len)
1151
1152/** Reset the 'current' position of the dbuff or marker to the 'start' of the buffer
1153 *
1154 */
1155#define fr_dbuff_set_to_start(_dbuff_or_marker) \
1156 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker))
1157
1158/** Reset the 'current' position of the dbuff or marker to the 'end' of the buffer
1159 *
1160 */
1161#define fr_dbuff_set_to_end(_dbuff_or_marker) \
1162 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_end(_dbuff_or_marker))
1163/** @} */
1164
1165/** @name Marker management
1166 *
1167 * Markers serve two purposes:
1168 *
1169 * - Markers allow the caller to track content in a dbuff as the dbuff is extended.
1170 * If the caller referred to content using a pointer into the underlying buffer,
1171 * that pointer may be invalidated if the buffer were extended.
1172 *
1173 * - Markers prevent content being shifted out of the buffer during an extension.
1174 *
1175 * Most operations that can be performed on an #fr_dbuff_t can also be performed
1176 * on a #fr_dbuff_marker_t.
1177 *
1178 * It is recommended that markers be created against a stack-frame-local dbuff so
1179 * that they are automatically released when the framed is popped.
1180 *
1181 * @see fr_dbuff_marker_t
1182 *
1183 * @{
1184 */
1185
1186/** Initialises a new marker pointing to the 'current' position of the dbuff
1187 *
1188 * @param[out] m to initialise.
1189 * @param[in] dbuff to associate marker with.
1190 * @return The position the marker was set to.
1191 */
1193{
1194 *m = (fr_dbuff_marker_t){
1195 .next = dbuff->m, /* Link into the head */
1196 .p = dbuff->p, /* Set the current position in the dbuff */
1197 .parent = dbuff /* Record which dbuff this marker was associated with */
1198 };
1199 dbuff->m = m;
1200
1201 return dbuff->p;
1202}
1203
1204/** Releases the specified marker and any markers added before it
1205 *
1206 * Pointers should be released in the inverse order to allocation.
1207 *
1208 * @param[in] m to release.
1209 */
1211{
1212 m->parent->m = m->next;
1213
1214#ifndef NDEBUG
1215 memset(m, 0, sizeof(*m)); /* Use after release */
1216#endif
1217}
1218
1219/** Trims the linked list back to the specified pointer and return how many bytes marker was behind p
1220 *
1221 * Pointers should be released in the inverse order to allocation.
1222 *
1223 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1224 * also being removed from the list.
1225 *
1226 * @param[in] m to release.
1227 * @return
1228 * - 0 marker is ahead of p.
1229 * - >0 the number of bytes the marker is behind p.
1230 */
1232{
1233 size_t len = fr_dbuff_behind(m);
1235 return len;
1236}
1237
1238/** Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p
1239 *
1240 * Pointers should be released in the inverse order to allocation.
1241 *
1242 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1243 * also being removed from the list.
1244 *
1245 * @param[in] m to release.
1246 * @return
1247 * - 0 marker is ahead of p.
1248 * - >0 the number of bytes the marker is behind p.
1249 */
1251{
1252 size_t len = fr_dbuff_ahead(m);
1254 return len;
1255}
1256/** @} */
1257
1258/** @name "in" functions (copy data into a dbuff)
1259 * @{
1260 */
1261
1262/** Internal copy function to switch between memcpy and memmove - do not call directly
1263 *
1264 * @private
1265 *
1266 * @param[out] o_start Where to copy data to.
1267 * @param[in] o_end end of the output buffer.
1268 * @param[in] i_start Where to copy data from.
1269 * @param[in] i_end end of the source buffer.
1270 * @return
1271 * - 0 on sanity check error.
1272 * - >0 the number of bytes copied.
1273 */
1274static inline CC_HINT(always_inline) size_t _fr_dbuff_safecpy(uint8_t *o_start, uint8_t *o_end,
1275 uint8_t const *i_start, uint8_t const *i_end)
1276{
1277 ssize_t diff;
1278 size_t i_len = i_end - i_start;
1279
1280 if (unlikely((o_end < o_start) || (i_end < i_start))) return 0; /* sanity check */
1281
1282 diff = (o_end - o_start) - (i_len);
1283 if (diff < 0) return 0;
1284
1285 if ((i_start > o_end) || (i_end < o_start)) { /* no-overlap */
1286 memcpy(o_start, i_start, i_len);
1287 } else { /* overlap */
1288 memmove(o_start, i_start, i_len);
1289 }
1290
1291 return (i_len);
1292}
1293
1294/** Internal function - do not call directly
1295 *
1296 * @private
1297 */
1298static inline ssize_t _fr_dbuff_in_memcpy(uint8_t **pos_p, fr_dbuff_t *out,
1299 uint8_t const *in, size_t inlen)
1300{
1301 fr_assert(!out->is_const);
1302
1303 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, inlen);
1304
1305 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen)); /* Advance out */
1306}
1307
1308/** Internal function - do not call directly
1309 *
1310 * @private
1311 */
1312static inline ssize_t _fr_dbuff_in_memcpy_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1313 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1314{
1315 fr_dbuff_t *our_in;
1316 uint8_t **our_in_p;
1317 size_t ext_len;
1318
1319 memcpy(&our_in, &in, sizeof(our_in)); /* Stupid const issues caused by generics */
1320 memcpy(&our_in_p, &in_p, sizeof(our_in_p)); /* Stupid const issues caused by generics */
1321
1322 if (inlen == SIZE_MAX) {
1323 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1324 if (ext_len < inlen) inlen = ext_len;
1325 } else {
1326 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(our_in_p, our_in, inlen); /* Extend in or return */
1327 }
1328 return _fr_dbuff_in_memcpy(pos_p, out, *our_in_p, inlen); /* Copy _in to _out */
1329}
1330
1331/** Copy exactly _inlen bytes into a dbuff or marker
1332 *
1333 * If _in is a dbuff and _inlen is greater than the number of bytes available
1334 * in that dbuff, the copy operation will fail.
1335 *
1336 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1337 *
1338 * @param[in] _dbuff_or_marker to copy data to.
1339 * @param[in] _in data to copy in to the dbuff or marker.
1340 * @param[in] _inlen How much data we need to copy.
1341 * If _in is a `char *` or `dbuff *` and SIZE_MAX
1342 * is passed, then _inlen will be substituted
1343 * for the length of the data in the dbuff.
1344 * @return
1345 * - 0 no data copied.
1346 * - >0 the number of bytes copied to the dbuff.
1347 * - <0 the number of bytes we would have needed
1348 * to complete the copy operation.
1349 */
1350#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen) \
1351 _Generic((_in), \
1352 uint8_t * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1353 fr_dbuff_ptr(_dbuff_or_marker), \
1354 (uint8_t const *)(_in), \
1355 _inlen), \
1356 uint8_t const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1357 fr_dbuff_ptr(_dbuff_or_marker), \
1358 (uint8_t const *)(_in), \
1359 _inlen), \
1360 char * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1361 fr_dbuff_ptr(_dbuff_or_marker), \
1362 (uint8_t const *)(_in), \
1363 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1364 char const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1365 fr_dbuff_ptr(_dbuff_or_marker), \
1366 (uint8_t const *)(_in), \
1367 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1368 fr_dbuff_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1369 fr_dbuff_ptr(_dbuff_or_marker), \
1370 &((fr_dbuff_t const *)(_in))->p, \
1371 ((fr_dbuff_t const *)(_in)), \
1372 _inlen), \
1373 fr_dbuff_marker_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1374 fr_dbuff_ptr(_dbuff_or_marker), \
1375 &((fr_dbuff_marker_t const *)(_in))->p, \
1376 ((fr_dbuff_marker_t const *)(_in))->parent, _inlen) \
1377 )
1378
1379/** Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space
1380 * @copydetails fr_dbuff_in_memcpy
1381 */
1382#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen) FR_DBUFF_RETURN(fr_dbuff_in_memcpy, _dbuff_or_marker, _in, _inlen)
1383
1384/** Internal function - do not call directly
1385 *
1386 * @private
1387 */
1388static inline size_t _fr_dbuff_in_memcpy_partial(uint8_t **pos_p, fr_dbuff_t *out,
1389 uint8_t const *in, size_t inlen)
1390{
1391 size_t ext_len;
1392
1393 fr_assert(!out->is_const);
1394
1395 ext_len = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*pos_p), inlen);
1396 if (ext_len < inlen) inlen = ext_len;
1397
1398 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen));
1399}
1400
1401/** Internal function - do not call directly
1402 *
1403 * @private
1404 */
1405static inline size_t _fr_dbuff_in_memcpy_partial_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1406 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1407{
1408 fr_dbuff_t *our_in = UNCONST(fr_dbuff_t *, in); /* Stupid const issues caused by generics */
1409 uint8_t **our_in_p = UNCONST(uint8_t **, in_p); /* Stupid const issues caused by generics */
1410 size_t ext_len;
1411
1412 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1413 if (ext_len < inlen) inlen = ext_len;
1414
1415 return _fr_dbuff_in_memcpy_partial(pos_p, out, (*our_in_p), inlen);
1416}
1417
1418/** Copy at most _inlen bytes into the dbuff
1419 *
1420 * Use this variant when writing data to a streaming buffer where
1421 * partial writes will be tracked.
1422 *
1423 * If _in is a #fr_dbuff_t and _inlen is greater than the number of bytes
1424 * available in that dbuff, the copy operation will truncated.
1425 *
1426 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1427 *
1428 * @param[in] _out to copy data to.
1429 * @param[in] _in Data to copy to dbuff.
1430 * @param[in] _inlen How much data we need to copy.
1431 * If _in is a char * or dbuff * and SIZE_MAX
1432 * is passed, then _inlen will be substituted
1433 * for the length of the buffer.
1434 * @return
1435 * - 0 no data copied.
1436 * - >0 the number of bytes copied to the dbuff.
1437 */
1438#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen) \
1439 _Generic((_in), \
1440 uint8_t * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1441 uint8_t const * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1442 char * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
1443 char const * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
1444 fr_dbuff_t * : _fr_dbuff_in_memcpy_partial_dbuff(_fr_dbuff_current_ptr(_out), fr_dbuff_ptr(_out), &((fr_dbuff_t const *)(_in))->p, ((fr_dbuff_t const *)(_in)), _inlen), \
1445 fr_dbuff_marker_t * : _fr_dbuff_in_memcpy_partial_dbuff(_fr_dbuff_current_ptr(_out), fr_dbuff_ptr(_out), &((fr_dbuff_marker_t const *)(_in))->p, ((fr_dbuff_marker_t const *)(_in))->parent, _inlen) \
1446 )
1447
1448/** Copy a partial byte sequence into a dbuff
1449 *
1450 * @copybrief fr_dbuff_in_memcpy_partial
1451 *
1452 * @param[in] _dbuff to copy byte sequence into.
1453 * @param[in] ... bytes to copy.
1454 */
1455#define fr_dbuff_in_bytes_partial(_dbuff, ...) \
1456 fr_dbuff_in_memcpy_partial(_dbuff, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1457
1458/** Copy a byte sequence into a dbuff or marker
1459 *
1460 * @copybrief fr_dbuff_in_memcpy
1461 *
1462 * @param[in] _dbuff_or_marker to copy byte sequence into.
1463 * @param[in] ... bytes to copy.
1464 */
1465#define fr_dbuff_in_bytes(_dbuff_or_marker, ...) \
1466 fr_dbuff_in_memcpy(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1467
1468/** Copy a byte sequence into a dbuff or marker returning if there's insufficient space
1469 *
1470 * @copydetails fr_dbuff_in_bytes
1471 */
1472#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker, ...) \
1473 FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1474
1475/** Internal function - do not call directly
1476 *
1477 * @private
1478 */
1479static inline ssize_t _fr_dbuff_memset(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t c, size_t inlen)
1480{
1481 fr_assert(!dbuff->is_const);
1482
1483 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, dbuff, inlen);
1484
1485 memset((*pos_p), c, inlen);
1486
1487 return _fr_dbuff_set(pos_p, dbuff, (*pos_p) + inlen);
1488}
1489
1490/** Set _inlen bytes of a dbuff or marker to _c
1491 *
1492 * @param[in] _dbuff_or_marker to copy data to.
1493 * Will be advanced by _inlen bytes.
1494 * @param[in] _c Value to set.
1495 * @param[in] _inlen How much data we need to copy.
1496 * @return
1497 * - 0 no data set.
1498 * - >0 the number of bytes set in the dbuff.
1499 * - <0 the number of bytes required.
1500 */
1501#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen) \
1502 _fr_dbuff_memset(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _c, _inlen)
1503
1504/** Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space
1505 *
1506 * @copydetails fr_dbuff_memset
1507 */
1508#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen) FR_DBUFF_RETURN(fr_dbuff_memset, _dbuff_or_marker, _c, _inlen)
1509
1510/** @cond */
1511/** Define integer decoding functions
1512 * @private
1513 */
1514#define FR_DBUFF_PARSE_INT_DEF(_type) \
1515static inline ssize_t _fr_dbuff_in_##_type(uint8_t **pos_p, fr_dbuff_t *out, _type##_t num) \
1516{ \
1517 fr_assert(!out->is_const); \
1518 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, sizeof(_type##_t)); \
1519 fr_nbo_from_##_type((*pos_p), num); \
1520 return _fr_dbuff_set(pos_p, out, (*pos_p) + sizeof(_type##_t)); \
1521}
1522FR_DBUFF_PARSE_INT_DEF(uint16)
1523FR_DBUFF_PARSE_INT_DEF(uint32)
1524FR_DBUFF_PARSE_INT_DEF(uint64)
1525FR_DBUFF_PARSE_INT_DEF(int16)
1526FR_DBUFF_PARSE_INT_DEF(int32)
1527FR_DBUFF_PARSE_INT_DEF(int64)
1528/** @endcond */
1529
1530/*
1531
1532 */
1533
1534/** Internal function - do not call directly
1535 *
1536 * The fr_dbuff_in_<type>() functions take rvalues, so to implement float and
1537 * double in terms of the same-sized integers, we need a layer that gives us an
1538 * lvalue whose address we can cast.
1539 *
1540 * @private
1541 */
1542static inline ssize_t _fr_dbuff_in_float(uint8_t **pos_p, fr_dbuff_t *out, float num)
1543{
1544 return _fr_dbuff_in_uint32(pos_p, out, *(uint32_t *)(&num));
1545}
1546
1547/** Internal function - do not call directly
1548 *
1549 * @copydetails _fr_dbuff_in_float
1550 *
1551 * @private
1552 */
1553static inline ssize_t _fr_dbuff_in_double(uint8_t **pos_p, fr_dbuff_t *out, double num)
1554{
1555 return _fr_dbuff_in_uint64(pos_p, out, *(uint64_t *)(&num));
1556}
1557
1558/** Copy data from a fixed sized C type into a dbuff or marker
1559 *
1560 * @param[out] _dbuff_or_marker to write to. Integer types will be automatically
1561 converted to big endian byte order.
1562 * @param[in] _in Value to copy.
1563 * @return
1564 * - <0 the number of bytes we would have needed to complete the conversion.
1565 * - >0 the number of bytes _dbuff_or_marker was advanced by.
1566 */
1567#define fr_dbuff_in(_dbuff_or_marker, _in) \
1568 _Generic((_in), \
1569 int8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (int8_t)_in), \
1570 int16_t : _fr_dbuff_in_int16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int16_t)_in), \
1571 int32_t : _fr_dbuff_in_int32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int32_t)_in), \
1572 int64_t : _fr_dbuff_in_int64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int64_t)_in), \
1573 uint8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (uint8_t)_in), \
1574 uint16_t : _fr_dbuff_in_uint16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint16_t)_in), \
1575 uint32_t : _fr_dbuff_in_uint32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint32_t)_in), \
1576 uint64_t : _fr_dbuff_in_uint64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint64_t)_in), \
1577 float : _fr_dbuff_in_float(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (float)_in), \
1578 double : _fr_dbuff_in_double(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (double)_in) \
1579 )
1580
1581/** Copy data from a fixed sized C type into a dbuff returning if there is insufficient space
1582 *
1583 * @copydetails fr_dbuff_in
1584 */
1585#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in) FR_DBUFF_RETURN(fr_dbuff_in, _dbuff_or_marker, _in)
1586
1587/** Internal function - do not call directly
1588 * @private
1589 */
1590static inline ssize_t _fr_dbuff_in_uint64v(uint8_t **pos_p, fr_dbuff_t *dbuff, uint64_t num)
1591{
1592 size_t ret;
1593 uint8_t swapped[sizeof(uint64_t)];
1594
1595 ret = ROUND_UP_DIV((size_t)fr_high_bit_pos(num | 0x08), 8);
1596#ifdef __COVERITY__
1597 if (ret > sizeof(uint64_t)) return -1;
1598#endif
1599 fr_nbo_from_uint64(swapped, num);
1600
1601 return _fr_dbuff_in_memcpy(pos_p, dbuff, (swapped + (sizeof(uint64_t) - ret)), ret);
1602}
1603
1604/** Copy an integer value into a dbuff or marker using our internal variable length encoding
1605 *
1606 * @param[out] _dbuff_or_marker to copy integer value to.
1607 * @param[in] _num to copy.
1608 * @return
1609 * - <0 the number of bytes we would have needed to encode the integer value.
1610 * - >0 the number of bytes used to represent the integer value.
1611 */
1612#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num) \
1613 _fr_dbuff_in_uint64v(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _num)
1614
1615/** Copy an integer value into a dbuff or marker using our internal variable length encoding returning if there is insufficient space
1616 *
1617 * @copydetails fr_dbuff_in_uint64v
1618 */
1619#define FR_DBUFF_IN_UINT64V(_dbuff_or_marker, _num) FR_DBUFF_RETURN(fr_dbuff_in_uint64v, _dbuff_or_marker, _num)
1620/** @} */
1621
1622/** @name "move" functions (copy data between dbuffs and markers)
1623 * @{
1624 */
1625/** Internal function - do not call directly
1626 * @private
1627 */
1628size_t _fr_dbuff_move_dbuff_to_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t len);
1629
1630/** Internal function - do not call directly
1631 * @private
1632 */
1633size_t _fr_dbuff_move_dbuff_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, size_t len);
1634
1635/** Internal function - do not call directly
1636 * @private
1637 */
1638size_t _fr_dbuff_move_dbuff_marker_to_dbuff(fr_dbuff_t *out, fr_dbuff_marker_t *in, size_t len);
1639
1640/** Internal function - do not call directly
1641 * @private
1642 */
1643size_t _fr_dbuff_move_dbuff_marker_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_marker_t *in, size_t len);
1644
1645/** Copy in as many bytes as possible from one dbuff or marker to another
1646 *
1647 * @warning Advances both _in and _out by _len, this may not be what you want.
1648 * If you only want _out to be advanced use fr_dbuff_in_memcpy(_out, _in, _len).
1649 * If you only want _in to be advanced use fr_dbuff_out_memcpy(_out, _in, _len).
1650 *
1651 * @param[in] _out to copy into.
1652 * @param[in] _in to copy from.
1653 * @param[in] _len The maximum length to copy.
1654 * @return Number of bytes to copy.
1655 */
1656#define fr_dbuff_move(_out, _in, _len) \
1657 _Generic((_out), \
1658 fr_dbuff_t * : \
1659 _Generic((_in), \
1660 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff((fr_dbuff_t *)_out, \
1661 (fr_dbuff_t *)_in, \
1662 _len), \
1663 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff((fr_dbuff_t *)_out, \
1664 (fr_dbuff_marker_t *)_in, \
1665 _len) \
1666 ), \
1667 fr_dbuff_marker_t * : \
1668 _Generic((_in), \
1669 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1670 (fr_dbuff_t *)_in, \
1671 _len), \
1672 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1673 (fr_dbuff_marker_t *)_in, \
1674 _len) \
1675 ) \
1676 )
1677/** @} */
1678
1679/** @name "out" functions (copy data out of a dbuff)
1680 * @{
1681 */
1682
1683/** Internal function - do not call directly
1684 *
1685 * @private
1686 */
1687static inline ssize_t _fr_dbuff_out_memcpy(uint8_t *out, uint8_t **pos_p, fr_dbuff_t *in, size_t outlen)
1688{
1689 size_t ext_len, to_copy, remaining;
1690
1691 for (remaining = outlen; remaining > 0; remaining -= to_copy) {
1692 to_copy = remaining;
1693 ext_len = _fr_dbuff_extend_lowat(NULL, in, fr_dbuff_end(in) - (*pos_p), 1);
1694 if (ext_len == 0) return -remaining;
1695 if (ext_len < to_copy) to_copy = ext_len;
1696 out += _fr_dbuff_set(pos_p, in,
1697 (*pos_p) + _fr_dbuff_safecpy(out, out + to_copy, (*pos_p), (*pos_p) + to_copy));
1698 }
1699
1700 return outlen;
1701}
1702/** Internal function - do not call directly
1703 *
1704 * @private
1705 */
1706static inline ssize_t _fr_dbuff_out_memcpy_dbuff(uint8_t **out_p, fr_dbuff_t *out, uint8_t **pos_p, fr_dbuff_t *in, size_t outlen)
1707{
1708 if (outlen == SIZE_MAX) outlen = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*out_p), outlen);
1709
1710 return _fr_dbuff_out_memcpy((*out_p), pos_p, in, outlen);
1711}
1712
1713/** Copy exactly _outlen bytes from the dbuff
1714 *
1715 * If _out is a dbuff and _outlen is greater than the number of bytes
1716 * available in that dbuff, the copy operation will fail.
1717 *
1718 * @note _out will not be advanced. If this is required #fr_dbuff_move should be used.
1719 *
1720 * @param[in] _out either a buffer, or another dbuff/marker to copy data to.
1721 * @param[in] _dbuff_or_marker to copy data from.
1722 * @param[in] _outlen How much data we need to copy.
1723 * If _out is `fr_dbuff_t *` and SIZE_MAX
1724 * is passed, then _inlen will be substituted
1725 * for the length of the buffer.
1726 * @return
1727 * - 0 no data copied.
1728 * - >0 the number of bytes copied.
1729 * - <0 the number of bytes we would have needed
1730 * to complete the copy operation.
1731 */
1732#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen) \
1733 _Generic((_out), \
1734 uint8_t * : _fr_dbuff_out_memcpy((uint8_t *)(_out), \
1735 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1736 fr_dbuff_ptr(_dbuff_or_marker), \
1737 _outlen), \
1738 fr_dbuff_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_t *)_out), \
1739 fr_dbuff_ptr((fr_dbuff_t *)(_out)), \
1740 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1741 fr_dbuff_ptr(_dbuff_or_marker), _outlen), \
1742 fr_dbuff_marker_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_marker_t *)_out), \
1743 fr_dbuff_ptr((fr_dbuff_marker_t *)(_out)), \
1744 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1745 fr_dbuff_ptr(_dbuff_or_marker), _outlen) \
1746 )
1747
1748/** Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff
1749 *
1750 * @copydetails fr_dbuff_out_memcpy
1751 */
1752#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen) FR_DBUFF_RETURN(fr_dbuff_out_memcpy, _out, _dbuff_or_marker, _outlen)
1753
1754/** @cond */
1755/** Define integer encoding functions
1756 * @private
1757 */
1758#define FR_DBUFF_OUT_DEF(_type) \
1759static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1760{ \
1761 fr_assert(out); \
1762 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1763 *out = fr_nbo_to_##_type((*pos_p)); \
1764 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1765}
1766
1767FR_DBUFF_OUT_DEF(uint16)
1768FR_DBUFF_OUT_DEF(uint32)
1769FR_DBUFF_OUT_DEF(uint64)
1770FR_DBUFF_OUT_DEF(int16)
1771FR_DBUFF_OUT_DEF(int32)
1772FR_DBUFF_OUT_DEF(int64)
1773
1774#define FR_DBUFF_OUT_DEF_NO_SWAP(_type) \
1775static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1776{ \
1777 fr_assert(out); \
1778 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1779 *out = **pos_p; \
1780 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1781}
1782
1783FR_DBUFF_OUT_DEF_NO_SWAP(uint8)
1784FR_DBUFF_OUT_DEF_NO_SWAP(int8)
1785/** @endcond */
1786
1787/** Copy data from a dbuff or marker to a fixed sized C type
1788 *
1789 * @param[out] _out Where to write the data. If out is an integer type
1790 * a byteswap will be performed if native endianness
1791 * is not big endian.
1792 * @param[in] _dbuff_or_marker to copy data from. Will be advanced by the number
1793 * of bytes consumed, i.e. if out is a uin16_t *,
1794 * _dbuff_or_marker will be advanced by two bytes.
1795 * @return
1796 * - <0 the number of bytes we would have needed to complete the conversion.
1797 * - >0 the number of bytes _in was advanced by.
1798 */
1799#define fr_dbuff_out(_out, _dbuff_or_marker) \
1800 _Generic((_out), \
1801 uint8_t * : _fr_dbuff_out_uint8((uint8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1802 uint16_t * : _fr_dbuff_out_uint16((uint16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1803 uint32_t * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1804 uint64_t * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1805 int8_t * : _fr_dbuff_out_int8((int8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1806 int16_t * : _fr_dbuff_out_int16((int16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1807 int32_t * : _fr_dbuff_out_int32((int32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1808 int64_t * : _fr_dbuff_out_int64((int64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1809 float * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1810 double * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)) \
1811 )
1812
1813/** Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data
1814 *
1815 * @copydetails fr_dbuff_out
1816 */
1817#ifndef STATIC_ANALYZER
1818#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker)
1819#else
1820#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) do { *_out = 0; FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker); } while (0)
1821#endif
1822
1823/** Internal function - do not call directly
1824 * @private
1825 */
1826static inline ssize_t _fr_dbuff_out_uint64v(uint64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1827{
1828 ssize_t slen;
1829
1830 fr_assert(length > 0 && length <= sizeof(uint64_t));
1831
1832 *num = 0;
1833 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1834 if (slen <= 0) return slen;
1835
1836 *num = fr_nbo_to_uint64((uint8_t const *)num);
1837 return length;
1838}
1839
1840/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1841 * @param[in] _num points to a uint64_t to store the integer in
1842 * @param[in] _dbuff_or_marker data to copy bytes from
1843 * @param[in] _len number of bytes to read (must be positive and less than eight)
1844 *
1845 * @return
1846 * - 0 no data read.
1847 * - >0 the number of bytes read.
1848 * - <0 the number of bytes we would have needed
1849 * to complete the read operation.
1850 */
1851#define fr_dbuff_out_uint64v(_num, _dbuff_or_marker, _len) \
1852 _fr_dbuff_out_uint64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1853
1854/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1855 *
1856 * @copydetails fr_dbuff_out_uint64v
1857 */
1858#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_uint64v, _num, _dbuff_or_marker, _len)
1859
1860/** Internal function - do not call directly
1861 * @private
1862 */
1863static inline ssize_t _fr_dbuff_out_int64v(int64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1864{
1865 ssize_t slen;
1866 uint8_t msb = **pos_p;
1867
1868 fr_assert(length > 0 && length <= sizeof(uint64_t));
1869
1870 *num = 0;
1871 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1872 if (slen <= 0) return slen;
1873
1874 if (msb & 0x80) memset(((uint8_t *)num), 0xff, sizeof(*num) - length);
1875 *num = fr_nbo_to_int64((uint8_t const *)num);
1876
1877 return length;
1878}
1879
1880/** Read bytes from a dbuff or marker and interpret them as a network order signed integer
1881 * @param[in] _num points to an int64_t to store the integer in
1882 * @param[in] _dbuff_or_marker data to copy bytes from
1883 * @param[in] _len number of bytes to read (must be positive and less than eight)
1884 *
1885 * @return
1886 * - 0 no data read.
1887 * - >0 the number of bytes read.
1888 * - <0 the number of bytes we would have needed
1889 * to complete the read operation.
1890 */
1891#define fr_dbuff_out_int64v(_num, _dbuff_or_marker, _len) \
1892 _fr_dbuff_out_int64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1893
1894/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1895 *
1896 * @copydetails fr_dbuff_out_int64v
1897 */
1898#define FR_DBUFF_OUT_INT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_int64v, _num, _dbuff_or_marker, _len)
1899
1900/** @} */
1901
1902#ifdef __cplusplus
1903}
1904#endif
static bool init
Definition fuzzer.c:41
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define DIAG_ON(_x)
Definition build.h:458
#define RCSIDH(h, id)
Definition build.h:484
#define unlikely(_x)
Definition build.h:381
#define DIAG_OFF(_x)
Definition build.h:457
struct fr_dbuff_s fr_dbuff_t
A dbuff.
Definition dbuff.h:65
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
Definition dbuff.h:786
#define FR_DBUFF_FLAG_EXTENDED
Flag indicating that during the last extend call the dbuff was extended.
Definition dbuff.h:586
fr_dbuff_uctx_talloc_t tctx
Thread local tctx.
Definition dbuff.h:542
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
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:453
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:485
static int _dbuff_thread_local_free(void *dbtl)
Definition dbuff.h:545
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:1231
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
Definition dbuff.h:590
@ FR_DBUFF_NOT_EXTENDABLE
dbuff cannot be extended
Definition dbuff.h:593
@ FR_DBUFF_EXTENDED
dbuff was extended in the last extend call but cannot be extended again
Definition dbuff.h:605
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
Definition dbuff.h:597
@ FR_DBUFF_EXTENDABLE_EXTENDED
dbuff was extended in the last extend call and may be extended again
Definition dbuff.h:601
size_t _fr_dbuff_extend_talloc(fr_dbuff_t *dbuff, size_t extension)
Reallocate the current buffer.
Definition dbuff.c:235
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
Definition dbuff.h:938
#define FR_DBUFF_ADV_PARENT_CURRENT
Advance current position of parent.
Definition dbuff.h:124
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
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:1192
#define FR_DBUFF_FLAG_EXTENDABLE
Flag indicating a dbuff is extendable.
Definition dbuff.h:582
size_t _fr_dbuff_extend_fd(fr_dbuff_t *dbuff, size_t extension)
Refresh the buffer with more data from the file.
Definition dbuff.c:175
fr_dbuff_t dbuff
Thread local dbuff.
Definition dbuff.h:541
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
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
Definition dbuff.h:1210
#define fr_dbuff_is_extendable(_status)
Check if a dbuff can be extended again.
Definition dbuff.h:610
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
Definition dbuff.h:796
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:1250
#define FR_DBUFF_ADV_PARENT_END
Advance end pointer of parent.
Definition dbuff.h:126
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:411
size_t(* fr_dbuff_extend_t)(fr_dbuff_t *dbuff, size_t req_extension)
dbuff extension callback
Definition dbuff.h:108
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
Structure to encapsulate a thread local dbuff information.
Definition dbuff.h:540
static fr_slen_t in
Definition dict.h:824
talloc_free(reap)
#define ROUND_UP_DIV(_x, _y)
Get the ceiling value of integer division.
Definition math.h:153
static uint8_t fr_high_bit_pos(uint64_t num)
Find the highest order high bit in an unsigned 64 bit integer.
Definition math.h:36
uint8_t * p
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
static uint64_t fr_nbo_to_uint64(uint8_t const data[static sizeof(uint64_t)])
Read an unsigned 64bit integer from wire format (big endian)
Definition nbo.h:177
static void fr_nbo_from_uint64(uint8_t out[static sizeof(uint64_t)], uint64_t num)
Write out an unsigned 64bit integer in wire format (big endian)
Definition nbo.h:72
#define fr_nbo_to_int64(_x)
Definition nbo.h:187
#define fr_assert(_expr)
Definition rad_assert.h:38
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
static fr_slen_t parent
Definition pair.h:851
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static size_t char fr_sbuff_t size_t inlen
Definition value.h:997
int nonnull(2, 5))
static size_t char ** out
Definition value.h:997