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