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