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