xref: /openbsd/usr.bin/dig/lib/isc/buffer.c (revision 873f12b9)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: buffer.c,v 1.8 2020/02/26 18:47:59 florian Exp $ */
18 
19 /*! \file */
20 
21 #include <stdlib.h>
22 #include <isc/buffer.h>
23 
24 #include <isc/region.h>
25 #include <string.h>
26 #include <isc/util.h>
27 
28 void
isc__buffer_init(isc_buffer_t * b,void * base,unsigned int length)29 isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
30 	/*
31 	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
32 	 * XXXDCL see the comment in buffer.h about base being const.
33 	 */
34 
35 	REQUIRE(b != NULL);
36 
37 	ISC__BUFFER_INIT(b, base, length);
38 }
39 
40 void
isc__buffer_invalidate(isc_buffer_t * b)41 isc__buffer_invalidate(isc_buffer_t *b) {
42 	/*
43 	 * Make 'b' an invalid buffer.
44 	 */
45 
46 	REQUIRE(!ISC_LINK_LINKED(b, link));
47 
48 	ISC__BUFFER_INVALIDATE(b);
49 }
50 
51 void
isc__buffer_usedregion(isc_buffer_t * b,isc_region_t * r)52 isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
53 	/*
54 	 * Make 'r' refer to the used region of 'b'.
55 	 */
56 
57 	REQUIRE(r != NULL);
58 
59 	ISC__BUFFER_USEDREGION(b, r);
60 }
61 
62 void
isc__buffer_availableregion(isc_buffer_t * b,isc_region_t * r)63 isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
64 	/*
65 	 * Make 'r' refer to the available region of 'b'.
66 	 */
67 
68 	REQUIRE(r != NULL);
69 
70 	ISC__BUFFER_AVAILABLEREGION(b, r);
71 }
72 
73 void
isc__buffer_add(isc_buffer_t * b,unsigned int n)74 isc__buffer_add(isc_buffer_t *b, unsigned int n) {
75 	/*
76 	 * Increase the 'used' region of 'b' by 'n' bytes.
77 	 */
78 
79 	REQUIRE(b->used + n <= b->length);
80 
81 	ISC__BUFFER_ADD(b, n);
82 }
83 
84 void
isc__buffer_subtract(isc_buffer_t * b,unsigned int n)85 isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
86 	/*
87 	 * Decrease the 'used' region of 'b' by 'n' bytes.
88 	 */
89 
90 	REQUIRE(b->used >= n);
91 
92 	ISC__BUFFER_SUBTRACT(b, n);
93 }
94 
95 void
isc__buffer_clear(isc_buffer_t * b)96 isc__buffer_clear(isc_buffer_t *b) {
97 	/*
98 	 * Make the used region empty.
99 	 */
100 
101 	ISC__BUFFER_CLEAR(b);
102 }
103 
104 void
isc__buffer_remainingregion(isc_buffer_t * b,isc_region_t * r)105 isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
106 	/*
107 	 * Make 'r' refer to the remaining region of 'b'.
108 	 */
109 
110 	REQUIRE(r != NULL);
111 
112 	ISC__BUFFER_REMAININGREGION(b, r);
113 }
114 
115 void
isc__buffer_activeregion(isc_buffer_t * b,isc_region_t * r)116 isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
117 	/*
118 	 * Make 'r' refer to the active region of 'b'.
119 	 */
120 
121 	REQUIRE(r != NULL);
122 
123 	ISC__BUFFER_ACTIVEREGION(b, r);
124 }
125 
126 void
isc__buffer_setactive(isc_buffer_t * b,unsigned int n)127 isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
128 	/*
129 	 * Sets the end of the active region 'n' bytes after current.
130 	 */
131 
132 	REQUIRE(b->current + n <= b->used);
133 
134 	ISC__BUFFER_SETACTIVE(b, n);
135 }
136 
137 void
isc__buffer_first(isc_buffer_t * b)138 isc__buffer_first(isc_buffer_t *b) {
139 	/*
140 	 * Make the consumed region empty.
141 	 */
142 
143 	ISC__BUFFER_FIRST(b);
144 }
145 
146 void
isc__buffer_forward(isc_buffer_t * b,unsigned int n)147 isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
148 	/*
149 	 * Increase the 'consumed' region of 'b' by 'n' bytes.
150 	 */
151 
152 	REQUIRE(b->current + n <= b->used);
153 
154 	ISC__BUFFER_FORWARD(b, n);
155 }
156 
157 void
isc_buffer_compact(isc_buffer_t * b)158 isc_buffer_compact(isc_buffer_t *b) {
159 	unsigned int length;
160 	void *src;
161 
162 	/*
163 	 * Compact the used region by moving the remaining region so it occurs
164 	 * at the start of the buffer.  The used region is shrunk by the size
165 	 * of the consumed region, and the consumed region is then made empty.
166 	 */
167 
168 	src = isc_buffer_current(b);
169 	length = isc_buffer_remaininglength(b);
170 	(void)memmove(b->base, src, (size_t)length);
171 
172 	if (b->active > b->current)
173 		b->active -= b->current;
174 	else
175 		b->active = 0;
176 	b->current = 0;
177 	b->used = length;
178 }
179 
180 uint8_t
isc_buffer_getuint8(isc_buffer_t * b)181 isc_buffer_getuint8(isc_buffer_t *b) {
182 	unsigned char *cp;
183 	uint8_t result;
184 
185 	/*
186 	 * Read an unsigned 8-bit integer from 'b' and return it.
187 	 */
188 
189 	REQUIRE(b->used - b->current >= 1);
190 
191 	cp = isc_buffer_current(b);
192 	b->current += 1;
193 	result = ((uint8_t)(cp[0]));
194 
195 	return (result);
196 }
197 
198 void
isc__buffer_putuint8(isc_buffer_t * b,uint8_t val)199 isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) {
200 	REQUIRE(b->used + 1 <= b->length);
201 
202 	ISC__BUFFER_PUTUINT8(b, val);
203 }
204 
205 uint16_t
isc_buffer_getuint16(isc_buffer_t * b)206 isc_buffer_getuint16(isc_buffer_t *b) {
207 	unsigned char *cp;
208 	uint16_t result;
209 
210 	/*
211 	 * Read an unsigned 16-bit integer in network byte order from 'b',
212 	 * convert it to host byte order, and return it.
213 	 */
214 
215 	REQUIRE(b->used - b->current >= 2);
216 
217 	cp = isc_buffer_current(b);
218 	b->current += 2;
219 	result = ((unsigned int)(cp[0])) << 8;
220 	result |= ((unsigned int)(cp[1]));
221 
222 	return (result);
223 }
224 
225 void
isc__buffer_putuint16(isc_buffer_t * b,uint16_t val)226 isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) {
227 	REQUIRE(b->used + 2 <= b->length);
228 
229 	ISC__BUFFER_PUTUINT16(b, val);
230 }
231 
232 uint32_t
isc_buffer_getuint32(isc_buffer_t * b)233 isc_buffer_getuint32(isc_buffer_t *b) {
234 	unsigned char *cp;
235 	uint32_t result;
236 
237 	/*
238 	 * Read an unsigned 32-bit integer in network byte order from 'b',
239 	 * convert it to host byte order, and return it.
240 	 */
241 
242 	REQUIRE(b->used - b->current >= 4);
243 
244 	cp = isc_buffer_current(b);
245 	b->current += 4;
246 	result = ((unsigned int)(cp[0])) << 24;
247 	result |= ((unsigned int)(cp[1])) << 16;
248 	result |= ((unsigned int)(cp[2])) << 8;
249 	result |= ((unsigned int)(cp[3]));
250 
251 	return (result);
252 }
253 
254 void
isc__buffer_putuint32(isc_buffer_t * b,uint32_t val)255 isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) {
256 	REQUIRE(b->used + 4 <= b->length);
257 
258 	ISC__BUFFER_PUTUINT32(b, val);
259 }
260 
261 void
isc__buffer_putuint48(isc_buffer_t * b,uint64_t val)262 isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) {
263 	uint16_t valhi;
264 	uint32_t vallo;
265 
266 	REQUIRE(b->used + 6 <= b->length);
267 
268 	valhi = (uint16_t)(val >> 32);
269 	vallo = (uint32_t)(val & 0xFFFFFFFF);
270 	ISC__BUFFER_PUTUINT16(b, valhi);
271 	ISC__BUFFER_PUTUINT32(b, vallo);
272 }
273 
274 void
isc__buffer_putmem(isc_buffer_t * b,const unsigned char * base,unsigned int length)275 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
276 		   unsigned int length)
277 {
278 	REQUIRE(b->used + length <= b->length);
279 
280 	ISC__BUFFER_PUTMEM(b, base, length);
281 }
282 
283 void
isc__buffer_putstr(isc_buffer_t * b,const char * source)284 isc__buffer_putstr(isc_buffer_t *b, const char *source) {
285 	unsigned int l;
286 	unsigned char *cp;
287 
288 	REQUIRE(source != NULL);
289 
290 	/*
291 	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
292 	 */
293 	l = strlen(source);
294 
295 	REQUIRE(l <= isc_buffer_availablelength(b));
296 
297 	cp = isc_buffer_used(b);
298 	memmove(cp, source, l);
299 	b->used += l;
300 }
301 
302 isc_result_t
isc_buffer_copyregion(isc_buffer_t * b,const isc_region_t * r)303 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
304 	unsigned char *base;
305 	unsigned int available;
306 
307 	REQUIRE(r != NULL);
308 
309 	/*
310 	 * XXXDCL
311 	 */
312 	base = isc_buffer_used(b);
313 	available = isc_buffer_availablelength(b);
314 	if (r->length > available)
315 		return (ISC_R_NOSPACE);
316 	memmove(base, r->base, r->length);
317 	b->used += r->length;
318 
319 	return (ISC_R_SUCCESS);
320 }
321 
322 isc_result_t
isc_buffer_allocate(isc_buffer_t ** dynbuffer,unsigned int length)323 isc_buffer_allocate(isc_buffer_t **dynbuffer,
324 		    unsigned int length)
325 {
326 	isc_buffer_t *dbuf;
327 
328 	REQUIRE(dynbuffer != NULL);
329 	REQUIRE(*dynbuffer == NULL);
330 
331 	dbuf = malloc(length + sizeof(isc_buffer_t));
332 	if (dbuf == NULL)
333 		return (ISC_R_NOMEMORY);
334 
335 	isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
336 			length);
337 
338 	*dynbuffer = dbuf;
339 
340 	return (ISC_R_SUCCESS);
341 }
342 
343 void
isc_buffer_free(isc_buffer_t ** dynbuffer)344 isc_buffer_free(isc_buffer_t **dynbuffer) {
345 	isc_buffer_t *dbuf;
346 
347 	REQUIRE(dynbuffer != NULL);
348 	dbuf = *dynbuffer;
349 	*dynbuffer = NULL;	/* destroy external reference */
350 
351 	isc_buffer_invalidate(dbuf);
352 
353 	free(dbuf);
354 }
355 
356 isc_result_t
isc_mem_tobuffer(isc_buffer_t * target,void * base,unsigned int length)357 isc_mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
358 	isc_region_t tr;
359 
360 	isc_buffer_availableregion(target, &tr);
361 	if (length > tr.length)
362 		return (ISC_R_NOSPACE);
363 	memmove(tr.base, base, length);
364 	isc_buffer_add(target, length);
365 	return (ISC_R_SUCCESS);
366 }
367 
368 /* this used to be str_totext() in rdata.c etc. */
369 isc_result_t
isc_str_tobuffer(const char * source,isc_buffer_t * target)370 isc_str_tobuffer(const char *source, isc_buffer_t *target) {
371 	unsigned int l;
372 	isc_region_t region;
373 
374 	isc_buffer_availableregion(target, &region);
375 	l = strlen(source);
376 
377 	if (l > region.length)
378 		return (ISC_R_NOSPACE);
379 
380 	memmove(region.base, source, l);
381 	isc_buffer_add(target, l);
382 	return (ISC_R_SUCCESS);
383 }
384