Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: buffer.c,v 1.2 2024/08/18 20:47:14 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
      5  * Copyright (C) 1998-2002  Internet Software Consortium.
      6  *
      7  * Permission to use, copy, modify, and/or distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
     12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
     14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     17  * PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 /* Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp  */
     21 
     22 /*! \file */
     23 
     24 #include <config.h>
     25 
     26 #include <isc/buffer.h>
     27 #include <isc/mem.h>
     28 #include <isc/region.h>
     29 #include <isc/string.h>
     30 #include <isc/util.h>
     31 
     32 void
     33 isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) {
     34 	/*
     35 	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
     36 	 * XXXDCL see the comment in buffer.h about base being const.
     37 	 */
     38 
     39 	REQUIRE(b != NULL);
     40 
     41 	ISC__BUFFER_INIT(b, base, length);
     42 }
     43 
     44 void
     45 isc__buffer_initnull(isc_buffer_t *b) {
     46 	/*
     47 	 * Initialize a new buffer which has no backing store.  This can
     48 	 * later be grown as needed and swapped in place.
     49 	 */
     50 
     51 	ISC__BUFFER_INIT(b, NULL, 0);
     52 }
     53 
     54 void
     55 isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
     56 	/*
     57 	 * Re-initialize the buffer enough to reconfigure the base of the
     58 	 * buffer.  We will swap in the new buffer, after copying any
     59 	 * data we contain into the new buffer and adjusting all of our
     60 	 * internal pointers.
     61 	 *
     62 	 * The buffer must not be smaller than the length of the original
     63 	 * buffer.
     64 	 */
     65 	REQUIRE(b->length <= length);
     66 	REQUIRE(base != NULL);
     67 
     68 	(void)memmove(base, b->base, b->length);
     69 	b->base = base;
     70 	b->length = length;
     71 }
     72 
     73 void
     74 isc__buffer_invalidate(isc_buffer_t *b) {
     75 	/*
     76 	 * Make 'b' an invalid buffer.
     77 	 */
     78 
     79 	REQUIRE(ISC_BUFFER_VALID(b));
     80 	REQUIRE(!ISC_LINK_LINKED(b, link));
     81 	REQUIRE(b->mctx == NULL);
     82 
     83 	ISC__BUFFER_INVALIDATE(b);
     84 }
     85 
     86 void
     87 isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
     88 	/*
     89 	 * Make 'r' refer to the region of 'b'.
     90 	 */
     91 
     92 	REQUIRE(ISC_BUFFER_VALID(b));
     93 	REQUIRE(r != NULL);
     94 
     95 	ISC__BUFFER_REGION(b, r);
     96 }
     97 
     98 void
     99 isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
    100 	/*
    101 	 * Make 'r' refer to the used region of 'b'.
    102 	 */
    103 
    104 	REQUIRE(ISC_BUFFER_VALID(b));
    105 	REQUIRE(r != NULL);
    106 
    107 	ISC__BUFFER_USEDREGION(b, r);
    108 }
    109 
    110 void
    111 isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
    112 	/*
    113 	 * Make 'r' refer to the available region of 'b'.
    114 	 */
    115 
    116 	REQUIRE(ISC_BUFFER_VALID(b));
    117 	REQUIRE(r != NULL);
    118 
    119 	ISC__BUFFER_AVAILABLEREGION(b, r);
    120 }
    121 
    122 void
    123 isc__buffer_add(isc_buffer_t *b, unsigned int n) {
    124 	/*
    125 	 * Increase the 'used' region of 'b' by 'n' bytes.
    126 	 */
    127 
    128 	REQUIRE(ISC_BUFFER_VALID(b));
    129 	REQUIRE(b->used + n <= b->length);
    130 
    131 	ISC__BUFFER_ADD(b, n);
    132 }
    133 
    134 void
    135 isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
    136 	/*
    137 	 * Decrease the 'used' region of 'b' by 'n' bytes.
    138 	 */
    139 
    140 	REQUIRE(ISC_BUFFER_VALID(b));
    141 	REQUIRE(b->used >= n);
    142 
    143 	ISC__BUFFER_SUBTRACT(b, n);
    144 }
    145 
    146 void
    147 isc__buffer_clear(isc_buffer_t *b) {
    148 	/*
    149 	 * Make the used region empty.
    150 	 */
    151 
    152 	REQUIRE(ISC_BUFFER_VALID(b));
    153 
    154 	ISC__BUFFER_CLEAR(b);
    155 }
    156 
    157 void
    158 isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
    159 	/*
    160 	 * Make 'r' refer to the consumed region of 'b'.
    161 	 */
    162 
    163 	REQUIRE(ISC_BUFFER_VALID(b));
    164 	REQUIRE(r != NULL);
    165 
    166 	ISC__BUFFER_CONSUMEDREGION(b, r);
    167 }
    168 
    169 void
    170 isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
    171 	/*
    172 	 * Make 'r' refer to the remaining region of 'b'.
    173 	 */
    174 
    175 	REQUIRE(ISC_BUFFER_VALID(b));
    176 	REQUIRE(r != NULL);
    177 
    178 	ISC__BUFFER_REMAININGREGION(b, r);
    179 }
    180 
    181 void
    182 isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
    183 	/*
    184 	 * Make 'r' refer to the active region of 'b'.
    185 	 */
    186 
    187 	REQUIRE(ISC_BUFFER_VALID(b));
    188 	REQUIRE(r != NULL);
    189 
    190 	ISC__BUFFER_ACTIVEREGION(b, r);
    191 }
    192 
    193 void
    194 isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
    195 	/*
    196 	 * Sets the end of the active region 'n' bytes after current.
    197 	 */
    198 
    199 	REQUIRE(ISC_BUFFER_VALID(b));
    200 	REQUIRE(b->current + n <= b->used);
    201 
    202 	ISC__BUFFER_SETACTIVE(b, n);
    203 }
    204 
    205 void
    206 isc__buffer_first(isc_buffer_t *b) {
    207 	/*
    208 	 * Make the consumed region empty.
    209 	 */
    210 
    211 	REQUIRE(ISC_BUFFER_VALID(b));
    212 
    213 	ISC__BUFFER_FIRST(b);
    214 }
    215 
    216 void
    217 isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
    218 	/*
    219 	 * Increase the 'consumed' region of 'b' by 'n' bytes.
    220 	 */
    221 
    222 	REQUIRE(ISC_BUFFER_VALID(b));
    223 	REQUIRE(b->current + n <= b->used);
    224 
    225 	ISC__BUFFER_FORWARD(b, n);
    226 }
    227 
    228 void
    229 isc__buffer_back(isc_buffer_t *b, unsigned int n) {
    230 	/*
    231 	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
    232 	 */
    233 
    234 	REQUIRE(ISC_BUFFER_VALID(b));
    235 	REQUIRE(n <= b->current);
    236 
    237 	ISC__BUFFER_BACK(b, n);
    238 }
    239 
    240 void
    241 isc_buffer_compact(isc_buffer_t *b) {
    242 	unsigned int length;
    243 	void *src;
    244 
    245 	/*
    246 	 * Compact the used region by moving the remaining region so it occurs
    247 	 * at the start of the buffer.  The used region is shrunk by the size
    248 	 * of the consumed region, and the consumed region is then made empty.
    249 	 */
    250 
    251 	REQUIRE(ISC_BUFFER_VALID(b));
    252 
    253 	src = isc_buffer_current(b);
    254 	length = isc_buffer_remaininglength(b);
    255 	(void)memmove(b->base, src, (size_t)length);
    256 
    257 	if (b->active > b->current)
    258 		b->active -= b->current;
    259 	else
    260 		b->active = 0;
    261 	b->current = 0;
    262 	b->used = length;
    263 }
    264 
    265 isc_uint8_t
    266 isc_buffer_getuint8(isc_buffer_t *b) {
    267 	unsigned char *cp;
    268 	isc_uint8_t result;
    269 
    270 	/*
    271 	 * Read an unsigned 8-bit integer from 'b' and return it.
    272 	 */
    273 
    274 	REQUIRE(ISC_BUFFER_VALID(b));
    275 	REQUIRE(b->used - b->current >= 1);
    276 
    277 	cp = isc_buffer_current(b);
    278 	b->current += 1;
    279 	result = ((isc_uint8_t)(cp[0]));
    280 
    281 	return (result);
    282 }
    283 
    284 void
    285 isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
    286 	REQUIRE(ISC_BUFFER_VALID(b));
    287 	REQUIRE(b->used + 1 <= b->length);
    288 
    289 	ISC__BUFFER_PUTUINT8(b, val);
    290 }
    291 
    292 isc_uint16_t
    293 isc_buffer_getuint16(isc_buffer_t *b) {
    294 	unsigned char *cp;
    295 	isc_uint16_t result;
    296 
    297 	/*
    298 	 * Read an unsigned 16-bit integer in network byte order from 'b',
    299 	 * convert it to host byte order, and return it.
    300 	 */
    301 
    302 	REQUIRE(ISC_BUFFER_VALID(b));
    303 	REQUIRE(b->used - b->current >= 2);
    304 
    305 	cp = isc_buffer_current(b);
    306 	b->current += 2;
    307 	result = ((unsigned int)(cp[0])) << 8;
    308 	result |= ((unsigned int)(cp[1]));
    309 
    310 	return (result);
    311 }
    312 
    313 void
    314 isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
    315 	REQUIRE(ISC_BUFFER_VALID(b));
    316 	REQUIRE(b->used + 2 <= b->length);
    317 
    318 	ISC__BUFFER_PUTUINT16(b, val);
    319 }
    320 
    321 void
    322 isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
    323 	REQUIRE(ISC_BUFFER_VALID(b));
    324 	REQUIRE(b->used + 3 <= b->length);
    325 
    326 	ISC__BUFFER_PUTUINT24(b, val);
    327 }
    328 
    329 isc_uint32_t
    330 isc_buffer_getuint32(isc_buffer_t *b) {
    331 	unsigned char *cp;
    332 	isc_uint32_t result;
    333 
    334 	/*
    335 	 * Read an unsigned 32-bit integer in network byte order from 'b',
    336 	 * convert it to host byte order, and return it.
    337 	 */
    338 
    339 	REQUIRE(ISC_BUFFER_VALID(b));
    340 	REQUIRE(b->used - b->current >= 4);
    341 
    342 	cp = isc_buffer_current(b);
    343 	b->current += 4;
    344 	result = ((unsigned int)(cp[0])) << 24;
    345 	result |= ((unsigned int)(cp[1])) << 16;
    346 	result |= ((unsigned int)(cp[2])) << 8;
    347 	result |= ((unsigned int)(cp[3]));
    348 
    349 	return (result);
    350 }
    351 
    352 void
    353 isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
    354 	REQUIRE(ISC_BUFFER_VALID(b));
    355 	REQUIRE(b->used + 4 <= b->length);
    356 
    357 	ISC__BUFFER_PUTUINT32(b, val);
    358 }
    359 
    360 isc_uint64_t
    361 isc_buffer_getuint48(isc_buffer_t *b) {
    362 	unsigned char *cp;
    363 	isc_uint64_t result;
    364 
    365 	/*
    366 	 * Read an unsigned 48-bit integer in network byte order from 'b',
    367 	 * convert it to host byte order, and return it.
    368 	 */
    369 
    370 	REQUIRE(ISC_BUFFER_VALID(b));
    371 	REQUIRE(b->used - b->current >= 6);
    372 
    373 	cp = isc_buffer_current(b);
    374 	b->current += 6;
    375 	result = ((isc_int64_t)(cp[0])) << 40;
    376 	result |= ((isc_int64_t)(cp[1])) << 32;
    377 	result |= ((isc_int64_t)(cp[2])) << 24;
    378 	result |= ((isc_int64_t)(cp[3])) << 16;
    379 	result |= ((isc_int64_t)(cp[4])) << 8;
    380 	result |= ((isc_int64_t)(cp[5]));
    381 
    382 	return (result);
    383 }
    384 
    385 void
    386 isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
    387 	isc_uint16_t valhi;
    388 	isc_uint32_t vallo;
    389 
    390 	REQUIRE(ISC_BUFFER_VALID(b));
    391 	REQUIRE(b->used + 6 <= b->length);
    392 
    393 	valhi = (isc_uint16_t)(val >> 32);
    394 	vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
    395 	ISC__BUFFER_PUTUINT16(b, valhi);
    396 	ISC__BUFFER_PUTUINT32(b, vallo);
    397 }
    398 
    399 void
    400 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
    401 		   unsigned int length)
    402 {
    403 	REQUIRE(ISC_BUFFER_VALID(b));
    404 	REQUIRE(b->used + length <= b->length);
    405 
    406 	ISC__BUFFER_PUTMEM(b, base, length);
    407 }
    408 
    409 void
    410 isc__buffer_putstr(isc_buffer_t *b, const char *source) {
    411 	size_t l;
    412 	unsigned char *cp;
    413 
    414 	REQUIRE(ISC_BUFFER_VALID(b));
    415 	REQUIRE(source != NULL);
    416 
    417 	/*
    418 	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
    419 	 */
    420 	l = strlen(source);
    421 
    422 	REQUIRE(l <= isc_buffer_availablelength(b));
    423 
    424 	cp = isc_buffer_used(b);
    425 	memcpy(cp, source, l);
    426 	b->used += (u_int)l; /* checked above - no overflow here */
    427 }
    428 
    429 isc_result_t
    430 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
    431 	unsigned char *base;
    432 	unsigned int available;
    433 
    434 	REQUIRE(ISC_BUFFER_VALID(b));
    435 	REQUIRE(r != NULL);
    436 
    437 	/*
    438 	 * XXXDCL
    439 	 */
    440 	base = isc_buffer_used(b);
    441 	available = isc_buffer_availablelength(b);
    442 	if (r->length > available)
    443 		return (ISC_R_NOSPACE);
    444 	memcpy(base, r->base, r->length);
    445 	b->used += r->length;
    446 
    447 	return (ISC_R_SUCCESS);
    448 }
    449 
    450 isc_result_t
    451 isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
    452 		    unsigned int length)
    453 {
    454 	isc_buffer_t *dbuf;
    455 
    456 	REQUIRE(dynbuffer != NULL);
    457 	REQUIRE(*dynbuffer == NULL);
    458 
    459 	dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
    460 	if (dbuf == NULL)
    461 		return (ISC_R_NOMEMORY);
    462 
    463 	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
    464 			length);
    465 	dbuf->mctx = mctx;
    466 
    467 	*dynbuffer = dbuf;
    468 
    469 	return (ISC_R_SUCCESS);
    470 }
    471 
    472 void
    473 isc_buffer_free(isc_buffer_t **dynbuffer) {
    474 	unsigned int real_length;
    475 	isc_buffer_t *dbuf;
    476 	isc_mem_t *mctx;
    477 
    478 	REQUIRE(dynbuffer != NULL);
    479 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
    480 	REQUIRE((*dynbuffer)->mctx != NULL);
    481 
    482 	dbuf = *dynbuffer;
    483 	*dynbuffer = NULL;	/* destroy external reference */
    484 
    485 	real_length = dbuf->length + sizeof(isc_buffer_t);
    486 	mctx = dbuf->mctx;
    487 	dbuf->mctx = NULL;
    488 	isc_buffer_invalidate(dbuf);
    489 
    490 	isc_mem_put(mctx, dbuf, real_length);
    491 }
    492