1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: buffer.c,v 1.8 2020/02/26 18:47:59 florian Exp $ */ 18 19 /*! \file */ 20 21 #include <stdlib.h> 22 #include <isc/buffer.h> 23 24 #include <isc/region.h> 25 #include <string.h> 26 #include <isc/util.h> 27 28 void 29 isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) { 30 /* 31 * Make 'b' refer to the 'length'-byte region starting at 'base'. 32 * XXXDCL see the comment in buffer.h about base being const. 33 */ 34 35 REQUIRE(b != NULL); 36 37 ISC__BUFFER_INIT(b, base, length); 38 } 39 40 void 41 isc__buffer_invalidate(isc_buffer_t *b) { 42 /* 43 * Make 'b' an invalid buffer. 44 */ 45 46 REQUIRE(!ISC_LINK_LINKED(b, link)); 47 48 ISC__BUFFER_INVALIDATE(b); 49 } 50 51 void 52 isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) { 53 /* 54 * Make 'r' refer to the used region of 'b'. 55 */ 56 57 REQUIRE(r != NULL); 58 59 ISC__BUFFER_USEDREGION(b, r); 60 } 61 62 void 63 isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) { 64 /* 65 * Make 'r' refer to the available region of 'b'. 66 */ 67 68 REQUIRE(r != NULL); 69 70 ISC__BUFFER_AVAILABLEREGION(b, r); 71 } 72 73 void 74 isc__buffer_add(isc_buffer_t *b, unsigned int n) { 75 /* 76 * Increase the 'used' region of 'b' by 'n' bytes. 77 */ 78 79 REQUIRE(b->used + n <= b->length); 80 81 ISC__BUFFER_ADD(b, n); 82 } 83 84 void 85 isc__buffer_subtract(isc_buffer_t *b, unsigned int n) { 86 /* 87 * Decrease the 'used' region of 'b' by 'n' bytes. 88 */ 89 90 REQUIRE(b->used >= n); 91 92 ISC__BUFFER_SUBTRACT(b, n); 93 } 94 95 void 96 isc__buffer_clear(isc_buffer_t *b) { 97 /* 98 * Make the used region empty. 99 */ 100 101 ISC__BUFFER_CLEAR(b); 102 } 103 104 void 105 isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) { 106 /* 107 * Make 'r' refer to the remaining region of 'b'. 108 */ 109 110 REQUIRE(r != NULL); 111 112 ISC__BUFFER_REMAININGREGION(b, r); 113 } 114 115 void 116 isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) { 117 /* 118 * Make 'r' refer to the active region of 'b'. 119 */ 120 121 REQUIRE(r != NULL); 122 123 ISC__BUFFER_ACTIVEREGION(b, r); 124 } 125 126 void 127 isc__buffer_setactive(isc_buffer_t *b, unsigned int n) { 128 /* 129 * Sets the end of the active region 'n' bytes after current. 130 */ 131 132 REQUIRE(b->current + n <= b->used); 133 134 ISC__BUFFER_SETACTIVE(b, n); 135 } 136 137 void 138 isc__buffer_first(isc_buffer_t *b) { 139 /* 140 * Make the consumed region empty. 141 */ 142 143 ISC__BUFFER_FIRST(b); 144 } 145 146 void 147 isc__buffer_forward(isc_buffer_t *b, unsigned int n) { 148 /* 149 * Increase the 'consumed' region of 'b' by 'n' bytes. 150 */ 151 152 REQUIRE(b->current + n <= b->used); 153 154 ISC__BUFFER_FORWARD(b, n); 155 } 156 157 void 158 isc_buffer_compact(isc_buffer_t *b) { 159 unsigned int length; 160 void *src; 161 162 /* 163 * Compact the used region by moving the remaining region so it occurs 164 * at the start of the buffer. The used region is shrunk by the size 165 * of the consumed region, and the consumed region is then made empty. 166 */ 167 168 src = isc_buffer_current(b); 169 length = isc_buffer_remaininglength(b); 170 (void)memmove(b->base, src, (size_t)length); 171 172 if (b->active > b->current) 173 b->active -= b->current; 174 else 175 b->active = 0; 176 b->current = 0; 177 b->used = length; 178 } 179 180 uint8_t 181 isc_buffer_getuint8(isc_buffer_t *b) { 182 unsigned char *cp; 183 uint8_t result; 184 185 /* 186 * Read an unsigned 8-bit integer from 'b' and return it. 187 */ 188 189 REQUIRE(b->used - b->current >= 1); 190 191 cp = isc_buffer_current(b); 192 b->current += 1; 193 result = ((uint8_t)(cp[0])); 194 195 return (result); 196 } 197 198 void 199 isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) { 200 REQUIRE(b->used + 1 <= b->length); 201 202 ISC__BUFFER_PUTUINT8(b, val); 203 } 204 205 uint16_t 206 isc_buffer_getuint16(isc_buffer_t *b) { 207 unsigned char *cp; 208 uint16_t result; 209 210 /* 211 * Read an unsigned 16-bit integer in network byte order from 'b', 212 * convert it to host byte order, and return it. 213 */ 214 215 REQUIRE(b->used - b->current >= 2); 216 217 cp = isc_buffer_current(b); 218 b->current += 2; 219 result = ((unsigned int)(cp[0])) << 8; 220 result |= ((unsigned int)(cp[1])); 221 222 return (result); 223 } 224 225 void 226 isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) { 227 REQUIRE(b->used + 2 <= b->length); 228 229 ISC__BUFFER_PUTUINT16(b, val); 230 } 231 232 uint32_t 233 isc_buffer_getuint32(isc_buffer_t *b) { 234 unsigned char *cp; 235 uint32_t result; 236 237 /* 238 * Read an unsigned 32-bit integer in network byte order from 'b', 239 * convert it to host byte order, and return it. 240 */ 241 242 REQUIRE(b->used - b->current >= 4); 243 244 cp = isc_buffer_current(b); 245 b->current += 4; 246 result = ((unsigned int)(cp[0])) << 24; 247 result |= ((unsigned int)(cp[1])) << 16; 248 result |= ((unsigned int)(cp[2])) << 8; 249 result |= ((unsigned int)(cp[3])); 250 251 return (result); 252 } 253 254 void 255 isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) { 256 REQUIRE(b->used + 4 <= b->length); 257 258 ISC__BUFFER_PUTUINT32(b, val); 259 } 260 261 void 262 isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) { 263 uint16_t valhi; 264 uint32_t vallo; 265 266 REQUIRE(b->used + 6 <= b->length); 267 268 valhi = (uint16_t)(val >> 32); 269 vallo = (uint32_t)(val & 0xFFFFFFFF); 270 ISC__BUFFER_PUTUINT16(b, valhi); 271 ISC__BUFFER_PUTUINT32(b, vallo); 272 } 273 274 void 275 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base, 276 unsigned int length) 277 { 278 REQUIRE(b->used + length <= b->length); 279 280 ISC__BUFFER_PUTMEM(b, base, length); 281 } 282 283 void 284 isc__buffer_putstr(isc_buffer_t *b, const char *source) { 285 unsigned int l; 286 unsigned char *cp; 287 288 REQUIRE(source != NULL); 289 290 /* 291 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once. 292 */ 293 l = strlen(source); 294 295 REQUIRE(l <= isc_buffer_availablelength(b)); 296 297 cp = isc_buffer_used(b); 298 memmove(cp, source, l); 299 b->used += l; 300 } 301 302 isc_result_t 303 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) { 304 unsigned char *base; 305 unsigned int available; 306 307 REQUIRE(r != NULL); 308 309 /* 310 * XXXDCL 311 */ 312 base = isc_buffer_used(b); 313 available = isc_buffer_availablelength(b); 314 if (r->length > available) 315 return (ISC_R_NOSPACE); 316 memmove(base, r->base, r->length); 317 b->used += r->length; 318 319 return (ISC_R_SUCCESS); 320 } 321 322 isc_result_t 323 isc_buffer_allocate(isc_buffer_t **dynbuffer, 324 unsigned int length) 325 { 326 isc_buffer_t *dbuf; 327 328 REQUIRE(dynbuffer != NULL); 329 REQUIRE(*dynbuffer == NULL); 330 331 dbuf = malloc(length + sizeof(isc_buffer_t)); 332 if (dbuf == NULL) 333 return (ISC_R_NOMEMORY); 334 335 isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t), 336 length); 337 338 *dynbuffer = dbuf; 339 340 return (ISC_R_SUCCESS); 341 } 342 343 void 344 isc_buffer_free(isc_buffer_t **dynbuffer) { 345 isc_buffer_t *dbuf; 346 347 REQUIRE(dynbuffer != NULL); 348 dbuf = *dynbuffer; 349 *dynbuffer = NULL; /* destroy external reference */ 350 351 isc_buffer_invalidate(dbuf); 352 353 free(dbuf); 354 } 355 356 isc_result_t 357 isc_mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 358 isc_region_t tr; 359 360 isc_buffer_availableregion(target, &tr); 361 if (length > tr.length) 362 return (ISC_R_NOSPACE); 363 memmove(tr.base, base, length); 364 isc_buffer_add(target, length); 365 return (ISC_R_SUCCESS); 366 } 367 368 /* this used to be str_totext() in rdata.c etc. */ 369 isc_result_t 370 isc_str_tobuffer(const char *source, isc_buffer_t *target) { 371 unsigned int l; 372 isc_region_t region; 373 374 isc_buffer_availableregion(target, ®ion); 375 l = strlen(source); 376 377 if (l > region.length) 378 return (ISC_R_NOSPACE); 379 380 memmove(region.base, source, l); 381 isc_buffer_add(target, l); 382 return (ISC_R_SUCCESS); 383 } 384