1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1998-2002  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/* $Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp $ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <isc/buffer.h>
25258945Sroberto#include <isc/mem.h>
26258945Sroberto#include <isc/region.h>
27258945Sroberto#include <isc/string.h>
28258945Sroberto#include <isc/util.h>
29258945Sroberto
30258945Srobertovoid
31258945Srobertoisc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) {
32258945Sroberto	/*
33258945Sroberto	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
34258945Sroberto	 * XXXDCL see the comment in buffer.h about base being const.
35258945Sroberto	 */
36258945Sroberto
37258945Sroberto	REQUIRE(b != NULL);
38258945Sroberto
39258945Sroberto	ISC__BUFFER_INIT(b, base, length);
40258945Sroberto}
41258945Sroberto
42258945Srobertovoid
43258945Srobertoisc__buffer_initnull(isc_buffer_t *b) {
44258945Sroberto	/*
45258945Sroberto	 * Initialize a new buffer which has no backing store.  This can
46258945Sroberto	 * later be grown as needed and swapped in place.
47258945Sroberto	 */
48258945Sroberto
49258945Sroberto	ISC__BUFFER_INIT(b, NULL, 0);
50258945Sroberto}
51258945Sroberto
52258945Srobertovoid
53258945Srobertoisc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
54258945Sroberto	/*
55258945Sroberto	 * Re-initialize the buffer enough to reconfigure the base of the
56258945Sroberto	 * buffer.  We will swap in the new buffer, after copying any
57258945Sroberto	 * data we contain into the new buffer and adjusting all of our
58258945Sroberto	 * internal pointers.
59258945Sroberto	 *
60258945Sroberto	 * The buffer must not be smaller than the length of the original
61258945Sroberto	 * buffer.
62258945Sroberto	 */
63258945Sroberto	REQUIRE(b->length <= length);
64258945Sroberto	REQUIRE(base != NULL);
65258945Sroberto
66258945Sroberto	(void)memmove(base, b->base, b->length);
67258945Sroberto	b->base = base;
68258945Sroberto	b->length = length;
69258945Sroberto}
70258945Sroberto
71258945Srobertovoid
72258945Srobertoisc__buffer_invalidate(isc_buffer_t *b) {
73258945Sroberto	/*
74258945Sroberto	 * Make 'b' an invalid buffer.
75258945Sroberto	 */
76258945Sroberto
77258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
78258945Sroberto	REQUIRE(!ISC_LINK_LINKED(b, link));
79258945Sroberto	REQUIRE(b->mctx == NULL);
80258945Sroberto
81258945Sroberto	ISC__BUFFER_INVALIDATE(b);
82258945Sroberto}
83258945Sroberto
84258945Srobertovoid
85258945Srobertoisc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
86258945Sroberto	/*
87258945Sroberto	 * Make 'r' refer to the region of 'b'.
88258945Sroberto	 */
89258945Sroberto
90258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
91258945Sroberto	REQUIRE(r != NULL);
92258945Sroberto
93258945Sroberto	ISC__BUFFER_REGION(b, r);
94258945Sroberto}
95258945Sroberto
96258945Srobertovoid
97258945Srobertoisc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
98258945Sroberto	/*
99258945Sroberto	 * Make 'r' refer to the used region of 'b'.
100258945Sroberto	 */
101258945Sroberto
102258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
103258945Sroberto	REQUIRE(r != NULL);
104258945Sroberto
105258945Sroberto	ISC__BUFFER_USEDREGION(b, r);
106258945Sroberto}
107258945Sroberto
108258945Srobertovoid
109258945Srobertoisc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
110258945Sroberto	/*
111258945Sroberto	 * Make 'r' refer to the available region of 'b'.
112258945Sroberto	 */
113258945Sroberto
114258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
115258945Sroberto	REQUIRE(r != NULL);
116258945Sroberto
117258945Sroberto	ISC__BUFFER_AVAILABLEREGION(b, r);
118258945Sroberto}
119258945Sroberto
120258945Srobertovoid
121258945Srobertoisc__buffer_add(isc_buffer_t *b, unsigned int n) {
122258945Sroberto	/*
123258945Sroberto	 * Increase the 'used' region of 'b' by 'n' bytes.
124258945Sroberto	 */
125258945Sroberto
126258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
127258945Sroberto	REQUIRE(b->used + n <= b->length);
128258945Sroberto
129258945Sroberto	ISC__BUFFER_ADD(b, n);
130258945Sroberto}
131258945Sroberto
132258945Srobertovoid
133258945Srobertoisc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
134258945Sroberto	/*
135258945Sroberto	 * Decrease the 'used' region of 'b' by 'n' bytes.
136258945Sroberto	 */
137258945Sroberto
138258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
139258945Sroberto	REQUIRE(b->used >= n);
140258945Sroberto
141258945Sroberto	ISC__BUFFER_SUBTRACT(b, n);
142258945Sroberto}
143258945Sroberto
144258945Srobertovoid
145258945Srobertoisc__buffer_clear(isc_buffer_t *b) {
146258945Sroberto	/*
147258945Sroberto	 * Make the used region empty.
148258945Sroberto	 */
149258945Sroberto
150258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
151258945Sroberto
152258945Sroberto	ISC__BUFFER_CLEAR(b);
153258945Sroberto}
154258945Sroberto
155258945Srobertovoid
156258945Srobertoisc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
157258945Sroberto	/*
158258945Sroberto	 * Make 'r' refer to the consumed region of 'b'.
159258945Sroberto	 */
160258945Sroberto
161258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
162258945Sroberto	REQUIRE(r != NULL);
163258945Sroberto
164258945Sroberto	ISC__BUFFER_CONSUMEDREGION(b, r);
165258945Sroberto}
166258945Sroberto
167258945Srobertovoid
168258945Srobertoisc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
169258945Sroberto	/*
170258945Sroberto	 * Make 'r' refer to the remaining region of 'b'.
171258945Sroberto	 */
172258945Sroberto
173258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
174258945Sroberto	REQUIRE(r != NULL);
175258945Sroberto
176258945Sroberto	ISC__BUFFER_REMAININGREGION(b, r);
177258945Sroberto}
178258945Sroberto
179258945Srobertovoid
180258945Srobertoisc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
181258945Sroberto	/*
182258945Sroberto	 * Make 'r' refer to the active region of 'b'.
183258945Sroberto	 */
184258945Sroberto
185258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
186258945Sroberto	REQUIRE(r != NULL);
187258945Sroberto
188258945Sroberto	ISC__BUFFER_ACTIVEREGION(b, r);
189258945Sroberto}
190258945Sroberto
191258945Srobertovoid
192258945Srobertoisc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
193258945Sroberto	/*
194258945Sroberto	 * Sets the end of the active region 'n' bytes after current.
195258945Sroberto	 */
196258945Sroberto
197258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
198258945Sroberto	REQUIRE(b->current + n <= b->used);
199258945Sroberto
200258945Sroberto	ISC__BUFFER_SETACTIVE(b, n);
201258945Sroberto}
202258945Sroberto
203258945Srobertovoid
204258945Srobertoisc__buffer_first(isc_buffer_t *b) {
205258945Sroberto	/*
206258945Sroberto	 * Make the consumed region empty.
207258945Sroberto	 */
208258945Sroberto
209258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
210258945Sroberto
211258945Sroberto	ISC__BUFFER_FIRST(b);
212258945Sroberto}
213258945Sroberto
214258945Srobertovoid
215258945Srobertoisc__buffer_forward(isc_buffer_t *b, unsigned int n) {
216258945Sroberto	/*
217258945Sroberto	 * Increase the 'consumed' region of 'b' by 'n' bytes.
218258945Sroberto	 */
219258945Sroberto
220258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
221258945Sroberto	REQUIRE(b->current + n <= b->used);
222258945Sroberto
223258945Sroberto	ISC__BUFFER_FORWARD(b, n);
224258945Sroberto}
225258945Sroberto
226258945Srobertovoid
227258945Srobertoisc__buffer_back(isc_buffer_t *b, unsigned int n) {
228258945Sroberto	/*
229258945Sroberto	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
230258945Sroberto	 */
231258945Sroberto
232258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
233258945Sroberto	REQUIRE(n <= b->current);
234258945Sroberto
235258945Sroberto	ISC__BUFFER_BACK(b, n);
236258945Sroberto}
237258945Sroberto
238258945Srobertovoid
239258945Srobertoisc_buffer_compact(isc_buffer_t *b) {
240258945Sroberto	unsigned int length;
241258945Sroberto	void *src;
242258945Sroberto
243258945Sroberto	/*
244258945Sroberto	 * Compact the used region by moving the remaining region so it occurs
245258945Sroberto	 * at the start of the buffer.  The used region is shrunk by the size
246258945Sroberto	 * of the consumed region, and the consumed region is then made empty.
247258945Sroberto	 */
248258945Sroberto
249258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
250258945Sroberto
251258945Sroberto	src = isc_buffer_current(b);
252258945Sroberto	length = isc_buffer_remaininglength(b);
253258945Sroberto	(void)memmove(b->base, src, (size_t)length);
254258945Sroberto
255258945Sroberto	if (b->active > b->current)
256258945Sroberto		b->active -= b->current;
257258945Sroberto	else
258258945Sroberto		b->active = 0;
259258945Sroberto	b->current = 0;
260258945Sroberto	b->used = length;
261258945Sroberto}
262258945Sroberto
263258945Srobertoisc_uint8_t
264258945Srobertoisc_buffer_getuint8(isc_buffer_t *b) {
265258945Sroberto	unsigned char *cp;
266258945Sroberto	isc_uint8_t result;
267258945Sroberto
268258945Sroberto	/*
269258945Sroberto	 * Read an unsigned 8-bit integer from 'b' and return it.
270258945Sroberto	 */
271258945Sroberto
272258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
273258945Sroberto	REQUIRE(b->used - b->current >= 1);
274258945Sroberto
275258945Sroberto	cp = isc_buffer_current(b);
276258945Sroberto	b->current += 1;
277258945Sroberto	result = ((isc_uint8_t)(cp[0]));
278258945Sroberto
279258945Sroberto	return (result);
280258945Sroberto}
281258945Sroberto
282258945Srobertovoid
283258945Srobertoisc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
284258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
285258945Sroberto	REQUIRE(b->used + 1 <= b->length);
286258945Sroberto
287258945Sroberto	ISC__BUFFER_PUTUINT8(b, val);
288258945Sroberto}
289258945Sroberto
290258945Srobertoisc_uint16_t
291258945Srobertoisc_buffer_getuint16(isc_buffer_t *b) {
292258945Sroberto	unsigned char *cp;
293258945Sroberto	isc_uint16_t result;
294258945Sroberto
295258945Sroberto	/*
296258945Sroberto	 * Read an unsigned 16-bit integer in network byte order from 'b',
297258945Sroberto	 * convert it to host byte order, and return it.
298258945Sroberto	 */
299258945Sroberto
300258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
301258945Sroberto	REQUIRE(b->used - b->current >= 2);
302258945Sroberto
303258945Sroberto	cp = isc_buffer_current(b);
304258945Sroberto	b->current += 2;
305258945Sroberto	result = ((unsigned int)(cp[0])) << 8;
306258945Sroberto	result |= ((unsigned int)(cp[1]));
307258945Sroberto
308258945Sroberto	return (result);
309258945Sroberto}
310258945Sroberto
311258945Srobertovoid
312258945Srobertoisc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
313258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
314258945Sroberto	REQUIRE(b->used + 2 <= b->length);
315258945Sroberto
316258945Sroberto	ISC__BUFFER_PUTUINT16(b, val);
317258945Sroberto}
318258945Sroberto
319258945Srobertovoid
320258945Srobertoisc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
321258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
322258945Sroberto	REQUIRE(b->used + 3 <= b->length);
323258945Sroberto
324258945Sroberto	ISC__BUFFER_PUTUINT24(b, val);
325258945Sroberto}
326258945Sroberto
327258945Srobertoisc_uint32_t
328258945Srobertoisc_buffer_getuint32(isc_buffer_t *b) {
329258945Sroberto	unsigned char *cp;
330258945Sroberto	isc_uint32_t result;
331258945Sroberto
332258945Sroberto	/*
333258945Sroberto	 * Read an unsigned 32-bit integer in network byte order from 'b',
334258945Sroberto	 * convert it to host byte order, and return it.
335258945Sroberto	 */
336258945Sroberto
337258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
338258945Sroberto	REQUIRE(b->used - b->current >= 4);
339258945Sroberto
340258945Sroberto	cp = isc_buffer_current(b);
341258945Sroberto	b->current += 4;
342258945Sroberto	result = ((unsigned int)(cp[0])) << 24;
343258945Sroberto	result |= ((unsigned int)(cp[1])) << 16;
344258945Sroberto	result |= ((unsigned int)(cp[2])) << 8;
345258945Sroberto	result |= ((unsigned int)(cp[3]));
346258945Sroberto
347258945Sroberto	return (result);
348258945Sroberto}
349258945Sroberto
350258945Srobertovoid
351258945Srobertoisc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
352258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
353258945Sroberto	REQUIRE(b->used + 4 <= b->length);
354258945Sroberto
355258945Sroberto	ISC__BUFFER_PUTUINT32(b, val);
356258945Sroberto}
357258945Sroberto
358258945Srobertoisc_uint64_t
359258945Srobertoisc_buffer_getuint48(isc_buffer_t *b) {
360258945Sroberto	unsigned char *cp;
361258945Sroberto	isc_uint64_t result;
362258945Sroberto
363258945Sroberto	/*
364258945Sroberto	 * Read an unsigned 48-bit integer in network byte order from 'b',
365258945Sroberto	 * convert it to host byte order, and return it.
366258945Sroberto	 */
367258945Sroberto
368258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
369258945Sroberto	REQUIRE(b->used - b->current >= 6);
370258945Sroberto
371258945Sroberto	cp = isc_buffer_current(b);
372258945Sroberto	b->current += 6;
373258945Sroberto	result = ((isc_int64_t)(cp[0])) << 40;
374258945Sroberto	result |= ((isc_int64_t)(cp[1])) << 32;
375258945Sroberto	result |= ((isc_int64_t)(cp[2])) << 24;
376258945Sroberto	result |= ((isc_int64_t)(cp[3])) << 16;
377258945Sroberto	result |= ((isc_int64_t)(cp[4])) << 8;
378258945Sroberto	result |= ((isc_int64_t)(cp[5]));
379258945Sroberto
380258945Sroberto	return (result);
381258945Sroberto}
382258945Sroberto
383258945Srobertovoid
384258945Srobertoisc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
385258945Sroberto	isc_uint16_t valhi;
386258945Sroberto	isc_uint32_t vallo;
387258945Sroberto
388258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
389258945Sroberto	REQUIRE(b->used + 6 <= b->length);
390258945Sroberto
391258945Sroberto	valhi = (isc_uint16_t)(val >> 32);
392258945Sroberto	vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
393258945Sroberto	ISC__BUFFER_PUTUINT16(b, valhi);
394258945Sroberto	ISC__BUFFER_PUTUINT32(b, vallo);
395258945Sroberto}
396258945Sroberto
397258945Srobertovoid
398258945Srobertoisc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
399258945Sroberto		   unsigned int length)
400258945Sroberto{
401258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
402258945Sroberto	REQUIRE(b->used + length <= b->length);
403258945Sroberto
404258945Sroberto	ISC__BUFFER_PUTMEM(b, base, length);
405258945Sroberto}
406258945Sroberto
407258945Srobertovoid
408258945Srobertoisc__buffer_putstr(isc_buffer_t *b, const char *source) {
409293893Sglebius	size_t l;
410258945Sroberto	unsigned char *cp;
411258945Sroberto
412258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
413258945Sroberto	REQUIRE(source != NULL);
414258945Sroberto
415258945Sroberto	/*
416258945Sroberto	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
417258945Sroberto	 */
418258945Sroberto	l = strlen(source);
419258945Sroberto
420258945Sroberto	REQUIRE(l <= isc_buffer_availablelength(b));
421258945Sroberto
422258945Sroberto	cp = isc_buffer_used(b);
423258945Sroberto	memcpy(cp, source, l);
424293893Sglebius	b->used += (u_int)l; /* checked above - no overflow here */
425258945Sroberto}
426258945Sroberto
427258945Srobertoisc_result_t
428258945Srobertoisc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
429258945Sroberto	unsigned char *base;
430258945Sroberto	unsigned int available;
431258945Sroberto
432258945Sroberto	REQUIRE(ISC_BUFFER_VALID(b));
433258945Sroberto	REQUIRE(r != NULL);
434258945Sroberto
435258945Sroberto	/*
436258945Sroberto	 * XXXDCL
437258945Sroberto	 */
438258945Sroberto	base = isc_buffer_used(b);
439258945Sroberto	available = isc_buffer_availablelength(b);
440258945Sroberto	if (r->length > available)
441258945Sroberto		return (ISC_R_NOSPACE);
442258945Sroberto	memcpy(base, r->base, r->length);
443258945Sroberto	b->used += r->length;
444258945Sroberto
445258945Sroberto	return (ISC_R_SUCCESS);
446258945Sroberto}
447258945Sroberto
448258945Srobertoisc_result_t
449258945Srobertoisc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
450258945Sroberto		    unsigned int length)
451258945Sroberto{
452258945Sroberto	isc_buffer_t *dbuf;
453258945Sroberto
454258945Sroberto	REQUIRE(dynbuffer != NULL);
455258945Sroberto	REQUIRE(*dynbuffer == NULL);
456258945Sroberto
457258945Sroberto	dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
458258945Sroberto	if (dbuf == NULL)
459258945Sroberto		return (ISC_R_NOMEMORY);
460258945Sroberto
461258945Sroberto	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
462258945Sroberto			length);
463258945Sroberto	dbuf->mctx = mctx;
464258945Sroberto
465258945Sroberto	*dynbuffer = dbuf;
466258945Sroberto
467258945Sroberto	return (ISC_R_SUCCESS);
468258945Sroberto}
469258945Sroberto
470258945Srobertovoid
471258945Srobertoisc_buffer_free(isc_buffer_t **dynbuffer) {
472258945Sroberto	unsigned int real_length;
473258945Sroberto	isc_buffer_t *dbuf;
474258945Sroberto	isc_mem_t *mctx;
475258945Sroberto
476258945Sroberto	REQUIRE(dynbuffer != NULL);
477258945Sroberto	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
478258945Sroberto	REQUIRE((*dynbuffer)->mctx != NULL);
479258945Sroberto
480258945Sroberto	dbuf = *dynbuffer;
481258945Sroberto	*dynbuffer = NULL;	/* destroy external reference */
482258945Sroberto
483258945Sroberto	real_length = dbuf->length + sizeof(isc_buffer_t);
484258945Sroberto	mctx = dbuf->mctx;
485258945Sroberto	dbuf->mctx = NULL;
486258945Sroberto	isc_buffer_invalidate(dbuf);
487258945Sroberto
488258945Sroberto	isc_mem_put(mctx, dbuf, real_length);
489258945Sroberto}
490