buffer.c revision 170223
1/*
2 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1998-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and 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.40.18.2 2005/04/29 00:16:44 marka 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_invalidate(isc_buffer_t *b) {
44	/*
45	 * Make 'b' an invalid buffer.
46	 */
47
48	REQUIRE(ISC_BUFFER_VALID(b));
49	REQUIRE(!ISC_LINK_LINKED(b, link));
50	REQUIRE(b->mctx == NULL);
51
52	ISC__BUFFER_INVALIDATE(b);
53}
54
55void
56isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
57	/*
58	 * Make 'r' refer to the region of 'b'.
59	 */
60
61	REQUIRE(ISC_BUFFER_VALID(b));
62	REQUIRE(r != NULL);
63
64	ISC__BUFFER_REGION(b, r);
65}
66
67void
68isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
69	/*
70	 * Make 'r' refer to the used region of 'b'.
71	 */
72
73	REQUIRE(ISC_BUFFER_VALID(b));
74	REQUIRE(r != NULL);
75
76	ISC__BUFFER_USEDREGION(b, r);
77}
78
79void
80isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
81	/*
82	 * Make 'r' refer to the available region of 'b'.
83	 */
84
85	REQUIRE(ISC_BUFFER_VALID(b));
86	REQUIRE(r != NULL);
87
88	ISC__BUFFER_AVAILABLEREGION(b, r);
89}
90
91void
92isc__buffer_add(isc_buffer_t *b, unsigned int n) {
93	/*
94	 * Increase the 'used' region of 'b' by 'n' bytes.
95	 */
96
97	REQUIRE(ISC_BUFFER_VALID(b));
98	REQUIRE(b->used + n <= b->length);
99
100	ISC__BUFFER_ADD(b, n);
101}
102
103void
104isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
105	/*
106	 * Decrease the 'used' region of 'b' by 'n' bytes.
107	 */
108
109	REQUIRE(ISC_BUFFER_VALID(b));
110	REQUIRE(b->used >= n);
111
112	ISC__BUFFER_SUBTRACT(b, n);
113}
114
115void
116isc__buffer_clear(isc_buffer_t *b) {
117	/*
118	 * Make the used region empty.
119	 */
120
121	REQUIRE(ISC_BUFFER_VALID(b));
122
123	ISC__BUFFER_CLEAR(b);
124}
125
126void
127isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
128	/*
129	 * Make 'r' refer to the consumed region of 'b'.
130	 */
131
132	REQUIRE(ISC_BUFFER_VALID(b));
133	REQUIRE(r != NULL);
134
135	ISC__BUFFER_CONSUMEDREGION(b, r);
136}
137
138void
139isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
140	/*
141	 * Make 'r' refer to the remaining region of 'b'.
142	 */
143
144	REQUIRE(ISC_BUFFER_VALID(b));
145	REQUIRE(r != NULL);
146
147	ISC__BUFFER_REMAININGREGION(b, r);
148}
149
150void
151isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
152	/*
153	 * Make 'r' refer to the active region of 'b'.
154	 */
155
156	REQUIRE(ISC_BUFFER_VALID(b));
157	REQUIRE(r != NULL);
158
159	ISC__BUFFER_ACTIVEREGION(b, r);
160}
161
162void
163isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
164	/*
165	 * Sets the end of the active region 'n' bytes after current.
166	 */
167
168	REQUIRE(ISC_BUFFER_VALID(b));
169	REQUIRE(b->current + n <= b->used);
170
171	ISC__BUFFER_SETACTIVE(b, n);
172}
173
174void
175isc__buffer_first(isc_buffer_t *b) {
176	/*
177	 * Make the consumed region empty.
178	 */
179
180	REQUIRE(ISC_BUFFER_VALID(b));
181
182	ISC__BUFFER_FIRST(b);
183}
184
185void
186isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
187	/*
188	 * Increase the 'consumed' region of 'b' by 'n' bytes.
189	 */
190
191	REQUIRE(ISC_BUFFER_VALID(b));
192	REQUIRE(b->current + n <= b->used);
193
194	ISC__BUFFER_FORWARD(b, n);
195}
196
197void
198isc__buffer_back(isc_buffer_t *b, unsigned int n) {
199	/*
200	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
201	 */
202
203	REQUIRE(ISC_BUFFER_VALID(b));
204	REQUIRE(n <= b->current);
205
206	ISC__BUFFER_BACK(b, n);
207}
208
209void
210isc_buffer_compact(isc_buffer_t *b) {
211	unsigned int length;
212	void *src;
213
214	/*
215	 * Compact the used region by moving the remaining region so it occurs
216	 * at the start of the buffer.  The used region is shrunk by the size
217	 * of the consumed region, and the consumed region is then made empty.
218	 */
219
220	REQUIRE(ISC_BUFFER_VALID(b));
221
222	src = isc_buffer_current(b);
223	length = isc_buffer_remaininglength(b);
224	(void)memmove(b->base, src, (size_t)length);
225
226	if (b->active > b->current)
227		b->active -= b->current;
228	else
229		b->active = 0;
230	b->current = 0;
231	b->used = length;
232}
233
234isc_uint8_t
235isc_buffer_getuint8(isc_buffer_t *b) {
236	unsigned char *cp;
237	isc_uint8_t result;
238
239	/*
240	 * Read an unsigned 8-bit integer from 'b' and return it.
241	 */
242
243	REQUIRE(ISC_BUFFER_VALID(b));
244	REQUIRE(b->used - b->current >= 1);
245
246	cp = isc_buffer_current(b);
247	b->current += 1;
248	result = ((isc_uint8_t)(cp[0]));
249
250	return (result);
251}
252
253void
254isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
255	REQUIRE(ISC_BUFFER_VALID(b));
256	REQUIRE(b->used + 1 <= b->length);
257
258	ISC__BUFFER_PUTUINT8(b, val);
259}
260
261isc_uint16_t
262isc_buffer_getuint16(isc_buffer_t *b) {
263	unsigned char *cp;
264	isc_uint16_t result;
265
266	/*
267	 * Read an unsigned 16-bit integer in network byte order from 'b',
268	 * convert it to host byte order, and return it.
269	 */
270
271	REQUIRE(ISC_BUFFER_VALID(b));
272	REQUIRE(b->used - b->current >= 2);
273
274	cp = isc_buffer_current(b);
275	b->current += 2;
276	result = ((unsigned int)(cp[0])) << 8;
277	result |= ((unsigned int)(cp[1]));
278
279	return (result);
280}
281
282void
283isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
284	REQUIRE(ISC_BUFFER_VALID(b));
285	REQUIRE(b->used + 2 <= b->length);
286
287	ISC__BUFFER_PUTUINT16(b, val);
288}
289
290isc_uint32_t
291isc_buffer_getuint32(isc_buffer_t *b) {
292	unsigned char *cp;
293	isc_uint32_t result;
294
295	/*
296	 * Read an unsigned 32-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 >= 4);
302
303	cp = isc_buffer_current(b);
304	b->current += 4;
305	result = ((unsigned int)(cp[0])) << 24;
306	result |= ((unsigned int)(cp[1])) << 16;
307	result |= ((unsigned int)(cp[2])) << 8;
308	result |= ((unsigned int)(cp[3]));
309
310	return (result);
311}
312
313void
314isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
315	REQUIRE(ISC_BUFFER_VALID(b));
316	REQUIRE(b->used + 4 <= b->length);
317
318	ISC__BUFFER_PUTUINT32(b, val);
319}
320
321void
322isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
323		   unsigned int length)
324{
325	REQUIRE(ISC_BUFFER_VALID(b));
326	REQUIRE(b->used + length <= b->length);
327
328	ISC__BUFFER_PUTMEM(b, base, length);
329}
330
331void
332isc__buffer_putstr(isc_buffer_t *b, const char *source) {
333	unsigned int l;
334	unsigned char *cp;
335
336	REQUIRE(ISC_BUFFER_VALID(b));
337	REQUIRE(source != NULL);
338
339	/*
340	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
341	 */
342	l = strlen(source);
343
344	REQUIRE(l <= isc_buffer_availablelength(b));
345
346	cp = isc_buffer_used(b);
347	memcpy(cp, source, l);
348	b->used += l;
349}
350
351isc_result_t
352isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
353	unsigned char *base;
354	unsigned int available;
355
356	REQUIRE(ISC_BUFFER_VALID(b));
357	REQUIRE(r != NULL);
358
359	/*
360	 * XXXDCL
361	 */
362	base = isc_buffer_used(b);
363	available = isc_buffer_availablelength(b);
364        if (r->length > available)
365		return (ISC_R_NOSPACE);
366	memcpy(base, r->base, r->length);
367	b->used += r->length;
368
369	return (ISC_R_SUCCESS);
370}
371
372isc_result_t
373isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
374		    unsigned int length)
375{
376	isc_buffer_t *dbuf;
377
378	REQUIRE(dynbuffer != NULL);
379	REQUIRE(*dynbuffer == NULL);
380
381	dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
382	if (dbuf == NULL)
383		return (ISC_R_NOMEMORY);
384
385	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
386			length);
387	dbuf->mctx = mctx;
388
389	*dynbuffer = dbuf;
390
391	return (ISC_R_SUCCESS);
392}
393
394void
395isc_buffer_free(isc_buffer_t **dynbuffer) {
396	unsigned int real_length;
397	isc_buffer_t *dbuf;
398	isc_mem_t *mctx;
399
400	REQUIRE(dynbuffer != NULL);
401	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
402	REQUIRE((*dynbuffer)->mctx != NULL);
403
404	dbuf = *dynbuffer;
405	*dynbuffer = NULL;	/* destroy external reference */
406
407	real_length = dbuf->length + sizeof(isc_buffer_t);
408	mctx = dbuf->mctx;
409	dbuf->mctx = NULL;
410	isc_buffer_invalidate(dbuf);
411
412	isc_mem_put(mctx, dbuf, real_length);
413}
414