buffer.c revision 290001
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
30void
31isc__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
42void
43isc__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
52void
53isc_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
71void
72isc__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
84void
85isc__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
96void
97isc__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
108void
109isc__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
120void
121isc__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
132void
133isc__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
144void
145isc__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
155void
156isc__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
167void
168isc__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
179void
180isc__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
191void
192isc__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
203void
204isc__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
214void
215isc__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
226void
227isc__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
238void
239isc_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
263isc_uint8_t
264isc_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
282void
283isc__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
290isc_uint16_t
291isc_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
311void
312isc__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
319void
320isc__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
327isc_uint32_t
328isc_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
350void
351isc__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
358isc_uint64_t
359isc_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
383void
384isc__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
397void
398isc__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
407void
408isc__buffer_putstr(isc_buffer_t *b, const char *source) {
409	unsigned int 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 += l;
425}
426
427isc_result_t
428isc_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
448isc_result_t
449isc_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
470void
471isc_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