buffer.c 8.26 KB
Newer Older
Bob Halley's avatar
Bob Halley committed
1
/*
David Lawrence's avatar
David Lawrence committed
2
 * Copyright (C) 1998-2000  Internet Software Consortium.
3
 *
Bob Halley's avatar
Bob Halley committed
4
5
6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
7
 *
8
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
Bob Halley committed
16
 */
Bob Halley's avatar
Bob Halley committed
17

18
/* $Id: buffer.c,v 1.35 2000/08/17 02:09:11 bwelling Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Bob Halley's avatar
Bob Halley committed
20
21
#include <config.h>

Bob Halley's avatar
Bob Halley committed
22
#include <isc/buffer.h>
23
24
#include <isc/mem.h>
#include <isc/region.h>
25
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
26
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
27
28

void
David Lawrence's avatar
David Lawrence committed
29
isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) {
Bob Halley's avatar
Bob Halley committed
30
	/*
David Lawrence's avatar
David Lawrence committed
31
32
	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
	 * XXXDCL see the comment in buffer.h about base being const.
Bob Halley's avatar
Bob Halley committed
33
34
	 */

35
	REQUIRE(b != NULL);
Bob Halley's avatar
Bob Halley committed
36

37
	ISC__BUFFER_INIT(b, base, length);
38
39
40
}

void
41
isc__buffer_invalidate(isc_buffer_t *b) {
42
43
44
45
	/*
	 * Make 'b' an invalid buffer.
	 */

46
	REQUIRE(ISC_BUFFER_VALID(b));
47
48
	REQUIRE(!ISC_LINK_LINKED(b, link));
	REQUIRE(b->mctx == NULL);
49

50
	ISC__BUFFER_INVALIDATE(b);
51
52
}

Bob Halley's avatar
Bob Halley committed
53
void
54
isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
55
56
57
58
	/*
	 * Make 'r' refer to the region of 'b'.
	 */

59
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
60
61
	REQUIRE(r != NULL);

62
	ISC__BUFFER_REGION(b, r);
Bob Halley's avatar
Bob Halley committed
63
64
65
}

void
66
isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
67
68
69
70
	/*
	 * Make 'r' refer to the used region of 'b'.
	 */

71
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
72
73
	REQUIRE(r != NULL);

74
	ISC__BUFFER_USEDREGION(b, r);
Bob Halley's avatar
Bob Halley committed
75
76
77
}

void
78
isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
79
80
81
82
	/*
	 * Make 'r' refer to the available region of 'b'.
	 */

83
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
84
85
	REQUIRE(r != NULL);

86
	ISC__BUFFER_AVAILABLEREGION(b, r);
Bob Halley's avatar
Bob Halley committed
87
88
89
}

void
90
isc__buffer_add(isc_buffer_t *b, unsigned int n) {
Bob Halley's avatar
Bob Halley committed
91
92
93
94
	/*
	 * Increase the 'used' region of 'b' by 'n' bytes.
	 */

95
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
96
97
	REQUIRE(b->used + n <= b->length);

98
	ISC__BUFFER_ADD(b, n);
Bob Halley's avatar
Bob Halley committed
99
100
101
}

void
102
isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
Bob Halley's avatar
Bob Halley committed
103
104
105
106
	/*
	 * Decrease the 'used' region of 'b' by 'n' bytes.
	 */

107
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
108
109
	REQUIRE(b->used >= n);

110
	ISC__BUFFER_SUBTRACT(b, n);
Bob Halley's avatar
Bob Halley committed
111
112
113
}

void
114
isc__buffer_clear(isc_buffer_t *b) {
Bob Halley's avatar
Bob Halley committed
115
116
117
118
	/*
	 * Make the used region empty.
	 */

119
	REQUIRE(ISC_BUFFER_VALID(b));
120

121
	ISC__BUFFER_CLEAR(b);
Bob Halley's avatar
Bob Halley committed
122
123
124
}

void
125
isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
126
127
128
129
	/*
	 * Make 'r' refer to the consumed region of 'b'.
	 */

130
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
131
132
	REQUIRE(r != NULL);

133
	ISC__BUFFER_CONSUMEDREGION(b, r);
Bob Halley's avatar
Bob Halley committed
134
135
136
}

void
137
isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
138
139
140
141
	/*
	 * Make 'r' refer to the remaining region of 'b'.
	 */

142
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
143
144
	REQUIRE(r != NULL);

145
	ISC__BUFFER_REMAININGREGION(b, r);
Bob Halley's avatar
Bob Halley committed
146
147
}

148
void
149
isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
150
151
152
153
	/*
	 * Make 'r' refer to the active region of 'b'.
	 */

154
	REQUIRE(ISC_BUFFER_VALID(b));
155
156
	REQUIRE(r != NULL);

157
	ISC__BUFFER_ACTIVEREGION(b, r);
158
159
160
}

void
161
isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
162
163
164
165
	/*
	 * Sets the end of the active region 'n' bytes after current.
	 */

166
	REQUIRE(ISC_BUFFER_VALID(b));
167
	REQUIRE(b->current + n <= b->used);
168

169
	ISC__BUFFER_SETACTIVE(b, n);
170
171
}

Bob Halley's avatar
Bob Halley committed
172
void
173
isc__buffer_first(isc_buffer_t *b) {
Bob Halley's avatar
Bob Halley committed
174
175
176
177
	/*
	 * Make the consumed region empty.
	 */

178
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
179

180
	ISC__BUFFER_FIRST(b);
Bob Halley's avatar
Bob Halley committed
181
182
183
}

void
184
isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
Bob Halley's avatar
Bob Halley committed
185
	/*
186
	 * Increase the 'consumed' region of 'b' by 'n' bytes.
Bob Halley's avatar
Bob Halley committed
187
188
	 */

189
	REQUIRE(ISC_BUFFER_VALID(b));
190
	REQUIRE(b->current + n <= b->used);
Bob Halley's avatar
Bob Halley committed
191

192
	ISC__BUFFER_FORWARD(b, n);
Bob Halley's avatar
Bob Halley committed
193
194
195
}

void
196
isc__buffer_back(isc_buffer_t *b, unsigned int n) {
Bob Halley's avatar
Bob Halley committed
197
198
199
200
	/*
	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
	 */

201
	REQUIRE(ISC_BUFFER_VALID(b));
202
	REQUIRE(n <= b->current);
Bob Halley's avatar
Bob Halley committed
203

204
	ISC__BUFFER_BACK(b, n);
Bob Halley's avatar
Bob Halley committed
205
206
207
}

void
Bob Halley's avatar
Bob Halley committed
208
isc_buffer_compact(isc_buffer_t *b) {
Bob Halley's avatar
Bob Halley committed
209
	unsigned int length;
210
	void *src;
Bob Halley's avatar
Bob Halley committed
211
212
213
214
215
216
217

	/*
	 * Compact the used region by moving the remaining region so it occurs
	 * at the start of the buffer.  The used region is shrunk by the size
	 * of the consumed region, and the consumed region is then made empty.
	 */

218
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
219

David Lawrence's avatar
David Lawrence committed
220
221
	src = isc_buffer_current(b);
	length = isc_buffer_remaininglength(b);
222
	(void)memmove(b->base, src, (size_t)length);
Bob Halley's avatar
Bob Halley committed
223

224
225
226
227
	if (b->active > b->current)
		b->active -= b->current;
	else
		b->active = 0;
228
	b->current = 0;
Bob Halley's avatar
Bob Halley committed
229
230
	b->used = length;
}
Bob Halley's avatar
Bob Halley committed
231

232
233
234
235
236
237
238
239
240
isc_uint8_t
isc_buffer_getuint8(isc_buffer_t *b) {
	unsigned char *cp;
	isc_uint8_t result;

	/*
	 * Read an unsigned 8-bit integer from 'b' and return it.
	 */

241
	REQUIRE(ISC_BUFFER_VALID(b));
242
243
	REQUIRE(b->used - b->current >= 1);

David Lawrence's avatar
David Lawrence committed
244
	cp = isc_buffer_current(b);
245
	b->current += 1;
David Lawrence's avatar
David Lawrence committed
246
	result = ((isc_uint8_t)(cp[0]));
247
248
249
250
251

	return (result);
}

void
David Lawrence's avatar
David Lawrence committed
252
isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
253
	REQUIRE(ISC_BUFFER_VALID(b));
254
255
	REQUIRE(b->used + 1 <= b->length);

256
	ISC__BUFFER_PUTUINT8(b, val);
257
258
}

Bob Halley's avatar
Bob Halley committed
259
260
261
262
263
264
265
266
267
268
isc_uint16_t
isc_buffer_getuint16(isc_buffer_t *b) {
	unsigned char *cp;
	isc_uint16_t result;

	/*
	 * Read an unsigned 16-bit integer in network byte order from 'b',
	 * convert it to host byte order, and return it.
	 */

269
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
270
271
	REQUIRE(b->used - b->current >= 2);

David Lawrence's avatar
David Lawrence committed
272
	cp = isc_buffer_current(b);
Bob Halley's avatar
Bob Halley committed
273
274
275
276
277
278
279
	b->current += 2;
	result = ((unsigned int)(cp[0])) << 8;
	result |= ((unsigned int)(cp[1]));

	return (result);
}

280
void
David Lawrence's avatar
David Lawrence committed
281
isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
282
	REQUIRE(ISC_BUFFER_VALID(b));
283
284
	REQUIRE(b->used + 2 <= b->length);

285
	ISC__BUFFER_PUTUINT16(b, val);
286
287
}

Bob Halley's avatar
Bob Halley committed
288
289
290
291
292
293
294
295
296
297
isc_uint32_t
isc_buffer_getuint32(isc_buffer_t *b) {
	unsigned char *cp;
	isc_uint32_t result;

	/*
	 * Read an unsigned 32-bit integer in network byte order from 'b',
	 * convert it to host byte order, and return it.
	 */

298
	REQUIRE(ISC_BUFFER_VALID(b));
Bob Halley's avatar
Bob Halley committed
299
300
	REQUIRE(b->used - b->current >= 4);

David Lawrence's avatar
David Lawrence committed
301
	cp = isc_buffer_current(b);
Bob Halley's avatar
Bob Halley committed
302
303
304
305
306
307
308
309
	b->current += 4;
	result = ((unsigned int)(cp[0])) << 24;
	result |= ((unsigned int)(cp[1])) << 16;
	result |= ((unsigned int)(cp[2])) << 8;
	result |= ((unsigned int)(cp[3]));

	return (result);
}
310
311

void
David Lawrence's avatar
David Lawrence committed
312
isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
313
	REQUIRE(ISC_BUFFER_VALID(b));
314
315
	REQUIRE(b->used + 4 <= b->length);

316
	ISC__BUFFER_PUTUINT32(b, val);
317
}
318

Andreas Gustafsson's avatar
Andreas Gustafsson committed
319
void
David Lawrence's avatar
David Lawrence committed
320
321
322
isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
		   unsigned int length)
{
Andreas Gustafsson's avatar
Andreas Gustafsson committed
323
324
325
	REQUIRE(ISC_BUFFER_VALID(b));
	REQUIRE(b->used + length <= b->length);

326
	ISC__BUFFER_PUTMEM(b, base, length);
David Lawrence's avatar
David Lawrence committed
327
}
Andreas Gustafsson's avatar
Andreas Gustafsson committed
328

329
void
David Lawrence's avatar
David Lawrence committed
330
isc__buffer_putstr(isc_buffer_t *b, const char *source) {
331
	unsigned int l;
332
	unsigned char *cp;
Mark Andrews's avatar
Mark Andrews committed
333
334
335
336

	REQUIRE(ISC_BUFFER_VALID(b));
	REQUIRE(source != NULL);

David Lawrence's avatar
David Lawrence committed
337
338
339
	/*
	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
	 */
Mark Andrews's avatar
Mark Andrews committed
340
341
	l = strlen(source);

342
343
344
	REQUIRE(l <= isc_buffer_availablelength(b));

	cp = isc_buffer_used(b);
345
	memcpy(cp, source, l);
Mark Andrews's avatar
Mark Andrews committed
346
347
348
	b->used += l;
}

Bob Halley's avatar
Bob Halley committed
349
isc_result_t
350
isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
Bob Halley's avatar
Bob Halley committed
351
352
353
354
355
356
	unsigned char *base;
	unsigned int available;

	REQUIRE(ISC_BUFFER_VALID(b));
	REQUIRE(r != NULL);

David Lawrence's avatar
David Lawrence committed
357
	/*
358
	 * XXXDCL
David Lawrence's avatar
David Lawrence committed
359
360
361
	 */
	base = isc_buffer_used(b);
	available = isc_buffer_availablelength(b);
Bob Halley's avatar
Bob Halley committed
362
363
364
365
366
367
368
369
        if (r->length > available)
		return (ISC_R_NOSPACE);
	memcpy(base, r->base, r->length);
	b->used += r->length;

	return (ISC_R_SUCCESS);
}

370
isc_result_t
371
isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
372
		    unsigned int length)
373
{
374
	isc_buffer_t *dbuf;
375
376
377
378

	REQUIRE(dynbuffer != NULL);
	REQUIRE(*dynbuffer == NULL);

379
	dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
380
381
382
	if (dbuf == NULL)
		return (ISC_R_NOMEMORY);

383
	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
384
			length);
385
	dbuf->mctx = mctx;
386
387
388
389
390
391

	*dynbuffer = dbuf;

	return (ISC_R_SUCCESS);
}

392
void
David Lawrence's avatar
David Lawrence committed
393
isc_buffer_free(isc_buffer_t **dynbuffer) {
394
	unsigned int real_length;
395
396
	isc_buffer_t *dbuf;
	isc_mem_t *mctx;
397
398

	REQUIRE(dynbuffer != NULL);
399
	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
400
	REQUIRE((*dynbuffer)->mctx != NULL);
401
402
403
404

	dbuf = *dynbuffer;
	*dynbuffer = NULL;	/* destroy external reference */

405
406
407
408
	real_length = dbuf->length + sizeof(isc_buffer_t);
	mctx = dbuf->mctx;
	dbuf->mctx = NULL;
	isc_buffer_invalidate(dbuf);
409
410
411

	isc_mem_put(mctx, dbuf, real_length);
}