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