sbuffer.h revision 356345
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
17extern "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 */
34INLINE uint16_t
35sldns_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
45INLINE uint32_t
46sldns_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 */
63INLINE void
64sldns_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
75INLINE void
76sldns_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
90INLINE void
91sldns_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 */
116struct 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};
138typedef struct sldns_buffer sldns_buffer;
139
140#ifdef NDEBUG
141INLINE void
142sldns_buffer_invariant(sldns_buffer *ATTR_UNUSED(buffer))
143{
144}
145#else
146INLINE void
147sldns_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 */
162sldns_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 */
173void 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 */
182void 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 */
189INLINE 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 */
207INLINE 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 */
220INLINE 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 */
232INLINE size_t
233sldns_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 */
244INLINE void
245sldns_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 */
258INLINE void
259sldns_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 */
270INLINE size_t
271sldns_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 */
282INLINE void
283sldns_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 */
296INLINE size_t
297sldns_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 */
310int 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 */
322int 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 */
330INLINE uint8_t *
331sldns_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 */
343INLINE uint8_t *
344sldns_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 */
355INLINE uint8_t *
356sldns_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 */
366INLINE uint8_t *
367sldns_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 */
379INLINE size_t
380sldns_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 */
393INLINE size_t
394sldns_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 */
408INLINE int
409sldns_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 */
420INLINE int
421sldns_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 */
433INLINE void
434sldns_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
448INLINE void
449sldns_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 */
462INLINE void
463sldns_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 */
475INLINE void
476sldns_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 */
486INLINE void
487sldns_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 */
498INLINE void
499sldns_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 */
510INLINE void
511sldns_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 */
523INLINE void
524sldns_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 */
535INLINE void
536sldns_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 */
548INLINE void
549sldns_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 */
561INLINE void
562sldns_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 */
573INLINE void
574sldns_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 */
585INLINE void
586sldns_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 */
599INLINE void
600sldns_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 */
612INLINE void
613sldns_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 */
625INLINE uint8_t
626sldns_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 */
637INLINE uint8_t
638sldns_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 */
651INLINE uint16_t
652sldns_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 */
663INLINE uint16_t
664sldns_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 */
677INLINE uint32_t
678sldns_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 */
689INLINE uint32_t
690sldns_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 */
702INLINE int
703sldns_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 */
713INLINE int
714sldns_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 */
729int 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 */
737void 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 */
746void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from);
747
748#ifdef __cplusplus
749}
750#endif
751
752#endif /* LDNS_SBUFFER_H */
753