xref: /freebsd/contrib/unbound/sldns/sbuffer.h (revision a521f2116473fbd8c09db395518f060a27d02334)
1 /*
2  * buffer.h -- generic memory buffer.
3  *
4  * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  *
9  * The buffer module implements a generic buffer.  The API is based on
10  * the java.nio.Buffer interface.
11  */
12 
13 #ifndef LDNS_SBUFFER_H
14 #define LDNS_SBUFFER_H
15 
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19 
20 #ifdef S_SPLINT_S
21 #  define INLINE
22 #else
23 #  ifdef SWIG
24 #    define INLINE static
25 #  else
26 #    define INLINE static inline
27 #  endif
28 #endif
29 
30 /*
31  * Copy data allowing for unaligned accesses in network byte order
32  * (big endian).
33  */
34 INLINE uint16_t
35 sldns_read_uint16(const void *src)
36 {
37 #ifdef ALLOW_UNALIGNED_ACCESSES
38         return ntohs(*(const uint16_t *) src);
39 #else
40         const uint8_t *p = (const uint8_t *) src;
41         return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
42 #endif
43 }
44 
45 INLINE uint32_t
46 sldns_read_uint32(const void *src)
47 {
48 #ifdef ALLOW_UNALIGNED_ACCESSES
49         return ntohl(*(const uint32_t *) src);
50 #else
51         const uint8_t *p = (const uint8_t *) src;
52         return (  ((uint32_t) p[0] << 24)
53                 | ((uint32_t) p[1] << 16)
54                 | ((uint32_t) p[2] << 8)
55                 |  (uint32_t) p[3]);
56 #endif
57 }
58 
59 /*
60  * Copy data allowing for unaligned accesses in network byte order
61  * (big endian).
62  */
63 INLINE void
64 sldns_write_uint16(void *dst, uint16_t data)
65 {
66 #ifdef ALLOW_UNALIGNED_ACCESSES
67         * (uint16_t *) dst = htons(data);
68 #else
69         uint8_t *p = (uint8_t *) dst;
70         p[0] = (uint8_t) ((data >> 8) & 0xff);
71         p[1] = (uint8_t) (data & 0xff);
72 #endif
73 }
74 
75 INLINE void
76 sldns_write_uint32(void *dst, uint32_t data)
77 {
78 #ifdef ALLOW_UNALIGNED_ACCESSES
79         * (uint32_t *) dst = htonl(data);
80 #else
81         uint8_t *p = (uint8_t *) dst;
82         p[0] = (uint8_t) ((data >> 24) & 0xff);
83         p[1] = (uint8_t) ((data >> 16) & 0xff);
84         p[2] = (uint8_t) ((data >> 8) & 0xff);
85         p[3] = (uint8_t) (data & 0xff);
86 #endif
87 }
88 
89 
90 INLINE void
91 sldns_write_uint48(void *dst, uint64_t data)
92 {
93         uint8_t *p = (uint8_t *) dst;
94         p[0] = (uint8_t) ((data >> 40) & 0xff);
95         p[1] = (uint8_t) ((data >> 32) & 0xff);
96         p[2] = (uint8_t) ((data >> 24) & 0xff);
97         p[3] = (uint8_t) ((data >> 16) & 0xff);
98         p[4] = (uint8_t) ((data >> 8) & 0xff);
99         p[5] = (uint8_t) (data & 0xff);
100 }
101 
102 
103 /**
104  * \file sbuffer.h
105  *
106  * This file contains the definition of sldns_buffer, and functions to manipulate those.
107  */
108 
109 /**
110  * implementation of buffers to ease operations
111  *
112  * sldns_buffers can contain arbitrary information, per octet. You can write
113  * to the current end of a buffer, read from the current position, and
114  * access any data within it.
115  */
116 struct sldns_buffer
117 {
118 	/** The current position used for reading/writing */
119 	size_t   _position;
120 
121 	/** The read/write limit */
122 	size_t   _limit;
123 
124 	/** The amount of data the buffer can contain */
125 	size_t   _capacity;
126 
127 	/** The data contained in the buffer */
128 	uint8_t *_data;
129 
130 	/** If the buffer is fixed it cannot be resized */
131 	unsigned _fixed : 1;
132 
133 	/** The current state of the buffer. If writing to the buffer fails
134 	 * for any reason, this value is changed. This way, you can perform
135 	 * multiple writes in sequence and check for success afterwards. */
136 	unsigned _status_err : 1;
137 };
138 typedef struct sldns_buffer sldns_buffer;
139 
140 #ifdef NDEBUG
141 INLINE void
142 sldns_buffer_invariant(sldns_buffer *ATTR_UNUSED(buffer))
143 {
144 }
145 #else
146 INLINE void
147 sldns_buffer_invariant(sldns_buffer *buffer)
148 {
149 	assert(buffer != NULL);
150 	assert(buffer->_position <= buffer->_limit);
151 	assert(buffer->_limit <= buffer->_capacity);
152 	assert(buffer->_data != NULL);
153 }
154 #endif
155 
156 /**
157  * creates a new buffer with the specified capacity.
158  *
159  * \param[in] capacity the size (in bytes) to allocate for the buffer
160  * \return the created buffer
161  */
162 sldns_buffer *sldns_buffer_new(size_t capacity);
163 
164 /**
165  * creates a buffer with the specified data.  The data IS copied
166  * and MEMORY allocations are done.  The buffer is not fixed and can
167  * be resized using buffer_reserve().
168  *
169  * \param[in] buffer pointer to the buffer to put the data in
170  * \param[in] data the data to encapsulate in the buffer
171  * \param[in] size the size of the data
172  */
173 void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size);
174 
175 /**
176  * Setup a buffer with the data pointed to. No data copied, no memory allocs.
177  * The buffer is fixed.
178  * \param[in] buffer pointer to the buffer to put the data in
179  * \param[in] data the data to encapsulate in the buffer
180  * \param[in] size the size of the data
181  */
182 void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size);
183 
184 /**
185  * clears the buffer and make it ready for writing.  The buffer's limit
186  * is set to the capacity and the position is set to 0.
187  * \param[in] buffer the buffer to clear
188  */
189 INLINE void sldns_buffer_clear(sldns_buffer *buffer)
190 {
191 	sldns_buffer_invariant(buffer);
192 
193 	/* reset status here? */
194 
195 	buffer->_position = 0;
196 	buffer->_limit = buffer->_capacity;
197 }
198 
199 /**
200  * makes the buffer ready for reading the data that has been written to
201  * the buffer.  The buffer's limit is set to the current position and
202  * the position is set to 0.
203  *
204  * \param[in] buffer the buffer to flip
205  * \return void
206  */
207 INLINE void sldns_buffer_flip(sldns_buffer *buffer)
208 {
209 	sldns_buffer_invariant(buffer);
210 
211 	buffer->_limit = buffer->_position;
212 	buffer->_position = 0;
213 }
214 
215 /**
216  * make the buffer ready for re-reading the data.  The buffer's
217  * position is reset to 0.
218  * \param[in] buffer the buffer to rewind
219  */
220 INLINE void sldns_buffer_rewind(sldns_buffer *buffer)
221 {
222 	sldns_buffer_invariant(buffer);
223 
224 	buffer->_position = 0;
225 }
226 
227 /**
228  * returns the current position in the buffer (as a number of bytes)
229  * \param[in] buffer the buffer
230  * \return the current position
231  */
232 INLINE size_t
233 sldns_buffer_position(sldns_buffer *buffer)
234 {
235 	return buffer->_position;
236 }
237 
238 /**
239  * sets the buffer's position to MARK.  The position must be less than
240  * or equal to the buffer's limit.
241  * \param[in] buffer the buffer
242  * \param[in] mark the mark to use
243  */
244 INLINE void
245 sldns_buffer_set_position(sldns_buffer *buffer, size_t mark)
246 {
247 	assert(mark <= buffer->_limit);
248 	buffer->_position = mark;
249 }
250 
251 /**
252  * changes the buffer's position by COUNT bytes.  The position must not
253  * be moved behind the buffer's limit or before the beginning of the
254  * buffer.
255  * \param[in] buffer the buffer
256  * \param[in] count the count to use
257  */
258 INLINE void
259 sldns_buffer_skip(sldns_buffer *buffer, ssize_t count)
260 {
261 	assert(buffer->_position + count <= buffer->_limit);
262 	buffer->_position += count;
263 }
264 
265 /**
266  * returns the maximum size of the buffer
267  * \param[in] buffer
268  * \return the size
269  */
270 INLINE size_t
271 sldns_buffer_limit(sldns_buffer *buffer)
272 {
273 	return buffer->_limit;
274 }
275 
276 /**
277  * changes the buffer's limit.  If the buffer's position is greater
278  * than the new limit the position is set to the limit.
279  * \param[in] buffer the buffer
280  * \param[in] limit the new limit
281  */
282 INLINE void
283 sldns_buffer_set_limit(sldns_buffer *buffer, size_t limit)
284 {
285 	assert(limit <= buffer->_capacity);
286 	buffer->_limit = limit;
287 	if (buffer->_position > buffer->_limit)
288 		buffer->_position = buffer->_limit;
289 }
290 
291 /**
292  * returns the number of bytes the buffer can hold.
293  * \param[in] buffer the buffer
294  * \return the number of bytes
295  */
296 INLINE size_t
297 sldns_buffer_capacity(sldns_buffer *buffer)
298 {
299 	return buffer->_capacity;
300 }
301 
302 /**
303  * changes the buffer's capacity.  The data is reallocated so any
304  * pointers to the data may become invalid.  The buffer's limit is set
305  * to the buffer's new capacity.
306  * \param[in] buffer the buffer
307  * \param[in] capacity the capacity to use
308  * \return whether this failed or succeeded
309  */
310 int sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity);
311 
312 /**
313  * ensures BUFFER can contain at least AMOUNT more bytes.  The buffer's
314  * capacity is increased if necessary using buffer_set_capacity().
315  *
316  * The buffer's limit is always set to the (possibly increased)
317  * capacity.
318  * \param[in] buffer the buffer
319  * \param[in] amount amount to use
320  * \return whether this failed or succeeded
321  */
322 int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount);
323 
324 /**
325  * returns a pointer to the data at the indicated position.
326  * \param[in] buffer the buffer
327  * \param[in] at position
328  * \return the pointer to the data
329  */
330 INLINE uint8_t *
331 sldns_buffer_at(const sldns_buffer *buffer, size_t at)
332 {
333 	assert(at <= buffer->_limit);
334 	return buffer->_data + at;
335 }
336 
337 /**
338  * returns a pointer to the beginning of the buffer (the data at
339  * position 0).
340  * \param[in] buffer the buffer
341  * \return the pointer
342  */
343 INLINE uint8_t *
344 sldns_buffer_begin(const sldns_buffer *buffer)
345 {
346 	return sldns_buffer_at(buffer, 0);
347 }
348 
349 /**
350  * returns a pointer to the end of the buffer (the data at the buffer's
351  * limit).
352  * \param[in] buffer the buffer
353  * \return the pointer
354  */
355 INLINE uint8_t *
356 sldns_buffer_end(sldns_buffer *buffer)
357 {
358 	return sldns_buffer_at(buffer, buffer->_limit);
359 }
360 
361 /**
362  * returns a pointer to the data at the buffer's current position.
363  * \param[in] buffer the buffer
364  * \return the pointer
365  */
366 INLINE uint8_t *
367 sldns_buffer_current(sldns_buffer *buffer)
368 {
369 	return sldns_buffer_at(buffer, buffer->_position);
370 }
371 
372 /**
373  * returns the number of bytes remaining between the indicated position and
374  * the limit.
375  * \param[in] buffer the buffer
376  * \param[in] at indicated position
377  * \return number of bytes
378  */
379 INLINE size_t
380 sldns_buffer_remaining_at(sldns_buffer *buffer, size_t at)
381 {
382 	sldns_buffer_invariant(buffer);
383 	assert(at <= buffer->_limit);
384 	return at < buffer->_limit ? buffer->_limit - at : 0;
385 }
386 
387 /**
388  * returns the number of bytes remaining between the buffer's position and
389  * limit.
390  * \param[in] buffer the buffer
391  * \return the number of bytes
392  */
393 INLINE size_t
394 sldns_buffer_remaining(sldns_buffer *buffer)
395 {
396 	return sldns_buffer_remaining_at(buffer, buffer->_position);
397 }
398 
399 /**
400  * checks if the buffer has at least COUNT more bytes available.
401  * Before reading or writing the caller needs to ensure enough space
402  * is available!
403  * \param[in] buffer the buffer
404  * \param[in] at indicated position
405  * \param[in] count how much is available
406  * \return true or false (as int?)
407  */
408 INLINE int
409 sldns_buffer_available_at(sldns_buffer *buffer, size_t at, size_t count)
410 {
411 	return count <= sldns_buffer_remaining_at(buffer, at);
412 }
413 
414 /**
415  * checks if the buffer has count bytes available at the current position
416  * \param[in] buffer the buffer
417  * \param[in] count how much is available
418  * \return true or false (as int?)
419  */
420 INLINE int
421 sldns_buffer_available(sldns_buffer *buffer, size_t count)
422 {
423 	return sldns_buffer_available_at(buffer, buffer->_position, count);
424 }
425 
426 /**
427  * writes the given data to the buffer at the specified position
428  * \param[in] buffer the buffer
429  * \param[in] at the position (in number of bytes) to write the data at
430  * \param[in] data pointer to the data to write to the buffer
431  * \param[in] count the number of bytes of data to write
432  */
433 INLINE void
434 sldns_buffer_write_at(sldns_buffer *buffer, size_t at, const void *data, size_t count)
435 {
436 	assert(sldns_buffer_available_at(buffer, at, count));
437 	memcpy(buffer->_data + at, data, count);
438 }
439 
440 /**
441  * set the given byte to the buffer at the specified position
442  * \param[in] buffer the buffer
443  * \param[in] at the position (in number of bytes) to write the data at
444  * \param[in] c the byte to set to the buffer
445  * \param[in] count the number of bytes of bytes to write
446  */
447 
448 INLINE void
449 sldns_buffer_set_at(sldns_buffer *buffer, size_t at, int c, size_t count)
450 {
451 	assert(sldns_buffer_available_at(buffer, at, count));
452 	memset(buffer->_data + at, c, count);
453 }
454 
455 
456 /**
457  * writes count bytes of data to the current position of the buffer
458  * \param[in] buffer the buffer
459  * \param[in] data the data to write
460  * \param[in] count the length of the data to write
461  */
462 INLINE void
463 sldns_buffer_write(sldns_buffer *buffer, const void *data, size_t count)
464 {
465 	sldns_buffer_write_at(buffer, buffer->_position, data, count);
466 	buffer->_position += count;
467 }
468 
469 /**
470  * copies the given (null-delimited) string to the specified position at the buffer
471  * \param[in] buffer the buffer
472  * \param[in] at the position in the buffer
473  * \param[in] str the string to write
474  */
475 INLINE void
476 sldns_buffer_write_string_at(sldns_buffer *buffer, size_t at, const char *str)
477 {
478 	sldns_buffer_write_at(buffer, at, str, strlen(str));
479 }
480 
481 /**
482  * copies the given (null-delimited) string to the current position at the buffer
483  * \param[in] buffer the buffer
484  * \param[in] str the string to write
485  */
486 INLINE void
487 sldns_buffer_write_string(sldns_buffer *buffer, const char *str)
488 {
489 	sldns_buffer_write(buffer, str, strlen(str));
490 }
491 
492 /**
493  * writes the given byte of data at the given position in the buffer
494  * \param[in] buffer the buffer
495  * \param[in] at the position in the buffer
496  * \param[in] data the 8 bits to write
497  */
498 INLINE void
499 sldns_buffer_write_u8_at(sldns_buffer *buffer, size_t at, uint8_t data)
500 {
501 	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
502 	buffer->_data[at] = data;
503 }
504 
505 /**
506  * writes the given byte of data at the current position in the buffer
507  * \param[in] buffer the buffer
508  * \param[in] data the 8 bits to write
509  */
510 INLINE void
511 sldns_buffer_write_u8(sldns_buffer *buffer, uint8_t data)
512 {
513 	sldns_buffer_write_u8_at(buffer, buffer->_position, data);
514 	buffer->_position += sizeof(data);
515 }
516 
517 /**
518  * writes the given 2 byte integer at the given position in the buffer
519  * \param[in] buffer the buffer
520  * \param[in] at the position in the buffer
521  * \param[in] data the 16 bits to write
522  */
523 INLINE void
524 sldns_buffer_write_u16_at(sldns_buffer *buffer, size_t at, uint16_t data)
525 {
526 	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
527 	sldns_write_uint16(buffer->_data + at, data);
528 }
529 
530 /**
531  * writes the given 2 byte integer at the current position in the buffer
532  * \param[in] buffer the buffer
533  * \param[in] data the 16 bits to write
534  */
535 INLINE void
536 sldns_buffer_write_u16(sldns_buffer *buffer, uint16_t data)
537 {
538 	sldns_buffer_write_u16_at(buffer, buffer->_position, data);
539 	buffer->_position += sizeof(data);
540 }
541 
542 /**
543  * writes the given 4 byte integer at the given position in the buffer
544  * \param[in] buffer the buffer
545  * \param[in] at the position in the buffer
546  * \param[in] data the 32 bits to write
547  */
548 INLINE void
549 sldns_buffer_write_u32_at(sldns_buffer *buffer, size_t at, uint32_t data)
550 {
551 	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
552 	sldns_write_uint32(buffer->_data + at, data);
553 }
554 
555 /**
556  * writes the given 6 byte integer at the given position in the buffer
557  * \param[in] buffer the buffer
558  * \param[in] at the position in the buffer
559  * \param[in] data the (lower) 48 bits to write
560  */
561 INLINE void
562 sldns_buffer_write_u48_at(sldns_buffer *buffer, size_t at, uint64_t data)
563 {
564 	assert(sldns_buffer_available_at(buffer, at, 6));
565 	sldns_write_uint48(buffer->_data + at, data);
566 }
567 
568 /**
569  * writes the given 4 byte integer at the current position in the buffer
570  * \param[in] buffer the buffer
571  * \param[in] data the 32 bits to write
572  */
573 INLINE void
574 sldns_buffer_write_u32(sldns_buffer *buffer, uint32_t data)
575 {
576 	sldns_buffer_write_u32_at(buffer, buffer->_position, data);
577 	buffer->_position += sizeof(data);
578 }
579 
580 /**
581  * writes the given 6 byte integer at the current position in the buffer
582  * \param[in] buffer the buffer
583  * \param[in] data the 48 bits to write
584  */
585 INLINE void
586 sldns_buffer_write_u48(sldns_buffer *buffer, uint64_t data)
587 {
588 	sldns_buffer_write_u48_at(buffer, buffer->_position, data);
589 	buffer->_position += 6;
590 }
591 
592 /**
593  * copies count bytes of data at the given position to the given data-array
594  * \param[in] buffer the buffer
595  * \param[in] at the position in the buffer to start
596  * \param[out] data buffer to copy to
597  * \param[in] count the length of the data to copy
598  */
599 INLINE void
600 sldns_buffer_read_at(sldns_buffer *buffer, size_t at, void *data, size_t count)
601 {
602 	assert(sldns_buffer_available_at(buffer, at, count));
603 	memcpy(data, buffer->_data + at, count);
604 }
605 
606 /**
607  * copies count bytes of data at the current position to the given data-array
608  * \param[in] buffer the buffer
609  * \param[out] data buffer to copy to
610  * \param[in] count the length of the data to copy
611  */
612 INLINE void
613 sldns_buffer_read(sldns_buffer *buffer, void *data, size_t count)
614 {
615 	sldns_buffer_read_at(buffer, buffer->_position, data, count);
616 	buffer->_position += count;
617 }
618 
619 /**
620  * returns the byte value at the given position in the buffer
621  * \param[in] buffer the buffer
622  * \param[in] at the position in the buffer
623  * \return 1 byte integer
624  */
625 INLINE uint8_t
626 sldns_buffer_read_u8_at(sldns_buffer *buffer, size_t at)
627 {
628 	assert(sldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
629 	return buffer->_data[at];
630 }
631 
632 /**
633  * returns the byte value at the current position in the buffer
634  * \param[in] buffer the buffer
635  * \return 1 byte integer
636  */
637 INLINE uint8_t
638 sldns_buffer_read_u8(sldns_buffer *buffer)
639 {
640 	uint8_t result = sldns_buffer_read_u8_at(buffer, buffer->_position);
641 	buffer->_position += sizeof(uint8_t);
642 	return result;
643 }
644 
645 /**
646  * returns the 2-byte integer value at the given position in the buffer
647  * \param[in] buffer the buffer
648  * \param[in] at position in the buffer
649  * \return 2 byte integer
650  */
651 INLINE uint16_t
652 sldns_buffer_read_u16_at(sldns_buffer *buffer, size_t at)
653 {
654 	assert(sldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
655 	return sldns_read_uint16(buffer->_data + at);
656 }
657 
658 /**
659  * returns the 2-byte integer value at the current position in the buffer
660  * \param[in] buffer the buffer
661  * \return 2 byte integer
662  */
663 INLINE uint16_t
664 sldns_buffer_read_u16(sldns_buffer *buffer)
665 {
666 	uint16_t result = sldns_buffer_read_u16_at(buffer, buffer->_position);
667 	buffer->_position += sizeof(uint16_t);
668 	return result;
669 }
670 
671 /**
672  * returns the 4-byte integer value at the given position in the buffer
673  * \param[in] buffer the buffer
674  * \param[in] at position in the buffer
675  * \return 4 byte integer
676  */
677 INLINE uint32_t
678 sldns_buffer_read_u32_at(sldns_buffer *buffer, size_t at)
679 {
680 	assert(sldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
681 	return sldns_read_uint32(buffer->_data + at);
682 }
683 
684 /**
685  * returns the 4-byte integer value at the current position in the buffer
686  * \param[in] buffer the buffer
687  * \return 4 byte integer
688  */
689 INLINE uint32_t
690 sldns_buffer_read_u32(sldns_buffer *buffer)
691 {
692 	uint32_t result = sldns_buffer_read_u32_at(buffer, buffer->_position);
693 	buffer->_position += sizeof(uint32_t);
694 	return result;
695 }
696 
697 /**
698  * returns the status of the buffer
699  * \param[in] buffer
700  * \return the status
701  */
702 INLINE int
703 sldns_buffer_status(sldns_buffer *buffer)
704 {
705 	return (int)buffer->_status_err;
706 }
707 
708 /**
709  * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise
710  * \param[in] buffer the buffer
711  * \return true or false
712  */
713 INLINE int
714 sldns_buffer_status_ok(sldns_buffer *buffer)
715 {
716 	if (buffer) {
717 		return sldns_buffer_status(buffer) == 0;
718 	} else {
719 		return 0;
720 	}
721 }
722 
723 /**
724  * prints to the buffer, increasing the capacity if required using
725  * buffer_reserve(). The buffer's position is set to the terminating '\\0'
726  * Returns the number of characters written (not including the
727  * terminating '\\0') or -1 on failure.
728  */
729 int sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
730 	ATTR_FORMAT(printf, 2, 3);
731 
732 /**
733  * frees the buffer.
734  * \param[in] *buffer the buffer to be freed
735  * \return void
736  */
737 void sldns_buffer_free(sldns_buffer *buffer);
738 
739 /**
740  * Copy contents of the from buffer to the result buffer and then flips
741  * the result buffer. Data will be silently truncated if the result buffer is
742  * too small.
743  * \param[out] *result resulting buffer which is copied to.
744  * \param[in] *from what to copy to result.
745  */
746 void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from);
747 
748 #ifdef __cplusplus
749 }
750 #endif
751 
752 #endif /* LDNS_SBUFFER_H */
753