1290001Sglebius/* 2290001Sglebius * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * Copyright (C) 1998-2002 Internet Software Consortium. 4290001Sglebius * 5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 6290001Sglebius * purpose with or without fee is hereby granted, provided that the above 7290001Sglebius * copyright notice and this permission notice appear in all copies. 8290001Sglebius * 9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 16290001Sglebius */ 17290001Sglebius 18290001Sglebius/* $Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp $ */ 19290001Sglebius 20290001Sglebius/*! \file */ 21290001Sglebius 22290001Sglebius#include <config.h> 23290001Sglebius 24290001Sglebius#include <isc/buffer.h> 25290001Sglebius#include <isc/mem.h> 26290001Sglebius#include <isc/region.h> 27290001Sglebius#include <isc/string.h> 28290001Sglebius#include <isc/util.h> 29290001Sglebius 30290001Sglebiusvoid 31290001Sglebiusisc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) { 32290001Sglebius /* 33290001Sglebius * Make 'b' refer to the 'length'-byte region starting at 'base'. 34290001Sglebius * XXXDCL see the comment in buffer.h about base being const. 35290001Sglebius */ 36290001Sglebius 37290001Sglebius REQUIRE(b != NULL); 38290001Sglebius 39290001Sglebius ISC__BUFFER_INIT(b, base, length); 40290001Sglebius} 41290001Sglebius 42290001Sglebiusvoid 43290001Sglebiusisc__buffer_initnull(isc_buffer_t *b) { 44290001Sglebius /* 45290001Sglebius * Initialize a new buffer which has no backing store. This can 46290001Sglebius * later be grown as needed and swapped in place. 47290001Sglebius */ 48290001Sglebius 49290001Sglebius ISC__BUFFER_INIT(b, NULL, 0); 50290001Sglebius} 51290001Sglebius 52290001Sglebiusvoid 53290001Sglebiusisc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) { 54290001Sglebius /* 55290001Sglebius * Re-initialize the buffer enough to reconfigure the base of the 56290001Sglebius * buffer. We will swap in the new buffer, after copying any 57290001Sglebius * data we contain into the new buffer and adjusting all of our 58290001Sglebius * internal pointers. 59290001Sglebius * 60290001Sglebius * The buffer must not be smaller than the length of the original 61290001Sglebius * buffer. 62290001Sglebius */ 63290001Sglebius REQUIRE(b->length <= length); 64290001Sglebius REQUIRE(base != NULL); 65290001Sglebius 66290001Sglebius (void)memmove(base, b->base, b->length); 67290001Sglebius b->base = base; 68290001Sglebius b->length = length; 69290001Sglebius} 70290001Sglebius 71290001Sglebiusvoid 72290001Sglebiusisc__buffer_invalidate(isc_buffer_t *b) { 73290001Sglebius /* 74290001Sglebius * Make 'b' an invalid buffer. 75290001Sglebius */ 76290001Sglebius 77290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 78290001Sglebius REQUIRE(!ISC_LINK_LINKED(b, link)); 79290001Sglebius REQUIRE(b->mctx == NULL); 80290001Sglebius 81290001Sglebius ISC__BUFFER_INVALIDATE(b); 82290001Sglebius} 83290001Sglebius 84290001Sglebiusvoid 85290001Sglebiusisc__buffer_region(isc_buffer_t *b, isc_region_t *r) { 86290001Sglebius /* 87290001Sglebius * Make 'r' refer to the region of 'b'. 88290001Sglebius */ 89290001Sglebius 90290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 91290001Sglebius REQUIRE(r != NULL); 92290001Sglebius 93290001Sglebius ISC__BUFFER_REGION(b, r); 94290001Sglebius} 95290001Sglebius 96290001Sglebiusvoid 97290001Sglebiusisc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) { 98290001Sglebius /* 99290001Sglebius * Make 'r' refer to the used region of 'b'. 100290001Sglebius */ 101290001Sglebius 102290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 103290001Sglebius REQUIRE(r != NULL); 104290001Sglebius 105290001Sglebius ISC__BUFFER_USEDREGION(b, r); 106290001Sglebius} 107290001Sglebius 108290001Sglebiusvoid 109290001Sglebiusisc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) { 110290001Sglebius /* 111290001Sglebius * Make 'r' refer to the available region of 'b'. 112290001Sglebius */ 113290001Sglebius 114290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 115290001Sglebius REQUIRE(r != NULL); 116290001Sglebius 117290001Sglebius ISC__BUFFER_AVAILABLEREGION(b, r); 118290001Sglebius} 119290001Sglebius 120290001Sglebiusvoid 121290001Sglebiusisc__buffer_add(isc_buffer_t *b, unsigned int n) { 122290001Sglebius /* 123290001Sglebius * Increase the 'used' region of 'b' by 'n' bytes. 124290001Sglebius */ 125290001Sglebius 126290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 127290001Sglebius REQUIRE(b->used + n <= b->length); 128290001Sglebius 129290001Sglebius ISC__BUFFER_ADD(b, n); 130290001Sglebius} 131290001Sglebius 132290001Sglebiusvoid 133290001Sglebiusisc__buffer_subtract(isc_buffer_t *b, unsigned int n) { 134290001Sglebius /* 135290001Sglebius * Decrease the 'used' region of 'b' by 'n' bytes. 136290001Sglebius */ 137290001Sglebius 138290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 139290001Sglebius REQUIRE(b->used >= n); 140290001Sglebius 141290001Sglebius ISC__BUFFER_SUBTRACT(b, n); 142290001Sglebius} 143290001Sglebius 144290001Sglebiusvoid 145290001Sglebiusisc__buffer_clear(isc_buffer_t *b) { 146290001Sglebius /* 147290001Sglebius * Make the used region empty. 148290001Sglebius */ 149290001Sglebius 150290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 151290001Sglebius 152290001Sglebius ISC__BUFFER_CLEAR(b); 153290001Sglebius} 154290001Sglebius 155290001Sglebiusvoid 156290001Sglebiusisc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) { 157290001Sglebius /* 158290001Sglebius * Make 'r' refer to the consumed region of 'b'. 159290001Sglebius */ 160290001Sglebius 161290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 162290001Sglebius REQUIRE(r != NULL); 163290001Sglebius 164290001Sglebius ISC__BUFFER_CONSUMEDREGION(b, r); 165290001Sglebius} 166290001Sglebius 167290001Sglebiusvoid 168290001Sglebiusisc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) { 169290001Sglebius /* 170290001Sglebius * Make 'r' refer to the remaining region of 'b'. 171290001Sglebius */ 172290001Sglebius 173290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 174290001Sglebius REQUIRE(r != NULL); 175290001Sglebius 176290001Sglebius ISC__BUFFER_REMAININGREGION(b, r); 177290001Sglebius} 178290001Sglebius 179290001Sglebiusvoid 180290001Sglebiusisc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) { 181290001Sglebius /* 182290001Sglebius * Make 'r' refer to the active region of 'b'. 183290001Sglebius */ 184290001Sglebius 185290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 186290001Sglebius REQUIRE(r != NULL); 187290001Sglebius 188290001Sglebius ISC__BUFFER_ACTIVEREGION(b, r); 189290001Sglebius} 190290001Sglebius 191290001Sglebiusvoid 192290001Sglebiusisc__buffer_setactive(isc_buffer_t *b, unsigned int n) { 193290001Sglebius /* 194290001Sglebius * Sets the end of the active region 'n' bytes after current. 195290001Sglebius */ 196290001Sglebius 197290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 198290001Sglebius REQUIRE(b->current + n <= b->used); 199290001Sglebius 200290001Sglebius ISC__BUFFER_SETACTIVE(b, n); 201290001Sglebius} 202290001Sglebius 203290001Sglebiusvoid 204290001Sglebiusisc__buffer_first(isc_buffer_t *b) { 205290001Sglebius /* 206290001Sglebius * Make the consumed region empty. 207290001Sglebius */ 208290001Sglebius 209290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 210290001Sglebius 211290001Sglebius ISC__BUFFER_FIRST(b); 212290001Sglebius} 213290001Sglebius 214290001Sglebiusvoid 215290001Sglebiusisc__buffer_forward(isc_buffer_t *b, unsigned int n) { 216290001Sglebius /* 217290001Sglebius * Increase the 'consumed' region of 'b' by 'n' bytes. 218290001Sglebius */ 219290001Sglebius 220290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 221290001Sglebius REQUIRE(b->current + n <= b->used); 222290001Sglebius 223290001Sglebius ISC__BUFFER_FORWARD(b, n); 224290001Sglebius} 225290001Sglebius 226290001Sglebiusvoid 227290001Sglebiusisc__buffer_back(isc_buffer_t *b, unsigned int n) { 228290001Sglebius /* 229290001Sglebius * Decrease the 'consumed' region of 'b' by 'n' bytes. 230290001Sglebius */ 231290001Sglebius 232290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 233290001Sglebius REQUIRE(n <= b->current); 234290001Sglebius 235290001Sglebius ISC__BUFFER_BACK(b, n); 236290001Sglebius} 237290001Sglebius 238290001Sglebiusvoid 239290001Sglebiusisc_buffer_compact(isc_buffer_t *b) { 240290001Sglebius unsigned int length; 241290001Sglebius void *src; 242290001Sglebius 243290001Sglebius /* 244290001Sglebius * Compact the used region by moving the remaining region so it occurs 245290001Sglebius * at the start of the buffer. The used region is shrunk by the size 246290001Sglebius * of the consumed region, and the consumed region is then made empty. 247290001Sglebius */ 248290001Sglebius 249290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 250290001Sglebius 251290001Sglebius src = isc_buffer_current(b); 252290001Sglebius length = isc_buffer_remaininglength(b); 253290001Sglebius (void)memmove(b->base, src, (size_t)length); 254290001Sglebius 255290001Sglebius if (b->active > b->current) 256290001Sglebius b->active -= b->current; 257290001Sglebius else 258290001Sglebius b->active = 0; 259290001Sglebius b->current = 0; 260290001Sglebius b->used = length; 261290001Sglebius} 262290001Sglebius 263290001Sglebiusisc_uint8_t 264290001Sglebiusisc_buffer_getuint8(isc_buffer_t *b) { 265290001Sglebius unsigned char *cp; 266290001Sglebius isc_uint8_t result; 267290001Sglebius 268290001Sglebius /* 269290001Sglebius * Read an unsigned 8-bit integer from 'b' and return it. 270290001Sglebius */ 271290001Sglebius 272290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 273290001Sglebius REQUIRE(b->used - b->current >= 1); 274290001Sglebius 275290001Sglebius cp = isc_buffer_current(b); 276290001Sglebius b->current += 1; 277290001Sglebius result = ((isc_uint8_t)(cp[0])); 278290001Sglebius 279290001Sglebius return (result); 280290001Sglebius} 281290001Sglebius 282290001Sglebiusvoid 283290001Sglebiusisc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) { 284290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 285290001Sglebius REQUIRE(b->used + 1 <= b->length); 286290001Sglebius 287290001Sglebius ISC__BUFFER_PUTUINT8(b, val); 288290001Sglebius} 289290001Sglebius 290290001Sglebiusisc_uint16_t 291290001Sglebiusisc_buffer_getuint16(isc_buffer_t *b) { 292290001Sglebius unsigned char *cp; 293290001Sglebius isc_uint16_t result; 294290001Sglebius 295290001Sglebius /* 296290001Sglebius * Read an unsigned 16-bit integer in network byte order from 'b', 297290001Sglebius * convert it to host byte order, and return it. 298290001Sglebius */ 299290001Sglebius 300290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 301290001Sglebius REQUIRE(b->used - b->current >= 2); 302290001Sglebius 303290001Sglebius cp = isc_buffer_current(b); 304290001Sglebius b->current += 2; 305290001Sglebius result = ((unsigned int)(cp[0])) << 8; 306290001Sglebius result |= ((unsigned int)(cp[1])); 307290001Sglebius 308290001Sglebius return (result); 309290001Sglebius} 310290001Sglebius 311290001Sglebiusvoid 312290001Sglebiusisc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) { 313290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 314290001Sglebius REQUIRE(b->used + 2 <= b->length); 315290001Sglebius 316290001Sglebius ISC__BUFFER_PUTUINT16(b, val); 317290001Sglebius} 318290001Sglebius 319290001Sglebiusvoid 320290001Sglebiusisc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) { 321290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 322290001Sglebius REQUIRE(b->used + 3 <= b->length); 323290001Sglebius 324290001Sglebius ISC__BUFFER_PUTUINT24(b, val); 325290001Sglebius} 326290001Sglebius 327290001Sglebiusisc_uint32_t 328290001Sglebiusisc_buffer_getuint32(isc_buffer_t *b) { 329290001Sglebius unsigned char *cp; 330290001Sglebius isc_uint32_t result; 331290001Sglebius 332290001Sglebius /* 333290001Sglebius * Read an unsigned 32-bit integer in network byte order from 'b', 334290001Sglebius * convert it to host byte order, and return it. 335290001Sglebius */ 336290001Sglebius 337290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 338290001Sglebius REQUIRE(b->used - b->current >= 4); 339290001Sglebius 340290001Sglebius cp = isc_buffer_current(b); 341290001Sglebius b->current += 4; 342290001Sglebius result = ((unsigned int)(cp[0])) << 24; 343290001Sglebius result |= ((unsigned int)(cp[1])) << 16; 344290001Sglebius result |= ((unsigned int)(cp[2])) << 8; 345290001Sglebius result |= ((unsigned int)(cp[3])); 346290001Sglebius 347290001Sglebius return (result); 348290001Sglebius} 349290001Sglebius 350290001Sglebiusvoid 351290001Sglebiusisc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) { 352290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 353290001Sglebius REQUIRE(b->used + 4 <= b->length); 354290001Sglebius 355290001Sglebius ISC__BUFFER_PUTUINT32(b, val); 356290001Sglebius} 357290001Sglebius 358290001Sglebiusisc_uint64_t 359290001Sglebiusisc_buffer_getuint48(isc_buffer_t *b) { 360290001Sglebius unsigned char *cp; 361290001Sglebius isc_uint64_t result; 362290001Sglebius 363290001Sglebius /* 364290001Sglebius * Read an unsigned 48-bit integer in network byte order from 'b', 365290001Sglebius * convert it to host byte order, and return it. 366290001Sglebius */ 367290001Sglebius 368290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 369290001Sglebius REQUIRE(b->used - b->current >= 6); 370290001Sglebius 371290001Sglebius cp = isc_buffer_current(b); 372290001Sglebius b->current += 6; 373290001Sglebius result = ((isc_int64_t)(cp[0])) << 40; 374290001Sglebius result |= ((isc_int64_t)(cp[1])) << 32; 375290001Sglebius result |= ((isc_int64_t)(cp[2])) << 24; 376290001Sglebius result |= ((isc_int64_t)(cp[3])) << 16; 377290001Sglebius result |= ((isc_int64_t)(cp[4])) << 8; 378290001Sglebius result |= ((isc_int64_t)(cp[5])); 379290001Sglebius 380290001Sglebius return (result); 381290001Sglebius} 382290001Sglebius 383290001Sglebiusvoid 384290001Sglebiusisc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) { 385290001Sglebius isc_uint16_t valhi; 386290001Sglebius isc_uint32_t vallo; 387290001Sglebius 388290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 389290001Sglebius REQUIRE(b->used + 6 <= b->length); 390290001Sglebius 391290001Sglebius valhi = (isc_uint16_t)(val >> 32); 392290001Sglebius vallo = (isc_uint32_t)(val & 0xFFFFFFFF); 393290001Sglebius ISC__BUFFER_PUTUINT16(b, valhi); 394290001Sglebius ISC__BUFFER_PUTUINT32(b, vallo); 395290001Sglebius} 396290001Sglebius 397290001Sglebiusvoid 398290001Sglebiusisc__buffer_putmem(isc_buffer_t *b, const unsigned char *base, 399290001Sglebius unsigned int length) 400290001Sglebius{ 401290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 402290001Sglebius REQUIRE(b->used + length <= b->length); 403290001Sglebius 404290001Sglebius ISC__BUFFER_PUTMEM(b, base, length); 405290001Sglebius} 406290001Sglebius 407290001Sglebiusvoid 408290001Sglebiusisc__buffer_putstr(isc_buffer_t *b, const char *source) { 409293896Sglebius size_t l; 410290001Sglebius unsigned char *cp; 411290001Sglebius 412290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 413290001Sglebius REQUIRE(source != NULL); 414290001Sglebius 415290001Sglebius /* 416290001Sglebius * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once. 417290001Sglebius */ 418290001Sglebius l = strlen(source); 419290001Sglebius 420290001Sglebius REQUIRE(l <= isc_buffer_availablelength(b)); 421290001Sglebius 422290001Sglebius cp = isc_buffer_used(b); 423290001Sglebius memcpy(cp, source, l); 424293896Sglebius b->used += (u_int)l; /* checked above - no overflow here */ 425290001Sglebius} 426290001Sglebius 427290001Sglebiusisc_result_t 428290001Sglebiusisc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) { 429290001Sglebius unsigned char *base; 430290001Sglebius unsigned int available; 431290001Sglebius 432290001Sglebius REQUIRE(ISC_BUFFER_VALID(b)); 433290001Sglebius REQUIRE(r != NULL); 434290001Sglebius 435290001Sglebius /* 436290001Sglebius * XXXDCL 437290001Sglebius */ 438290001Sglebius base = isc_buffer_used(b); 439290001Sglebius available = isc_buffer_availablelength(b); 440290001Sglebius if (r->length > available) 441290001Sglebius return (ISC_R_NOSPACE); 442290001Sglebius memcpy(base, r->base, r->length); 443290001Sglebius b->used += r->length; 444290001Sglebius 445290001Sglebius return (ISC_R_SUCCESS); 446290001Sglebius} 447290001Sglebius 448290001Sglebiusisc_result_t 449290001Sglebiusisc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer, 450290001Sglebius unsigned int length) 451290001Sglebius{ 452290001Sglebius isc_buffer_t *dbuf; 453290001Sglebius 454290001Sglebius REQUIRE(dynbuffer != NULL); 455290001Sglebius REQUIRE(*dynbuffer == NULL); 456290001Sglebius 457290001Sglebius dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t)); 458290001Sglebius if (dbuf == NULL) 459290001Sglebius return (ISC_R_NOMEMORY); 460290001Sglebius 461290001Sglebius isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t), 462290001Sglebius length); 463290001Sglebius dbuf->mctx = mctx; 464290001Sglebius 465290001Sglebius *dynbuffer = dbuf; 466290001Sglebius 467290001Sglebius return (ISC_R_SUCCESS); 468290001Sglebius} 469290001Sglebius 470290001Sglebiusvoid 471290001Sglebiusisc_buffer_free(isc_buffer_t **dynbuffer) { 472290001Sglebius unsigned int real_length; 473290001Sglebius isc_buffer_t *dbuf; 474290001Sglebius isc_mem_t *mctx; 475290001Sglebius 476290001Sglebius REQUIRE(dynbuffer != NULL); 477290001Sglebius REQUIRE(ISC_BUFFER_VALID(*dynbuffer)); 478290001Sglebius REQUIRE((*dynbuffer)->mctx != NULL); 479290001Sglebius 480290001Sglebius dbuf = *dynbuffer; 481290001Sglebius *dynbuffer = NULL; /* destroy external reference */ 482290001Sglebius 483290001Sglebius real_length = dbuf->length + sizeof(isc_buffer_t); 484290001Sglebius mctx = dbuf->mctx; 485290001Sglebius dbuf->mctx = NULL; 486290001Sglebius isc_buffer_invalidate(dbuf); 487290001Sglebius 488290001Sglebius isc_mem_put(mctx, dbuf, real_length); 489290001Sglebius} 490