Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: buffer.h,v 1.10 2025/01/26 16:25:40 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 /*****
     19 ***** Module Info
     20 *****/
     21 
     22 /*! \file isc/buffer.h
     23  *
     24  * \brief A buffer is a region of memory, together with a set of related
     25  * subregions. Buffers are used for parsing and I/O operations.
     26  *
     27  * The 'used region' and the 'available region' are disjoint, and their
     28  * union is the buffer's region.  The used region extends from the beginning
     29  * of the buffer region to the last used byte.  The available region
     30  * extends from one byte greater than the last used byte to the end of the
     31  * buffer's region.  The size of the used region can be changed using various
     32  * buffer commands.  Initially, the used region is empty.
     33  *
     34  * The used region is further subdivided into two disjoint regions: the
     35  * 'consumed region' and the 'remaining region'.  The union of these two
     36  * regions is the used region.  The consumed region extends from the beginning
     37  * of the used region to the byte before the 'current' offset (if any).  The
     38  * 'remaining' region extends from the current offset to the end of the used
     39  * region.  The size of the consumed region can be changed using various
     40  * buffer commands.  Initially, the consumed region is empty.
     41  *
     42  * The 'active region' is an (optional) subregion of the remaining region.
     43  * It extends from the current offset to an offset in the remaining region
     44  * that is selected with isc_buffer_setactive().  Initially, the active region
     45  * is empty.  If the current offset advances beyond the chosen offset, the
     46  * active region will also be empty.
     47  *
     48  * \verbatim
     49  *  /------------entire length---------------\
     50  *  /----- used region -----\/-- available --\
     51  *  +----------------------------------------+
     52  *  | consumed  | remaining |                |
     53  *  +----------------------------------------+
     54  *  a           b     c     d                e
     55  *
     56  * a == base of buffer.
     57  * b == current pointer.  Can be anywhere between a and d.
     58  * c == active pointer.  Meaningful between b and d.
     59  * d == used pointer.
     60  * e == length of buffer.
     61  *
     62  * a-e == entire length of buffer.
     63  * a-d == used region.
     64  * a-b == consumed region.
     65  * b-d == remaining region.
     66  * b-c == optional active region.
     67  *\endverbatim
     68  *
     69  * The following invariants are maintained by all routines:
     70  *
     71  *\code
     72  *	length > 0
     73  *
     74  *	base is a valid pointer to length bytes of memory
     75  *
     76  *	0 <= used <= length
     77  *
     78  *	0 <= current <= used
     79  *
     80  *	0 <= active <= used
     81  *	(although active < current implies empty active region)
     82  *\endcode
     83  *
     84  * \li MP:
     85  *	Buffers have no synchronization.  Clients must ensure exclusive
     86  *	access.
     87  *
     88  * \li Reliability:
     89  *	No anticipated impact.
     90  *
     91  * \li Resources:
     92  *	Memory: 1 pointer + 6 unsigned integers per buffer.
     93  *
     94  * \li Security:
     95  *	No anticipated impact.
     96  *
     97  * \li Standards:
     98  *	None.
     99  */
    100 
    101 /***
    102  *** Imports
    103  ***/
    104 
    105 #include <inttypes.h>
    106 #include <stdbool.h>
    107 
    108 #include <isc/assertions.h>
    109 #include <isc/endian.h>
    110 #include <isc/formatcheck.h>
    111 #include <isc/lang.h>
    112 #include <isc/list.h>
    113 #include <isc/magic.h>
    114 #include <isc/mem.h>
    115 #include <isc/region.h>
    116 #include <isc/string.h>
    117 #include <isc/types.h>
    118 #include <isc/util.h>
    119 
    120 ISC_LANG_BEGINDECLS
    121 
    122 /*@{*/
    123 /*!
    124  *** Magic numbers
    125  ***/
    126 #define ISC_BUFFER_MAGIC    0x42756621U /* Buf!. */
    127 #define ISC_BUFFER_VALID(b) ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
    128 /*@}*/
    129 
    130 /*!
    131  * Size granularity for dynamically resizable buffers; when reserving
    132  * space in a buffer, we round the allocated buffer length up to the
    133  * nearest * multiple of this value.
    134  */
    135 #define ISC_BUFFER_INCR 512
    136 
    137 /*
    138  * The following macros MUST be used only on valid buffers.  It is the
    139  * caller's responsibility to ensure this by using the ISC_BUFFER_VALID
    140  * check above, or by calling another isc_buffer_*() function (rather than
    141  * another macro.)
    142  */
    143 
    144 /*@{*/
    145 /*!
    146  * Fundamental buffer elements.  (A through E in the introductory comment.)
    147  */
    148 #define isc_buffer_base(b) ((void *)(b)->base) /*a*/
    149 #define isc_buffer_current(b) \
    150 	((void *)((unsigned char *)(b)->base + (b)->current)) /*b*/
    151 #define isc_buffer_active(b) \
    152 	((void *)((unsigned char *)(b)->base + (b)->active)) /*c*/
    153 #define isc_buffer_used(b) \
    154 	((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/
    155 #define isc_buffer_length(b) ((b)->length)		   /*e*/
    156 /*@}*/
    157 
    158 /*@{*/
    159 /*!
    160  * Derived lengths.  (Described in the introductory comment.)
    161  */
    162 #define isc_buffer_usedlength(b)      ((b)->used)		   /* d-a */
    163 #define isc_buffer_consumedlength(b)  ((b)->current)		   /* b-a */
    164 #define isc_buffer_remaininglength(b) ((b)->used - (b)->current)   /* d-b */
    165 #define isc_buffer_activelength(b)    ((b)->active - (b)->current) /* c-b */
    166 #define isc_buffer_availablelength(b) ((b)->length - (b)->used)	   /* e-d */
    167 /*@}*/
    168 
    169 /*!
    170  * Note that the buffer structure is public.  This is principally so buffer
    171  * operations can be implemented using macros.  Applications are strongly
    172  * discouraged from directly manipulating the structure.
    173  */
    174 
    175 struct isc_buffer {
    176 	unsigned int magic;
    177 	void	    *base;
    178 	/*@{*/
    179 	/*! The following integers are byte offsets from 'base'. */
    180 	unsigned int length;
    181 	unsigned int used;
    182 	unsigned int current;
    183 	unsigned int active;
    184 	/*@}*/
    185 	/*! The extra bytes allocated for static buffer */
    186 	unsigned int extra;
    187 	bool	     dynamic;
    188 	/*! linkable */
    189 	ISC_LINK(isc_buffer_t) link;
    190 	/*! private internal elements */
    191 	isc_mem_t *mctx;
    192 };
    193 
    194 /***
    195  *** Functions
    196  ***/
    197 
    198 static inline void
    199 isc_buffer_allocate(isc_mem_t	      *mctx, isc_buffer_t **restrict dynbuffer,
    200 		    const unsigned int length);
    201 /*!<
    202  * \brief Allocate a dynamic linkable buffer which has "length" bytes in the
    203  * data region.
    204  *
    205  * Requires:
    206  *\li	"mctx" is valid.
    207  *
    208  *\li	"dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
    209  *
    210  * Note:
    211  *\li	Changing the buffer's length field is not permitted.
    212  */
    213 
    214 static inline void
    215 isc_buffer_setmctx(isc_buffer_t *restrict b, isc_mem_t *mctx);
    216 static inline void
    217 isc_buffer_clearmctx(isc_buffer_t *restrict b);
    218 /*!<
    219  * \brief Sets/Clears the internal memory context, so isc_buffer_reserve() can
    220  * be used on previously 'static' buffer.
    221  */
    222 
    223 static inline isc_result_t
    224 isc_buffer_reserve(isc_buffer_t *restrict dynbuffer, const unsigned int size);
    225 /*!<
    226  * \brief Make "size" bytes of space available in the buffer. The buffer
    227  * pointer may move when you call this function.
    228  *
    229  * Requires:
    230  *\li	"dynbuffer" is a valid dynamic buffer.
    231  *
    232  * Returns:
    233  *\li	ISC_R_SUCCESS		- success
    234  *\li	ISC_R_NOMEMORY		- no memory available
    235  */
    236 
    237 static inline void
    238 isc_buffer_free(isc_buffer_t **restrict dynbuffer);
    239 /*!<
    240  * \brief Release resources allocated for a dynamic buffer.
    241  *
    242  * Requires:
    243  *\li	"dynbuffer" is not NULL.
    244  *
    245  *\li	"*dynbuffer" is a valid dynamic buffer.
    246  *
    247  * Ensures:
    248  *\li	"*dynbuffer" will be NULL on return, and all memory associated with
    249  *	the dynamic buffer is returned to the memory context used in
    250  *	isc_buffer_allocate().
    251  */
    252 
    253 static inline void
    254 isc_buffer_initnull(isc_buffer_t *restrict b);
    255 
    256 static inline void
    257 isc_buffer_reinit(isc_buffer_t *restrict b, void *base,
    258 		  const unsigned int length);
    259 /*!<
    260  * \brief Make 'b' refer to the 'length'-byte region starting at base.
    261  * Any existing data will be copied.
    262  *
    263  * Requires:
    264  *
    265  *\li	'length' > 0 AND length >= previous length
    266  *
    267  *\li	'base' is a pointer to a sequence of 'length' bytes.
    268  *
    269  */
    270 
    271 static inline void
    272 isc_buffer_trycompact(isc_buffer_t *restrict b);
    273 static inline void
    274 isc_buffer_compact(isc_buffer_t *restrict b);
    275 /*!<
    276  * \brief Compact the used region by moving the remaining region so it occurs
    277  * at the start of the buffer.  The used region is shrunk by the size of
    278  * the consumed region, and the consumed region is then made empty.
    279  *
    280  * Requires:
    281  *
    282  *\li	'b' is a valid buffer
    283  *
    284  * Ensures:
    285  *
    286  *\li	current == 0
    287  *
    288  *\li	The size of the used region is now equal to the size of the remaining
    289  *	region (as it was before the call).  The contents of the used region
    290  *	are those of the remaining region (as it was before the call).
    291  */
    292 
    293 static inline isc_result_t
    294 isc_buffer_peekuint8(const isc_buffer_t *restrict b, uint8_t *valp);
    295 static inline uint8_t
    296 isc_buffer_getuint8(isc_buffer_t *restrict b);
    297 static inline void
    298 isc_buffer_putuint8(isc_buffer_t *restrict b, const uint8_t val);
    299 /*!<
    300  * \brief Peek/Read/Write an unsigned 8-bit integer from/to 'b'.
    301  *
    302  * Requires:
    303  *
    304  *\li	'b' is a valid buffer.
    305  *
    306  *\li	The length of the available region of 'b' is at least 1
    307  *	or the buffer has autoreallocation enabled.
    308  *
    309  * Ensures (for Read):
    310  *
    311  *\li	The current pointer in 'b' is advanced by 1.
    312  *
    313  * Ensures (for Write):
    314  *
    315  *\li	The used pointer in 'b' is advanced by 1.
    316  *
    317  * Returns (for Peek and Read):
    318  *
    319  *\li	A 8-bit unsigned integer. (peek and get)
    320  */
    321 
    322 static inline isc_result_t
    323 isc_buffer_peekuint16(const isc_buffer_t *restrict b, uint16_t *valp);
    324 static inline uint16_t
    325 isc_buffer_getuint16(isc_buffer_t *restrict b);
    326 static inline void
    327 isc_buffer_putuint16(isc_buffer_t *restrict b, const uint16_t val);
    328 /*!<
    329  * \brief Peek/Read/Write an unsigned 16-bit integer in network byte order
    330  * from/to 'b', convert it to/from host byte order..
    331  *
    332  * Requires:
    333  *
    334  *\li	'b' is a valid buffer.
    335  *
    336  *\li	The length of the available region of 'b' is at least 2
    337  *	or the buffer has autoreallocation enabled.
    338  *
    339  * Ensures (for Read):
    340  *
    341  *\li	The current pointer in 'b' is advanced by 2.
    342  *
    343  * Ensures (for Write):
    344  *
    345  *\li	The used pointer in 'b' is advanced by 2.
    346  *
    347  * Returns (for Peek and Read):
    348  *
    349  *\li	A 16-bit unsigned integer.
    350  */
    351 
    352 static inline isc_result_t
    353 isc_buffer_peekuint32(const isc_buffer_t *restrict b, uint32_t *restrict valp);
    354 static inline uint32_t
    355 isc_buffer_getuint32(isc_buffer_t *restrict b);
    356 static inline void
    357 isc_buffer_putuint32(isc_buffer_t *restrict b, uint32_t const val);
    358 /*!<
    359  * \brief Peek/Read/Write an unsigned 32-bit integer in network byte order
    360  * from/to 'b', convert it to/from host byte order.
    361  *
    362  * Requires:
    363  *
    364  *\li	'b' is a valid buffer.
    365  *
    366  *\li	The length of the available region of 'b' is at least 4
    367  *	or the buffer has autoreallocation enabled.
    368  *
    369  * Ensures (for Read):
    370  *
    371  *\li	The current pointer in 'b' is advanced by 4.
    372  *
    373  * Ensures (for Write):
    374  *
    375  *\li	The used pointer in 'b' is advanced by 4.
    376  *
    377  * Returns (for Peek and Read):
    378  *
    379  *\li	A 32-bit unsigned integer.
    380  */
    381 
    382 static inline isc_result_t
    383 isc_buffer_peekuint48(const isc_buffer_t *restrict b, uint64_t *valp);
    384 static inline uint64_t
    385 isc_buffer_getuint48(isc_buffer_t *restrict b);
    386 static inline void
    387 isc_buffer_putuint48(isc_buffer_t *restrict b, const uint64_t val);
    388 /*!<
    389  * \brief Peek/Read/Write an unsigned 48-bit integer in network byte order
    390  * from/to 'b', convert it to/from host byte order.
    391  *
    392  * Requires:
    393  *
    394  *\li	'b' is a valid buffer.
    395  *
    396  *\li	The length of the available region of 'b' is at least 6
    397  *	or the buffer has autoreallocation enabled.
    398  *
    399  * Ensures (for Read):
    400  *
    401  *\li	The current pointer in 'b' is advanced by 6.
    402  *
    403  * Ensures (for Write):
    404  *
    405  *\li	The used pointer in 'b' is advanced by 6.
    406  *
    407  * Returns (for Peek and Read):
    408  *
    409  *\li	A 48-bit unsigned integer (stored in a 64-bit integer).
    410  */
    411 
    412 static inline void
    413 isc_buffer_putmem(isc_buffer_t *restrict b, const unsigned char *restrict base,
    414 		  const unsigned int length);
    415 /*!<
    416  * \brief Copy 'length' bytes of memory at 'base' into 'b'.
    417  *
    418  * Requires:
    419  *\li	'b' is a valid buffer.
    420  *
    421  *\li	'base' points to 'length' bytes of valid memory.
    422  *
    423  *\li	The length of the available region of 'b' is at least 'length'
    424  *	or the buffer has autoreallocation enabled.
    425  *
    426  * Ensures:
    427  *\li	The used pointer in 'b' is advanced by 'length'.
    428  */
    429 
    430 static inline isc_result_t
    431 isc_buffer_copyregion(isc_buffer_t *restrict b, const isc_region_t *restrict r);
    432 /*!<
    433  * \brief Copy the contents of 'r' into 'b'.
    434  *
    435  * Notes:
    436  *\li	If 'b' has autoreallocation enabled, and the length of 'r' is greater
    437  *	than the length of the available region of 'b', 'b' is reallocated.
    438  *
    439  * Requires:
    440  *\li	'b' is a valid buffer.
    441  *
    442  *\li	'r' is a valid region.
    443  *
    444  * Returns:
    445  *\li	ISC_R_SUCCESS
    446  *\li	ISC_R_NOSPACE			The available region of 'b' is not
    447  *					big enough.
    448  */
    449 
    450 static inline isc_result_t
    451 isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **restrict dstp,
    452 	       const isc_buffer_t *restrict src);
    453 /*!<
    454  * \brief Allocate 'dst' and copy used contents of 'src' into it.
    455  *
    456  * Requires:
    457  *\li	'dstp' is not NULL and *dst is NULL.
    458  *\li	'src' is a valid buffer.
    459  *
    460  * Returns:
    461  *\li	ISC_R_SUCCESS
    462  */
    463 
    464 static inline isc_result_t
    465 isc_buffer_printf(isc_buffer_t *restrict b, const char *restrict format, ...)
    466 	ISC_FORMAT_PRINTF(2, 3);
    467 /*!<
    468  * \brief Append a formatted string to the used region of 'b'.
    469  *
    470  * Notes:
    471  *
    472  *\li	The 'format' argument is a printf(3) string, with additional arguments
    473  *	as necessary.
    474  *
    475  *\li	If 'b' has autoreallocation enabled, and the length of the formatted
    476  *	string is greater than the length of the available region of 'b', 'b'
    477  *	is reallocated.
    478  *
    479  * Requires:
    480  *
    481  *\li	'b' is a valid buffer.
    482  *
    483  * Ensures:
    484  *
    485  *\li	The used pointer in 'b' is advanced by the number of bytes appended
    486  *	(excluding the terminating NULL byte).
    487  *
    488  * Returns:
    489  *
    490  *\li	#ISC_R_SUCCESS	Operation succeeded.
    491  *\li	#ISC_R_NOSPACE	'b' does not allow reallocation and appending the
    492  *			formatted string to it would cause it to overflow.
    493  *\li	#ISC_R_NOMEMORY	Reallocation failed.
    494  *\li	#ISC_R_FAILURE	Other error occurred.
    495  */
    496 
    497 /*
    498  * Buffer functions implemented as inline.
    499  */
    500 
    501 /*! \note
    502  * XXXDCL Something more could be done with initializing buffers that
    503  * point to const data.  For example, isc_buffer_constinit() could
    504  * set a new boolean flag in the buffer structure indicating whether
    505  * the buffer was initialized with that function.  Then if the
    506  * boolean were true, the isc_buffer_put* functions could assert a
    507  * contractual requirement for a non-const buffer.
    508  *
    509  * One drawback is that the isc_buffer_* functions that return
    510  * pointers would still need to return non-const pointers to avoid compiler
    511  * warnings, so it would be up to code that uses them to have to deal
    512  * with the possibility that the buffer was initialized as const --
    513  * a problem that they *already* have to deal with but have absolutely
    514  * no ability to.  With a new isc_buffer_isconst() function returning
    515  * true/false, they could at least assert a contractual requirement for
    516  * non-const buffers when needed.
    517  */
    518 
    519 /*!
    520  * \brief Make 'b' refer to the 'length'-byte region starting at 'base'.
    521  *
    522  * Requires:
    523  *
    524  *\li	'length' > 0
    525  *
    526  *\li	'base' is a pointer to a sequence of 'length' bytes.
    527  */
    528 static inline void
    529 isc_buffer_init(isc_buffer_t *restrict b, void *base,
    530 		const unsigned int length) {
    531 	REQUIRE(b != NULL);
    532 
    533 	*b = (isc_buffer_t){
    534 		.base = base,
    535 		.length = length,
    536 		.link = ISC_LINK_INITIALIZER,
    537 		.magic = ISC_BUFFER_MAGIC,
    538 	};
    539 }
    540 
    541 /*!
    542  *\brief Initialize a buffer 'b' with a null data field and zero length.
    543  * This can later be grown as needed and swapped in place.
    544  */
    545 static inline void
    546 isc_buffer_initnull(isc_buffer_t *restrict b) {
    547 	*b = (isc_buffer_t){
    548 		.link = ISC_LINK_INITIALIZER,
    549 		.magic = ISC_BUFFER_MAGIC,
    550 	};
    551 }
    552 
    553 /*!
    554  * \brief Make 'b' refer to the 'length'-byte constant region starting
    555  * at 'base'.
    556  *
    557  * Requires:
    558  *
    559  *\li	'length' > 0
    560  *\li	'base' is a pointer to a sequence of 'length' bytes.
    561  */
    562 #define isc_buffer_constinit(_b, _d, _l)                    \
    563 	do {                                                \
    564 		union {                                     \
    565 			void	   *_var;                   \
    566 			const void *_const;                 \
    567 		} _deconst;                                 \
    568 		_deconst._const = (_d);                     \
    569 		isc_buffer_init((_b), _deconst._var, (_l)); \
    570 	} while (0)
    571 
    572 /*!
    573  * \brief Make 'b' an invalid buffer.
    574  *
    575  * Requires:
    576  *\li	'b' is a valid buffer.
    577  *
    578  * Ensures:
    579  *\li	Future attempts to use 'b' without calling isc_buffer_init() on
    580  *	it will cause an assertion failure.
    581  */
    582 static inline void
    583 isc_buffer_invalidate(isc_buffer_t *restrict b) {
    584 	REQUIRE(ISC_BUFFER_VALID(b));
    585 	REQUIRE(!ISC_LINK_LINKED(b, link));
    586 	REQUIRE(b->mctx == NULL);
    587 
    588 	*b = (isc_buffer_t){
    589 		.magic = 0,
    590 	};
    591 }
    592 
    593 /*!
    594  * \brief Make 'r' refer to the region of 'b'.
    595  *
    596  * Requires:
    597  *
    598  *\li	'b' is a valid buffer.
    599  *
    600  *\li	'r' points to a region structure.
    601  */
    602 static inline void
    603 isc_buffer_region(isc_buffer_t *restrict b, isc_region_t *restrict r) {
    604 	REQUIRE(ISC_BUFFER_VALID(b));
    605 	REQUIRE(r != NULL);
    606 
    607 	r->base = b->base;
    608 	r->length = b->length;
    609 }
    610 
    611 /*!
    612  * \brief Make 'r' refer to the used region of 'b'.
    613  *
    614  * Requires:
    615  *
    616  *\li	'b' is a valid buffer.
    617  *
    618  *\li	'r' points to a region structure.
    619  */
    620 static inline void
    621 isc_buffer_usedregion(const isc_buffer_t *restrict b,
    622 		      isc_region_t *restrict r) {
    623 	REQUIRE(ISC_BUFFER_VALID(b));
    624 	REQUIRE(r != NULL);
    625 
    626 	r->base = b->base;
    627 	r->length = b->used;
    628 }
    629 
    630 /*!
    631  * \brief Make 'r' refer to the available region of 'b'.
    632  *
    633  * Requires:
    634  *
    635  *\li	'b' is a valid buffer.
    636  *
    637  *\li	'r' points to a region structure.
    638  */
    639 static inline void
    640 isc_buffer_availableregion(isc_buffer_t *restrict b, isc_region_t *restrict r) {
    641 	REQUIRE(ISC_BUFFER_VALID(b));
    642 	REQUIRE(r != NULL);
    643 
    644 	r->base = isc_buffer_used(b);
    645 	r->length = isc_buffer_availablelength(b);
    646 }
    647 
    648 /*!
    649  * \brief Increase the 'used' region of 'b' by 'n' bytes.
    650  *
    651  * Requires:
    652  *
    653  *\li	'b' is a valid buffer
    654  *
    655  *\li	used + n <= length
    656  */
    657 static inline void
    658 isc_buffer_add(isc_buffer_t *restrict b, const unsigned int n) {
    659 	REQUIRE(ISC_BUFFER_VALID(b));
    660 	REQUIRE(b->used + n <= b->length);
    661 
    662 	b->used += n;
    663 }
    664 
    665 /*!
    666  * \brief Decrease the 'used' region of 'b' by 'n' bytes.
    667  *
    668  * Requires:
    669  *
    670  *\li	'b' is a valid buffer
    671  *
    672  *\li	used >= n
    673  */
    674 static inline void
    675 isc_buffer_subtract(isc_buffer_t *restrict b, const unsigned int n) {
    676 	REQUIRE(ISC_BUFFER_VALID(b));
    677 	REQUIRE(b->used >= n);
    678 
    679 	b->used -= n;
    680 	if (b->current > b->used) {
    681 		b->current = b->used;
    682 	}
    683 	if (b->active > b->used) {
    684 		b->active = b->used;
    685 	}
    686 }
    687 
    688 /*!<
    689  * \brief Make the used region empty.
    690  *
    691  * Requires:
    692  *
    693  *\li	'b' is a valid buffer
    694  *
    695  * Ensures:
    696  *
    697  *\li	used = 0
    698  */
    699 static inline void
    700 isc_buffer_clear(isc_buffer_t *restrict b) {
    701 	REQUIRE(ISC_BUFFER_VALID(b));
    702 
    703 	b->used = 0;
    704 	b->current = 0;
    705 	b->active = 0;
    706 }
    707 
    708 /*!
    709  * \brief Make 'r' refer to the consumed region of 'b'.
    710  *
    711  * Requires:
    712  *
    713  *\li	'b' is a valid buffer.
    714  *
    715  *\li	'r' points to a region structure.
    716  */
    717 static inline void
    718 isc_buffer_consumedregion(isc_buffer_t *restrict b, isc_region_t *restrict r) {
    719 	REQUIRE(ISC_BUFFER_VALID(b));
    720 	REQUIRE(r != NULL);
    721 
    722 	r->base = b->base;
    723 	r->length = b->current;
    724 }
    725 
    726 /*!
    727  * \brief Make 'r' refer to the remaining region of 'b'.
    728  *
    729  * Requires:
    730  *
    731  *\li	'b' is a valid buffer.
    732  *
    733  *\li	'r' points to a region structure.
    734  */
    735 static inline void
    736 isc_buffer_remainingregion(isc_buffer_t *restrict b, isc_region_t *restrict r) {
    737 	REQUIRE(ISC_BUFFER_VALID(b));
    738 	REQUIRE(r != NULL);
    739 
    740 	r->base = isc_buffer_current(b);
    741 	r->length = isc_buffer_remaininglength(b);
    742 }
    743 
    744 /*!
    745  * \brief Make 'r' refer to the active region of 'b'.
    746  *
    747  * Requires:
    748  *
    749  *\li	'b' is a valid buffer.
    750  *
    751  *\li	'r' points to a region structure.
    752  */
    753 static inline void
    754 isc_buffer_activeregion(isc_buffer_t *restrict b, isc_region_t *restrict r) {
    755 	REQUIRE(ISC_BUFFER_VALID(b));
    756 	REQUIRE(r != NULL);
    757 
    758 	if (b->current < b->active) {
    759 		r->base = isc_buffer_current(b);
    760 		r->length = isc_buffer_activelength(b);
    761 	} else {
    762 		r->base = NULL;
    763 		r->length = 0;
    764 	}
    765 }
    766 
    767 /*!
    768  * \brief Sets the end of the active region 'n' bytes after current.
    769  *
    770  * Requires:
    771  *
    772  *\li	'b' is a valid buffer.
    773  *
    774  *\li	current + n <= used
    775  */
    776 static inline void
    777 isc_buffer_setactive(isc_buffer_t *restrict b, const unsigned int n) {
    778 	REQUIRE(ISC_BUFFER_VALID(b));
    779 	REQUIRE(b->current + n <= b->used);
    780 
    781 	b->active = b->current + n;
    782 }
    783 
    784 /*!<
    785  * \brief Make the consumed region empty.
    786  *
    787  * Requires:
    788  *
    789  *\li	'b' is a valid buffer
    790  *
    791  * Ensures:
    792  *
    793  *\li	current == 0
    794  */
    795 static inline void
    796 isc_buffer_first(isc_buffer_t *restrict b) {
    797 	REQUIRE(ISC_BUFFER_VALID(b));
    798 
    799 	b->current = 0;
    800 }
    801 
    802 /*!
    803  * \brief Increase the 'consumed' region of 'b' by 'n' bytes.
    804  *
    805  * Requires:
    806  *
    807  *\li	'b' is a valid buffer
    808  *
    809  *\li	current + n <= used
    810  */
    811 static inline void
    812 isc_buffer_forward(isc_buffer_t *restrict b, const unsigned int n) {
    813 	REQUIRE(ISC_BUFFER_VALID(b));
    814 	REQUIRE(b->current + n <= b->used);
    815 
    816 	b->current += n;
    817 }
    818 
    819 /*!
    820  * \brief Decrease the 'consumed' region of 'b' by 'n' bytes.
    821  *
    822  * Requires:
    823  *
    824  *\li	'b' is a valid buffer
    825  *
    826  *\li	n <= current
    827  */
    828 static inline void
    829 isc_buffer_back(isc_buffer_t *restrict b, const unsigned int n) {
    830 	REQUIRE(ISC_BUFFER_VALID(b));
    831 	REQUIRE(n <= b->current);
    832 
    833 	b->current -= n;
    834 }
    835 
    836 #define ISC_BUFFER_PEEK_CHECK(b, s)                 \
    837 	{                                           \
    838 		REQUIRE(ISC_BUFFER_VALID(b));       \
    839 		if ((b)->used - (b)->current < s) { \
    840 			return (ISC_R_NOMORE);      \
    841 		}                                   \
    842 	}
    843 
    844 static inline isc_result_t
    845 isc_buffer_peekuint8(const isc_buffer_t *restrict b, uint8_t *valp) {
    846 	ISC_BUFFER_PEEK_CHECK(b, sizeof(*valp));
    847 
    848 	uint8_t *cp = isc_buffer_current(b);
    849 	SET_IF_NOT_NULL(valp, (uint8_t)(cp[0]));
    850 	return ISC_R_SUCCESS;
    851 }
    852 
    853 static inline uint8_t
    854 isc_buffer_getuint8(isc_buffer_t *restrict b) {
    855 	uint8_t	     val = 0;
    856 	isc_result_t result = isc_buffer_peekuint8(b, &val);
    857 	ENSURE(result == ISC_R_SUCCESS);
    858 	b->current += sizeof(val);
    859 	return val;
    860 }
    861 
    862 #define ISC_BUFFER_PUT_RESERVE(b, v, s)                                 \
    863 	{                                                               \
    864 		REQUIRE(ISC_BUFFER_VALID(b));                           \
    865                                                                         \
    866 		if (b->mctx) {                                          \
    867 			isc_result_t result = isc_buffer_reserve(b, s); \
    868 			ENSURE(result == ISC_R_SUCCESS);                \
    869 		}                                                       \
    870                                                                         \
    871 		REQUIRE(isc_buffer_availablelength(b) >= s);            \
    872 	}
    873 
    874 static inline void
    875 isc_buffer_putuint8(isc_buffer_t *restrict b, const uint8_t val) {
    876 	ISC_BUFFER_PUT_RESERVE(b, val, sizeof(val));
    877 
    878 	uint8_t *cp = isc_buffer_used(b);
    879 	b->used += sizeof(val);
    880 	cp[0] = val;
    881 }
    882 
    883 static inline isc_result_t
    884 isc_buffer_peekuint16(const isc_buffer_t *restrict b, uint16_t *valp) {
    885 	ISC_BUFFER_PEEK_CHECK(b, sizeof(*valp));
    886 
    887 	uint8_t *cp = isc_buffer_current(b);
    888 
    889 	SET_IF_NOT_NULL(valp, ISC_U8TO16_BE(cp));
    890 	return ISC_R_SUCCESS;
    891 }
    892 
    893 static inline uint16_t
    894 isc_buffer_getuint16(isc_buffer_t *restrict b) {
    895 	uint16_t     val = 0;
    896 	isc_result_t result = isc_buffer_peekuint16(b, &val);
    897 	ENSURE(result == ISC_R_SUCCESS);
    898 	b->current += sizeof(val);
    899 	return val;
    900 }
    901 
    902 static inline void
    903 isc_buffer_putuint16(isc_buffer_t *restrict b, const uint16_t val) {
    904 	ISC_BUFFER_PUT_RESERVE(b, val, sizeof(val));
    905 
    906 	uint8_t *cp = isc_buffer_used(b);
    907 	b->used += sizeof(val);
    908 	ISC_U16TO8_BE(cp, val);
    909 }
    910 
    911 static inline isc_result_t
    912 isc_buffer_peekuint32(const isc_buffer_t *restrict b, uint32_t *valp) {
    913 	ISC_BUFFER_PEEK_CHECK(b, sizeof(*valp));
    914 
    915 	uint8_t *cp = isc_buffer_current(b);
    916 
    917 	SET_IF_NOT_NULL(valp, ISC_U8TO32_BE(cp));
    918 	return ISC_R_SUCCESS;
    919 }
    920 
    921 uint32_t
    922 isc_buffer_getuint32(isc_buffer_t *restrict b) {
    923 	uint32_t     val = 0;
    924 	isc_result_t result = isc_buffer_peekuint32(b, &val);
    925 	ENSURE(result == ISC_R_SUCCESS);
    926 	b->current += sizeof(val);
    927 	return val;
    928 }
    929 
    930 static inline void
    931 isc_buffer_putuint32(isc_buffer_t *restrict b, const uint32_t val) {
    932 	ISC_BUFFER_PUT_RESERVE(b, val, sizeof(val));
    933 
    934 	uint8_t *cp = isc_buffer_used(b);
    935 	b->used += sizeof(val);
    936 
    937 	ISC_U32TO8_BE(cp, val);
    938 }
    939 
    940 static inline isc_result_t
    941 isc_buffer_peekuint48(const isc_buffer_t *restrict b, uint64_t *valp) {
    942 	ISC_BUFFER_PEEK_CHECK(b, 6); /* 48-bits */
    943 
    944 	uint8_t *cp = isc_buffer_current(b);
    945 
    946 	SET_IF_NOT_NULL(valp, ISC_U8TO48_BE(cp));
    947 	return ISC_R_SUCCESS;
    948 }
    949 
    950 static inline uint64_t
    951 isc_buffer_getuint48(isc_buffer_t *restrict b) {
    952 	uint64_t     val = 0;
    953 	isc_result_t result = isc_buffer_peekuint48(b, &val);
    954 	ENSURE(result == ISC_R_SUCCESS);
    955 	b->current += 6; /* 48-bits */
    956 	return val;
    957 }
    958 
    959 static inline void
    960 isc_buffer_putuint48(isc_buffer_t *restrict b, const uint64_t val) {
    961 	ISC_BUFFER_PUT_RESERVE(b, val, 6); /* 48-bits */
    962 
    963 	uint8_t *cp = isc_buffer_used(b);
    964 	b->used += 6;
    965 
    966 	ISC_U48TO8_BE(cp, val);
    967 }
    968 
    969 static inline void
    970 isc_buffer_putmem(isc_buffer_t *restrict b, const unsigned char *restrict base,
    971 		  const unsigned int length) {
    972 	REQUIRE(ISC_BUFFER_VALID(b));
    973 
    974 	if (b->mctx) {
    975 		isc_result_t result = isc_buffer_reserve(b, length);
    976 		REQUIRE(result == ISC_R_SUCCESS);
    977 	}
    978 
    979 	REQUIRE(isc_buffer_availablelength(b) >= (unsigned int)length);
    980 
    981 	if (length > 0U) {
    982 		memmove(isc_buffer_used(b), base, length);
    983 		b->used += length;
    984 	}
    985 }
    986 
    987 /*!
    988  * \brief Copy 'source' into 'b', not including terminating NUL.
    989  *
    990  * Requires:
    991  *\li	'b' is a valid buffer.
    992  *
    993  *\li	'source' is a valid NULL terminated string.
    994  *
    995  *\li	The length of the available region of 'b' is at least strlen('source')
    996  *	or the buffer has autoreallocation enabled.
    997  *
    998  * Ensures:
    999  *\li	The used pointer in 'b' is advanced by strlen('source').
   1000  */
   1001 static inline void
   1002 isc_buffer_putstr(isc_buffer_t *restrict b, const char *restrict source) {
   1003 	unsigned int   length;
   1004 	unsigned char *cp;
   1005 
   1006 	REQUIRE(ISC_BUFFER_VALID(b));
   1007 	REQUIRE(source != NULL);
   1008 
   1009 	length = (unsigned int)strlen(source);
   1010 	if (b->mctx) {
   1011 		isc_result_t result = isc_buffer_reserve(b, length);
   1012 		ENSURE(result == ISC_R_SUCCESS);
   1013 	}
   1014 
   1015 	REQUIRE(isc_buffer_availablelength(b) >= length);
   1016 
   1017 	cp = isc_buffer_used(b);
   1018 	memmove(cp, source, length);
   1019 	b->used += length;
   1020 }
   1021 
   1022 static inline void
   1023 isc_buffer_reinit(isc_buffer_t *restrict b, void *base,
   1024 		  const unsigned int length) {
   1025 	/*
   1026 	 * Re-initialize the buffer enough to reconfigure the base of the
   1027 	 * buffer.  We will swap in the new buffer, after copying any
   1028 	 * data we contain into the new buffer and adjusting all of our
   1029 	 * internal pointers.
   1030 	 *
   1031 	 * The buffer must not be smaller than the length of the original
   1032 	 * buffer.
   1033 	 */
   1034 	REQUIRE(b->length <= length);
   1035 	REQUIRE(base != NULL);
   1036 	REQUIRE(b->mctx == NULL);
   1037 
   1038 	if (b->length > 0U) {
   1039 		(void)memmove(base, b->base, b->length);
   1040 	}
   1041 
   1042 	b->base = base;
   1043 	b->length = length;
   1044 }
   1045 
   1046 static inline void
   1047 isc_buffer_trycompact(isc_buffer_t *restrict b) {
   1048 	if (isc_buffer_consumedlength(b) >= isc_buffer_remaininglength(b)) {
   1049 		isc_buffer_compact(b);
   1050 	}
   1051 }
   1052 
   1053 static inline void
   1054 isc_buffer_compact(isc_buffer_t *restrict b) {
   1055 	unsigned int length;
   1056 	void	    *src;
   1057 
   1058 	/*
   1059 	 * Compact the used region by moving the remaining region so it occurs
   1060 	 * at the start of the buffer.  The used region is shrunk by the size
   1061 	 * of the consumed region, and the consumed region is then made empty.
   1062 	 */
   1063 
   1064 	REQUIRE(ISC_BUFFER_VALID(b));
   1065 
   1066 	src = isc_buffer_current(b);
   1067 	length = isc_buffer_remaininglength(b);
   1068 	if (length > 0U) {
   1069 		(void)memmove(b->base, src, (size_t)length);
   1070 	}
   1071 
   1072 	if (b->active > b->current) {
   1073 		b->active -= b->current;
   1074 	} else {
   1075 		b->active = 0;
   1076 	}
   1077 	b->current = 0;
   1078 	b->used = length;
   1079 }
   1080 
   1081 static inline void
   1082 isc_buffer_allocate(isc_mem_t	      *mctx, isc_buffer_t **restrict dbufp,
   1083 		    const unsigned int length) {
   1084 	REQUIRE(dbufp != NULL && *dbufp == NULL);
   1085 
   1086 	isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(*dbuf) + length);
   1087 	uint8_t	     *bdata = (uint8_t *)dbuf + sizeof(*dbuf);
   1088 
   1089 	isc_buffer_init(dbuf, bdata, length);
   1090 	dbuf->extra = length;
   1091 	isc_buffer_setmctx(dbuf, mctx);
   1092 
   1093 	*dbufp = dbuf;
   1094 }
   1095 
   1096 static inline void
   1097 isc_buffer_setmctx(isc_buffer_t *restrict b, isc_mem_t *mctx) {
   1098 	REQUIRE(ISC_BUFFER_VALID(b));
   1099 
   1100 	b->mctx = mctx;
   1101 }
   1102 
   1103 static inline void
   1104 isc_buffer_clearmctx(isc_buffer_t *restrict b) {
   1105 	REQUIRE(ISC_BUFFER_VALID(b));
   1106 
   1107 	if (b->dynamic) {
   1108 		isc_mem_put(b->mctx, b->base, b->length);
   1109 		b->dynamic = false;
   1110 	}
   1111 
   1112 	b->mctx = NULL;
   1113 }
   1114 
   1115 static inline isc_result_t
   1116 isc_buffer_reserve(isc_buffer_t *restrict dbuf, const unsigned int size) {
   1117 	REQUIRE(ISC_BUFFER_VALID(dbuf));
   1118 
   1119 	size_t len;
   1120 
   1121 	len = dbuf->length;
   1122 	if ((len - dbuf->used) >= size) {
   1123 		return ISC_R_SUCCESS;
   1124 	}
   1125 
   1126 	if (dbuf->mctx == NULL) {
   1127 		return ISC_R_NOSPACE;
   1128 	}
   1129 
   1130 	/* Round to nearest buffer size increment */
   1131 	len = size + dbuf->used;
   1132 	len = ISC_ALIGN(len, ISC_BUFFER_INCR);
   1133 
   1134 	/* Cap at UINT_MAX */
   1135 	if (len > UINT_MAX) {
   1136 		len = UINT_MAX;
   1137 	}
   1138 
   1139 	if ((len - dbuf->used) < size) {
   1140 		return ISC_R_NOMEMORY;
   1141 	}
   1142 
   1143 	if (!dbuf->dynamic) {
   1144 		void *old_base = dbuf->base;
   1145 		dbuf->base = isc_mem_get(dbuf->mctx, len);
   1146 		if (old_base != NULL) {
   1147 			memmove(dbuf->base, old_base, dbuf->used);
   1148 		}
   1149 		dbuf->dynamic = true;
   1150 	} else {
   1151 		dbuf->base = isc_mem_creget(dbuf->mctx, dbuf->base,
   1152 					    dbuf->length, len, sizeof(char));
   1153 	}
   1154 	dbuf->length = (unsigned int)len;
   1155 
   1156 	return ISC_R_SUCCESS;
   1157 }
   1158 
   1159 static inline void
   1160 isc_buffer_free(isc_buffer_t **restrict dbufp) {
   1161 	REQUIRE(dbufp != NULL && ISC_BUFFER_VALID(*dbufp));
   1162 	REQUIRE((*dbufp)->mctx != NULL);
   1163 
   1164 	isc_buffer_t *dbuf = *dbufp;
   1165 	isc_mem_t    *mctx = dbuf->mctx;
   1166 	unsigned int  extra = dbuf->extra;
   1167 
   1168 	*dbufp = NULL; /* destroy external reference */
   1169 
   1170 	isc_buffer_clearmctx(dbuf);
   1171 
   1172 	isc_buffer_invalidate(dbuf);
   1173 	isc_mem_put(mctx, dbuf, sizeof(*dbuf) + extra);
   1174 }
   1175 
   1176 static inline isc_result_t
   1177 isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **restrict dstp,
   1178 	       const isc_buffer_t *restrict src) {
   1179 	isc_buffer_t *dst = NULL;
   1180 	isc_region_t  region;
   1181 	isc_result_t  result;
   1182 
   1183 	REQUIRE(dstp != NULL && *dstp == NULL);
   1184 	REQUIRE(ISC_BUFFER_VALID(src));
   1185 
   1186 	isc_buffer_usedregion(src, &region);
   1187 
   1188 	isc_buffer_allocate(mctx, &dst, region.length);
   1189 
   1190 	result = isc_buffer_copyregion(dst, &region);
   1191 	RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
   1192 	*dstp = dst;
   1193 	return ISC_R_SUCCESS;
   1194 }
   1195 
   1196 static inline isc_result_t
   1197 isc_buffer_copyregion(isc_buffer_t *restrict b,
   1198 		      const isc_region_t *restrict r) {
   1199 	isc_result_t result;
   1200 
   1201 	REQUIRE(ISC_BUFFER_VALID(b));
   1202 	REQUIRE(r != NULL);
   1203 
   1204 	if (b->mctx) {
   1205 		result = isc_buffer_reserve(b, r->length);
   1206 		if (result != ISC_R_SUCCESS) {
   1207 			return result;
   1208 		}
   1209 	}
   1210 
   1211 	if (r->length > isc_buffer_availablelength(b)) {
   1212 		return ISC_R_NOSPACE;
   1213 	}
   1214 
   1215 	if (r->length > 0U) {
   1216 		memmove(isc_buffer_used(b), r->base, r->length);
   1217 		b->used += r->length;
   1218 	}
   1219 
   1220 	return ISC_R_SUCCESS;
   1221 }
   1222 
   1223 static inline isc_result_t
   1224 isc_buffer_printf(isc_buffer_t *restrict b, const char *restrict format, ...) {
   1225 	va_list	     ap;
   1226 	int	     n;
   1227 	isc_result_t result;
   1228 
   1229 	REQUIRE(ISC_BUFFER_VALID(b));
   1230 
   1231 	va_start(ap, format);
   1232 	n = vsnprintf(NULL, 0, format, ap);
   1233 	va_end(ap);
   1234 
   1235 	if (n < 0) {
   1236 		return ISC_R_FAILURE;
   1237 	}
   1238 
   1239 	if (b->mctx) {
   1240 		result = isc_buffer_reserve(b, n + 1);
   1241 		if (result != ISC_R_SUCCESS) {
   1242 			return result;
   1243 		}
   1244 	}
   1245 
   1246 	if (isc_buffer_availablelength(b) < (unsigned int)n + 1) {
   1247 		return ISC_R_NOSPACE;
   1248 	}
   1249 
   1250 	va_start(ap, format);
   1251 	n = vsnprintf(isc_buffer_used(b), n + 1, format, ap);
   1252 	va_end(ap);
   1253 
   1254 	if (n < 0) {
   1255 		return ISC_R_FAILURE;
   1256 	}
   1257 
   1258 	b->used += n;
   1259 
   1260 	return ISC_R_SUCCESS;
   1261 }
   1262 
   1263 ISC_LANG_ENDDECLS
   1264