xref: /freebsd/contrib/ntp/libntp/lib/isc/buffer.c (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
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 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 	REQUIRE(b != NULL);
38 
39 	ISC__BUFFER_INIT(b, base, length);
40 }
41 
42 void
43 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 	ISC__BUFFER_INIT(b, NULL, 0);
50 }
51 
52 void
53 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 	REQUIRE(b->length <= length);
64 	REQUIRE(base != NULL);
65 
66 	(void)memmove(base, b->base, b->length);
67 	b->base = base;
68 	b->length = length;
69 }
70 
71 void
72 isc__buffer_invalidate(isc_buffer_t *b) {
73 	/*
74 	 * Make 'b' an invalid buffer.
75 	 */
76 
77 	REQUIRE(ISC_BUFFER_VALID(b));
78 	REQUIRE(!ISC_LINK_LINKED(b, link));
79 	REQUIRE(b->mctx == NULL);
80 
81 	ISC__BUFFER_INVALIDATE(b);
82 }
83 
84 void
85 isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
86 	/*
87 	 * Make 'r' refer to the region of 'b'.
88 	 */
89 
90 	REQUIRE(ISC_BUFFER_VALID(b));
91 	REQUIRE(r != NULL);
92 
93 	ISC__BUFFER_REGION(b, r);
94 }
95 
96 void
97 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 	REQUIRE(ISC_BUFFER_VALID(b));
103 	REQUIRE(r != NULL);
104 
105 	ISC__BUFFER_USEDREGION(b, r);
106 }
107 
108 void
109 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 	REQUIRE(ISC_BUFFER_VALID(b));
115 	REQUIRE(r != NULL);
116 
117 	ISC__BUFFER_AVAILABLEREGION(b, r);
118 }
119 
120 void
121 isc__buffer_add(isc_buffer_t *b, unsigned int n) {
122 	/*
123 	 * Increase the 'used' region of 'b' by 'n' bytes.
124 	 */
125 
126 	REQUIRE(ISC_BUFFER_VALID(b));
127 	REQUIRE(b->used + n <= b->length);
128 
129 	ISC__BUFFER_ADD(b, n);
130 }
131 
132 void
133 isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
134 	/*
135 	 * Decrease the 'used' region of 'b' by 'n' bytes.
136 	 */
137 
138 	REQUIRE(ISC_BUFFER_VALID(b));
139 	REQUIRE(b->used >= n);
140 
141 	ISC__BUFFER_SUBTRACT(b, n);
142 }
143 
144 void
145 isc__buffer_clear(isc_buffer_t *b) {
146 	/*
147 	 * Make the used region empty.
148 	 */
149 
150 	REQUIRE(ISC_BUFFER_VALID(b));
151 
152 	ISC__BUFFER_CLEAR(b);
153 }
154 
155 void
156 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 	REQUIRE(ISC_BUFFER_VALID(b));
162 	REQUIRE(r != NULL);
163 
164 	ISC__BUFFER_CONSUMEDREGION(b, r);
165 }
166 
167 void
168 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 	REQUIRE(ISC_BUFFER_VALID(b));
174 	REQUIRE(r != NULL);
175 
176 	ISC__BUFFER_REMAININGREGION(b, r);
177 }
178 
179 void
180 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 	REQUIRE(ISC_BUFFER_VALID(b));
186 	REQUIRE(r != NULL);
187 
188 	ISC__BUFFER_ACTIVEREGION(b, r);
189 }
190 
191 void
192 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 	REQUIRE(ISC_BUFFER_VALID(b));
198 	REQUIRE(b->current + n <= b->used);
199 
200 	ISC__BUFFER_SETACTIVE(b, n);
201 }
202 
203 void
204 isc__buffer_first(isc_buffer_t *b) {
205 	/*
206 	 * Make the consumed region empty.
207 	 */
208 
209 	REQUIRE(ISC_BUFFER_VALID(b));
210 
211 	ISC__BUFFER_FIRST(b);
212 }
213 
214 void
215 isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
216 	/*
217 	 * Increase the 'consumed' region of 'b' by 'n' bytes.
218 	 */
219 
220 	REQUIRE(ISC_BUFFER_VALID(b));
221 	REQUIRE(b->current + n <= b->used);
222 
223 	ISC__BUFFER_FORWARD(b, n);
224 }
225 
226 void
227 isc__buffer_back(isc_buffer_t *b, unsigned int n) {
228 	/*
229 	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
230 	 */
231 
232 	REQUIRE(ISC_BUFFER_VALID(b));
233 	REQUIRE(n <= b->current);
234 
235 	ISC__BUFFER_BACK(b, n);
236 }
237 
238 void
239 isc_buffer_compact(isc_buffer_t *b) {
240 	unsigned int length;
241 	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 	REQUIRE(ISC_BUFFER_VALID(b));
250 
251 	src = isc_buffer_current(b);
252 	length = isc_buffer_remaininglength(b);
253 	(void)memmove(b->base, src, (size_t)length);
254 
255 	if (b->active > b->current)
256 		b->active -= b->current;
257 	else
258 		b->active = 0;
259 	b->current = 0;
260 	b->used = length;
261 }
262 
263 isc_uint8_t
264 isc_buffer_getuint8(isc_buffer_t *b) {
265 	unsigned char *cp;
266 	isc_uint8_t result;
267 
268 	/*
269 	 * Read an unsigned 8-bit integer from 'b' and return it.
270 	 */
271 
272 	REQUIRE(ISC_BUFFER_VALID(b));
273 	REQUIRE(b->used - b->current >= 1);
274 
275 	cp = isc_buffer_current(b);
276 	b->current += 1;
277 	result = ((isc_uint8_t)(cp[0]));
278 
279 	return (result);
280 }
281 
282 void
283 isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
284 	REQUIRE(ISC_BUFFER_VALID(b));
285 	REQUIRE(b->used + 1 <= b->length);
286 
287 	ISC__BUFFER_PUTUINT8(b, val);
288 }
289 
290 isc_uint16_t
291 isc_buffer_getuint16(isc_buffer_t *b) {
292 	unsigned char *cp;
293 	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 	REQUIRE(ISC_BUFFER_VALID(b));
301 	REQUIRE(b->used - b->current >= 2);
302 
303 	cp = isc_buffer_current(b);
304 	b->current += 2;
305 	result = ((unsigned int)(cp[0])) << 8;
306 	result |= ((unsigned int)(cp[1]));
307 
308 	return (result);
309 }
310 
311 void
312 isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
313 	REQUIRE(ISC_BUFFER_VALID(b));
314 	REQUIRE(b->used + 2 <= b->length);
315 
316 	ISC__BUFFER_PUTUINT16(b, val);
317 }
318 
319 void
320 isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
321 	REQUIRE(ISC_BUFFER_VALID(b));
322 	REQUIRE(b->used + 3 <= b->length);
323 
324 	ISC__BUFFER_PUTUINT24(b, val);
325 }
326 
327 isc_uint32_t
328 isc_buffer_getuint32(isc_buffer_t *b) {
329 	unsigned char *cp;
330 	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 	REQUIRE(ISC_BUFFER_VALID(b));
338 	REQUIRE(b->used - b->current >= 4);
339 
340 	cp = isc_buffer_current(b);
341 	b->current += 4;
342 	result = ((unsigned int)(cp[0])) << 24;
343 	result |= ((unsigned int)(cp[1])) << 16;
344 	result |= ((unsigned int)(cp[2])) << 8;
345 	result |= ((unsigned int)(cp[3]));
346 
347 	return (result);
348 }
349 
350 void
351 isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
352 	REQUIRE(ISC_BUFFER_VALID(b));
353 	REQUIRE(b->used + 4 <= b->length);
354 
355 	ISC__BUFFER_PUTUINT32(b, val);
356 }
357 
358 isc_uint64_t
359 isc_buffer_getuint48(isc_buffer_t *b) {
360 	unsigned char *cp;
361 	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 	REQUIRE(ISC_BUFFER_VALID(b));
369 	REQUIRE(b->used - b->current >= 6);
370 
371 	cp = isc_buffer_current(b);
372 	b->current += 6;
373 	result = ((isc_int64_t)(cp[0])) << 40;
374 	result |= ((isc_int64_t)(cp[1])) << 32;
375 	result |= ((isc_int64_t)(cp[2])) << 24;
376 	result |= ((isc_int64_t)(cp[3])) << 16;
377 	result |= ((isc_int64_t)(cp[4])) << 8;
378 	result |= ((isc_int64_t)(cp[5]));
379 
380 	return (result);
381 }
382 
383 void
384 isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
385 	isc_uint16_t valhi;
386 	isc_uint32_t vallo;
387 
388 	REQUIRE(ISC_BUFFER_VALID(b));
389 	REQUIRE(b->used + 6 <= b->length);
390 
391 	valhi = (isc_uint16_t)(val >> 32);
392 	vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
393 	ISC__BUFFER_PUTUINT16(b, valhi);
394 	ISC__BUFFER_PUTUINT32(b, vallo);
395 }
396 
397 void
398 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
399 		   unsigned int length)
400 {
401 	REQUIRE(ISC_BUFFER_VALID(b));
402 	REQUIRE(b->used + length <= b->length);
403 
404 	ISC__BUFFER_PUTMEM(b, base, length);
405 }
406 
407 void
408 isc__buffer_putstr(isc_buffer_t *b, const char *source) {
409 	size_t l;
410 	unsigned char *cp;
411 
412 	REQUIRE(ISC_BUFFER_VALID(b));
413 	REQUIRE(source != NULL);
414 
415 	/*
416 	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
417 	 */
418 	l = strlen(source);
419 
420 	REQUIRE(l <= isc_buffer_availablelength(b));
421 
422 	cp = isc_buffer_used(b);
423 	memcpy(cp, source, l);
424 	b->used += (u_int)l; /* checked above - no overflow here */
425 }
426 
427 isc_result_t
428 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
429 	unsigned char *base;
430 	unsigned int available;
431 
432 	REQUIRE(ISC_BUFFER_VALID(b));
433 	REQUIRE(r != NULL);
434 
435 	/*
436 	 * XXXDCL
437 	 */
438 	base = isc_buffer_used(b);
439 	available = isc_buffer_availablelength(b);
440 	if (r->length > available)
441 		return (ISC_R_NOSPACE);
442 	memcpy(base, r->base, r->length);
443 	b->used += r->length;
444 
445 	return (ISC_R_SUCCESS);
446 }
447 
448 isc_result_t
449 isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
450 		    unsigned int length)
451 {
452 	isc_buffer_t *dbuf;
453 
454 	REQUIRE(dynbuffer != NULL);
455 	REQUIRE(*dynbuffer == NULL);
456 
457 	dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
458 	if (dbuf == NULL)
459 		return (ISC_R_NOMEMORY);
460 
461 	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
462 			length);
463 	dbuf->mctx = mctx;
464 
465 	*dynbuffer = dbuf;
466 
467 	return (ISC_R_SUCCESS);
468 }
469 
470 void
471 isc_buffer_free(isc_buffer_t **dynbuffer) {
472 	unsigned int real_length;
473 	isc_buffer_t *dbuf;
474 	isc_mem_t *mctx;
475 
476 	REQUIRE(dynbuffer != NULL);
477 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
478 	REQUIRE((*dynbuffer)->mctx != NULL);
479 
480 	dbuf = *dynbuffer;
481 	*dynbuffer = NULL;	/* destroy external reference */
482 
483 	real_length = dbuf->length + sizeof(isc_buffer_t);
484 	mctx = dbuf->mctx;
485 	dbuf->mctx = NULL;
486 	isc_buffer_invalidate(dbuf);
487 
488 	isc_mem_put(mctx, dbuf, real_length);
489 }
490