1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
9 * \brief Implements a generic buffer interface.
11 * A buf_t is a (fairly) opaque byte-oriented FIFO that can read to or flush
12 * from memory, sockets, file descriptors, TLS connections, or another buf_t.
13 * Buffers are implemented as linked lists of memory chunks.
15 * All socket-backed and TLS-based connection_t objects have a pair of
16 * buffers: one for incoming data, and one for outcoming data. These are fed
17 * and drained from functions in connection.c, triggered by events that are
18 * monitored in main.c.
20 * This module only handles the buffer implementation itself. To use a buffer
21 * with the network, a compressor, or a TLS connection, see the other buffer_*
25 #define BUFFERS_PRIVATE
28 #include "lib/buf/buffers.h"
29 #include "lib/cc/torint.h"
30 #include "lib/log/log.h"
31 #include "lib/log/util_bug.h"
32 #include "lib/ctime/di_ops.h"
33 #include "lib/malloc/malloc.h"
34 #include "lib/string/printf.h"
35 #include "lib/time/compat_time.h"
47 /** Helper: If PARANOIA is defined, assert that the buffer in local variable
48 * <b>buf</b> is well-formed. */
49 #define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
51 #define check() STMT_NIL
52 #endif /* defined(PARANOIA) */
54 /* Implementation notes:
56 * After flirting with memmove, and dallying with ring-buffers, we're finally
57 * getting up to speed with the 1970s and implementing buffers as a linked
58 * list of small chunks. Each buffer has such a list; data is removed from
59 * the head of the list, and added at the tail. The list is singly linked,
60 * and the buffer keeps a pointer to the head and the tail.
62 * Every chunk, except the tail, contains at least one byte of data. Data in
63 * each chunk is contiguous.
65 * When you need to treat the first N characters on a buffer as a contiguous
66 * string, use the buf_pullup function to make them so. Don't do this more
69 * The major free Unix kernels have handled buffers like this since, like,
73 /* Chunk manipulation functions */
75 #define CHUNK_HEADER_LEN offsetof(chunk_t, mem[0])
77 /* We leave this many NUL bytes at the end of the buffer. */
78 #ifdef DISABLE_MEMORY_SENTINELS
79 #define SENTINEL_LEN 0
81 #define SENTINEL_LEN 4
84 /* Header size plus NUL bytes at the end */
85 #define CHUNK_OVERHEAD (CHUNK_HEADER_LEN + SENTINEL_LEN)
87 /** Return the number of bytes needed to allocate a chunk to hold
88 * <b>memlen</b> bytes. */
89 #define CHUNK_ALLOC_SIZE(memlen) (CHUNK_OVERHEAD + (memlen))
90 /** Return the number of usable bytes in a chunk allocated with
91 * malloc(<b>memlen</b>). */
92 #define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_OVERHEAD)
94 #define DEBUG_SENTINEL
96 #if defined(DEBUG_SENTINEL) && !defined(DISABLE_MEMORY_SENTINELS)
99 #define DBG_S(s) (void)0
103 #ifdef DISABLE_MEMORY_SENTINELS
104 #define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL
106 #define CHUNK_SET_SENTINEL(chunk, alloclen) do { \
107 uint8_t *a = (uint8_t*) &(chunk)->mem[(chunk)->memlen]; \
108 DBG_S(uint8_t *b = &((uint8_t*)(chunk))[(alloclen)-SENTINEL_LEN]); \
109 DBG_S(tor_assert(a == b)); \
110 memset(a,0,SENTINEL_LEN); \
112 #endif /* defined(DISABLE_MEMORY_SENTINELS) */
113 #endif /* !defined(COCCI) */
115 /** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
116 * to free up space at the end. */
118 chunk_repack(chunk_t
*chunk
)
120 if (chunk
->datalen
&& chunk
->data
!= &chunk
->mem
[0]) {
121 memmove(chunk
->mem
, chunk
->data
, chunk
->datalen
);
123 chunk
->data
= &chunk
->mem
[0];
126 /** Keep track of total size of allocated chunks for consistency asserts */
127 static size_t total_bytes_allocated_in_chunks
= 0;
129 buf_chunk_free_unchecked(chunk_t
*chunk
)
133 #ifdef DEBUG_CHUNK_ALLOC
134 tor_assert(CHUNK_ALLOC_SIZE(chunk
->memlen
) == chunk
->DBG_alloc
);
136 tor_assert(total_bytes_allocated_in_chunks
>=
137 CHUNK_ALLOC_SIZE(chunk
->memlen
));
138 total_bytes_allocated_in_chunks
-= CHUNK_ALLOC_SIZE(chunk
->memlen
);
141 static inline chunk_t
*
142 chunk_new_with_alloc_size(size_t alloc
)
145 ch
= tor_malloc(alloc
);
148 #ifdef DEBUG_CHUNK_ALLOC
149 ch
->DBG_alloc
= alloc
;
151 ch
->memlen
= CHUNK_SIZE_WITH_ALLOC(alloc
);
152 total_bytes_allocated_in_chunks
+= alloc
;
153 ch
->data
= &ch
->mem
[0];
154 CHUNK_SET_SENTINEL(ch
, alloc
);
158 /** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a
159 * new pointer to <b>chunk</b>. Old pointers are no longer valid. */
160 static inline chunk_t
*
161 chunk_grow(chunk_t
*chunk
, size_t sz
)
164 const size_t memlen_orig
= chunk
->memlen
;
165 const size_t orig_alloc
= CHUNK_ALLOC_SIZE(memlen_orig
);
166 const size_t new_alloc
= CHUNK_ALLOC_SIZE(sz
);
167 tor_assert(sz
> chunk
->memlen
);
168 offset
= chunk
->data
- chunk
->mem
;
169 chunk
= tor_realloc(chunk
, new_alloc
);
171 chunk
->data
= chunk
->mem
+ offset
;
172 #ifdef DEBUG_CHUNK_ALLOC
173 tor_assert(chunk
->DBG_alloc
== orig_alloc
);
174 chunk
->DBG_alloc
= new_alloc
;
176 total_bytes_allocated_in_chunks
+= new_alloc
- orig_alloc
;
177 CHUNK_SET_SENTINEL(chunk
, new_alloc
);
181 /** Every chunk should take up at least this many bytes. */
182 #define MIN_CHUNK_ALLOC 256
183 /** No chunk should take up more than this many bytes. */
184 #define MAX_CHUNK_ALLOC 65536
186 /** Return the allocation size we'd like to use to hold <b>target</b>
189 buf_preferred_chunk_size(size_t target
)
191 tor_assert(target
<= SIZE_T_CEILING
- CHUNK_OVERHEAD
);
192 if (CHUNK_ALLOC_SIZE(target
) >= MAX_CHUNK_ALLOC
)
193 return CHUNK_ALLOC_SIZE(target
);
194 size_t sz
= MIN_CHUNK_ALLOC
;
195 while (CHUNK_SIZE_WITH_ALLOC(sz
) < target
) {
201 /** Collapse data from the first N chunks from <b>buf</b> into buf->head,
202 * growing it as necessary, until buf->head has the first <b>bytes</b> bytes
203 * of data from the buffer, or until buf->head has all the data in <b>buf</b>.
205 * Set *<b>head_out</b> to point to the first byte of available data, and
206 * *<b>len_out</b> to the number of bytes of data available at
207 * *<b>head_out</b>. Note that *<b>len_out</b> may be more or less than
208 * <b>bytes</b>, depending on the number of bytes available.
211 buf_pullup(buf_t
*buf
, size_t bytes
, const char **head_out
, size_t *len_out
)
222 if (buf
->datalen
< bytes
)
223 bytes
= buf
->datalen
;
226 if (buf
->head
->datalen
>= bytes
) {
227 *head_out
= buf
->head
->data
;
228 *len_out
= buf
->head
->datalen
;
232 if (buf
->head
->memlen
>= capacity
) {
233 /* We don't need to grow the first chunk, but we might need to repack it.*/
234 size_t needed
= capacity
- buf
->head
->datalen
;
235 if (CHUNK_REMAINING_CAPACITY(buf
->head
) < needed
)
236 chunk_repack(buf
->head
);
237 tor_assert(CHUNK_REMAINING_CAPACITY(buf
->head
) >= needed
);
241 /* We need to grow the chunk. */
242 chunk_repack(buf
->head
);
243 newsize
= CHUNK_SIZE_WITH_ALLOC(buf_preferred_chunk_size(capacity
));
244 newhead
= chunk_grow(buf
->head
, newsize
);
245 tor_assert(newhead
->memlen
>= capacity
);
246 if (newhead
!= buf
->head
) {
247 if (buf
->tail
== buf
->head
)
254 while (dest
->datalen
< bytes
) {
255 size_t n
= bytes
- dest
->datalen
;
258 if (n
>= src
->datalen
) {
259 memcpy(CHUNK_WRITE_PTR(dest
), src
->data
, src
->datalen
);
260 dest
->datalen
+= src
->datalen
;
261 dest
->next
= src
->next
;
262 if (buf
->tail
== src
)
264 buf_chunk_free_unchecked(src
);
266 memcpy(CHUNK_WRITE_PTR(dest
), src
->data
, n
);
270 tor_assert(dest
->datalen
== bytes
);
275 *head_out
= buf
->head
->data
;
276 *len_out
= buf
->head
->datalen
;
279 #ifdef TOR_UNIT_TESTS
280 /* Write sz bytes from cp into a newly allocated buffer buf.
281 * Returns NULL when passed a NULL cp or zero sz.
282 * Asserts on failure: only for use in unit tests.
283 * buf must be freed using buf_free(). */
285 buf_new_with_data(const char *cp
, size_t sz
)
287 /* Validate arguments */
288 if (!cp
|| sz
<= 0 || sz
> BUF_MAX_LEN
) {
292 tor_assert(sz
< SSIZE_T_CEILING
);
294 /* Allocate a buffer */
295 buf_t
*buf
= buf_new_with_capacity(sz
);
298 tor_assert(!buf
->head
);
300 /* Allocate a chunk that is sz bytes long */
301 buf
->head
= chunk_new_with_alloc_size(CHUNK_ALLOC_SIZE(sz
));
302 buf
->tail
= buf
->head
;
303 tor_assert(buf
->head
);
305 tor_assert(buf_allocation(buf
) >= sz
);
307 /* Copy the data and size the buffers */
308 tor_assert(sz
<= buf_slack(buf
));
309 tor_assert(sz
<= CHUNK_REMAINING_CAPACITY(buf
->head
));
310 memcpy(&buf
->head
->mem
[0], cp
, sz
);
312 buf
->head
->datalen
= sz
;
313 buf
->head
->data
= &buf
->head
->mem
[0];
316 /* Make sure everything is large enough */
317 tor_assert(buf_allocation(buf
) >= sz
);
318 tor_assert(buf_allocation(buf
) >= buf_datalen(buf
) + buf_slack(buf
));
319 /* Does the buffer implementation allocate more than the requested size?
320 * (for example, by rounding up). If so, these checks will fail. */
321 tor_assert(buf_datalen(buf
) == sz
);
322 tor_assert(buf_slack(buf
) == 0);
326 #endif /* defined(TOR_UNIT_TESTS) */
328 /** Remove the first <b>n</b> bytes from buf. */
330 buf_drain(buf_t
*buf
, size_t n
)
332 tor_assert(buf
->datalen
>= n
);
334 tor_assert(buf
->head
);
335 if (buf
->head
->datalen
> n
) {
336 buf
->head
->datalen
-= n
;
337 buf
->head
->data
+= n
;
341 chunk_t
*victim
= buf
->head
;
342 n
-= victim
->datalen
;
343 buf
->datalen
-= victim
->datalen
;
344 buf
->head
= victim
->next
;
345 if (buf
->tail
== victim
)
347 buf_chunk_free_unchecked(victim
);
353 /** Create and return a new buf with default chunk capacity <b>size</b>.
356 buf_new_with_capacity(size_t size
)
358 buf_t
*b
= buf_new();
359 b
->default_chunk_size
= buf_preferred_chunk_size(size
);
363 /** Allocate and return a new buffer with default capacity. */
367 buf_t
*buf
= tor_malloc_zero(sizeof(buf_t
));
368 buf
->magic
= BUFFER_MAGIC
;
369 buf
->default_chunk_size
= 4096;
374 buf_get_default_chunk_size(const buf_t
*buf
)
376 return buf
->default_chunk_size
;
379 /** Remove all data from <b>buf</b>. */
381 buf_clear(buf_t
*buf
)
383 chunk_t
*chunk
, *next
;
385 for (chunk
= buf
->head
; chunk
; chunk
= next
) {
387 buf_chunk_free_unchecked(chunk
);
389 buf
->head
= buf
->tail
= NULL
;
392 /** Return the number of bytes stored in <b>buf</b> */
394 buf_datalen
, (const buf_t
*buf
))
399 /** Return the total length of all chunks used in <b>buf</b>. */
401 buf_allocation(const buf_t
*buf
)
404 const chunk_t
*chunk
;
405 for (chunk
= buf
->head
; chunk
; chunk
= chunk
->next
) {
406 total
+= CHUNK_ALLOC_SIZE(chunk
->memlen
);
411 /** Return the number of bytes that can be added to <b>buf</b> without
412 * performing any additional allocation. */
414 buf_slack(const buf_t
*buf
)
419 return CHUNK_REMAINING_CAPACITY(buf
->tail
);
422 /** Release storage held by <b>buf</b>. */
424 buf_free_(buf_t
*buf
)
430 buf
->magic
= 0xdeadbeef;
434 /** Return a new copy of <b>in_chunk</b> */
436 chunk_copy(const chunk_t
*in_chunk
)
438 chunk_t
*newch
= tor_memdup(in_chunk
, CHUNK_ALLOC_SIZE(in_chunk
->memlen
));
439 total_bytes_allocated_in_chunks
+= CHUNK_ALLOC_SIZE(in_chunk
->memlen
);
440 #ifdef DEBUG_CHUNK_ALLOC
441 newch
->DBG_alloc
= CHUNK_ALLOC_SIZE(in_chunk
->memlen
);
444 if (in_chunk
->data
) {
445 ptrdiff_t offset
= in_chunk
->data
- in_chunk
->mem
;
446 newch
->data
= newch
->mem
+ offset
;
451 /** Return a new copy of <b>buf</b> */
453 buf_copy(const buf_t
*buf
)
456 buf_t
*out
= buf_new();
457 out
->default_chunk_size
= buf
->default_chunk_size
;
458 for (ch
= buf
->head
; ch
; ch
= ch
->next
) {
459 chunk_t
*newch
= chunk_copy(ch
);
461 out
->tail
->next
= newch
;
464 out
->head
= out
->tail
= newch
;
467 out
->datalen
= buf
->datalen
;
471 /** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
472 * the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
473 * than MAX_CHUNK_ALLOC. */
475 buf_add_chunk_with_capacity(buf_t
*buf
, size_t capacity
, int capped
)
479 if (CHUNK_ALLOC_SIZE(capacity
) < buf
->default_chunk_size
) {
480 chunk
= chunk_new_with_alloc_size(buf
->default_chunk_size
);
481 } else if (capped
&& CHUNK_ALLOC_SIZE(capacity
) > MAX_CHUNK_ALLOC
) {
482 chunk
= chunk_new_with_alloc_size(MAX_CHUNK_ALLOC
);
484 chunk
= chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity
));
487 chunk
->inserted_time
= monotime_coarse_get_stamp();
490 tor_assert(buf
->head
);
491 buf
->tail
->next
= chunk
;
494 tor_assert(!buf
->head
);
495 buf
->head
= buf
->tail
= chunk
;
501 /** Return the age of the oldest chunk in the buffer <b>buf</b>, in
502 * timestamp units. Requires the current monotonic timestamp as its
506 buf_get_oldest_chunk_timestamp(const buf_t
*buf
, uint32_t now
)
509 return now
- buf
->head
->inserted_time
;
516 buf_get_total_allocation(void)
518 return total_bytes_allocated_in_chunks
;
521 /** Append <b>string_len</b> bytes from <b>string</b> to the end of
524 * Return the new length of the buffer on success, -1 on failure.
527 buf_add(buf_t
*buf
, const char *string
, size_t string_len
)
530 return (int)buf
->datalen
;
533 if (BUG(buf
->datalen
> BUF_MAX_LEN
))
535 if (BUG(buf
->datalen
> BUF_MAX_LEN
- string_len
))
540 if (!buf
->tail
|| !CHUNK_REMAINING_CAPACITY(buf
->tail
))
541 buf_add_chunk_with_capacity(buf
, string_len
, 1);
543 copy
= CHUNK_REMAINING_CAPACITY(buf
->tail
);
544 if (copy
> string_len
)
546 memcpy(CHUNK_WRITE_PTR(buf
->tail
), string
, copy
);
549 buf
->datalen
+= copy
;
550 buf
->tail
->datalen
+= copy
;
554 tor_assert(buf
->datalen
<= BUF_MAX_LEN
);
555 return (int)buf
->datalen
;
558 /** Add a nul-terminated <b>string</b> to <b>buf</b>, not including the
559 * terminating NUL. */
561 buf_add_string(buf_t
*buf
, const char *string
)
563 buf_add(buf
, string
, strlen(string
));
566 /** As tor_snprintf, but write the results into a buf_t */
568 buf_add_printf(buf_t
*buf
, const char *format
, ...)
572 buf_add_vprintf(buf
, format
, ap
);
576 /** As tor_vsnprintf, but write the results into a buf_t. */
578 buf_add_vprintf(buf_t
*buf
, const char *format
, va_list args
)
580 /* XXXX Faster implementations are easy enough, but let's optimize later */
582 tor_vasprintf(&tmp
, format
, args
);
583 tor_assert(tmp
!= NULL
);
584 buf_add(buf
, tmp
, strlen(tmp
));
588 /** Return a heap-allocated string containing the contents of <b>buf</b>, plus
589 * a NUL byte. If <b>sz_out</b> is provided, set *<b>sz_out</b> to the length
590 * of the returned string, not including the terminating NUL. */
592 buf_extract(buf_t
*buf
, size_t *sz_out
)
596 size_t sz
= buf_datalen(buf
);
598 result
= tor_malloc(sz
+1);
599 buf_peek(buf
, result
, sz
);
606 /** Helper: copy the first <b>string_len</b> bytes from <b>buf</b>
607 * onto <b>string</b>.
610 buf_peek(const buf_t
*buf
, char *string
, size_t string_len
)
615 /* make sure we don't ask for too much */
616 tor_assert(string_len
<= buf
->datalen
);
617 /* buf_assert_ok(buf); */
621 size_t copy
= string_len
;
623 if (chunk
->datalen
< copy
)
624 copy
= chunk
->datalen
;
625 memcpy(string
, chunk
->data
, copy
);
632 /** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store
633 * them into <b>string</b>. Return the new buffer size. <b>string_len</b>
634 * must be \<= the number of bytes on the buffer.
637 buf_get_bytes(buf_t
*buf
, char *string
, size_t string_len
)
639 /* There must be string_len bytes in buf; write them onto string,
640 * then memmove buf back (that is, remove them from buf).
642 * Return the number of bytes still on the buffer. */
645 buf_peek(buf
, string
, string_len
);
646 buf_drain(buf
, string_len
);
648 tor_assert(buf
->datalen
<= BUF_MAX_LEN
);
649 return (int)buf
->datalen
;
652 /** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
653 * <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
654 * Return the number of bytes actually copied.
657 buf_move_to_buf(buf_t
*buf_out
, buf_t
*buf_in
, size_t *buf_flushlen
)
659 /* We can do way better here, but this doesn't turn up in any profiles. */
663 if (BUG(buf_out
->datalen
> BUF_MAX_LEN
|| *buf_flushlen
> BUF_MAX_LEN
))
665 if (BUG(buf_out
->datalen
> BUF_MAX_LEN
- *buf_flushlen
))
669 if (len
> buf_in
->datalen
)
670 len
= buf_in
->datalen
;
672 cp
= len
; /* Remember the number of bytes we intend to copy. */
673 tor_assert(cp
<= BUF_MAX_LEN
);
675 /* This isn't the most efficient implementation one could imagine, since
676 * it does two copies instead of 1, but I kinda doubt that this will be
678 size_t n
= len
> sizeof(b
) ? sizeof(b
) : len
;
679 buf_get_bytes(buf_in
, b
, n
);
680 buf_add(buf_out
, b
, n
);
687 /** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying.
688 * Return the number of bytes that were moved.
691 buf_move_all(buf_t
*buf_out
, buf_t
*buf_in
)
696 if (buf_datalen(buf_in
) == 0)
698 if (BUG(buf_out
->datalen
> BUF_MAX_LEN
|| buf_in
->datalen
> BUF_MAX_LEN
))
700 if (BUG(buf_out
->datalen
> BUF_MAX_LEN
- buf_in
->datalen
))
703 size_t n_bytes_moved
= buf_in
->datalen
;
705 if (buf_out
->head
== NULL
) {
706 buf_out
->head
= buf_in
->head
;
707 buf_out
->tail
= buf_in
->tail
;
709 buf_out
->tail
->next
= buf_in
->head
;
710 buf_out
->tail
= buf_in
->tail
;
713 buf_out
->datalen
+= buf_in
->datalen
;
714 buf_in
->head
= buf_in
->tail
= NULL
;
717 return n_bytes_moved
;
720 /** Internal structure: represents a position in a buffer. */
721 typedef struct buf_pos_t
{
722 const chunk_t
*chunk
; /**< Which chunk are we pointing to? */
723 ptrdiff_t pos
;/**< Which character inside the chunk's data are we pointing
725 size_t chunk_pos
; /**< Total length of all previous chunks. */
728 /** Initialize <b>out</b> to point to the first character of <b>buf</b>.*/
730 buf_pos_init(const buf_t
*buf
, buf_pos_t
*out
)
732 out
->chunk
= buf
->head
;
737 /** Advance <b>out</b> to the first appearance of <b>ch</b> at the current
738 * position of <b>out</b>, or later. Return -1 if no instances are found;
739 * otherwise returns the absolute position of the character. */
741 buf_find_pos_of_char(char ch
, buf_pos_t
*out
)
743 const chunk_t
*chunk
;
747 if (out
->chunk
->datalen
) {
748 tor_assert(out
->pos
< (ptrdiff_t)out
->chunk
->datalen
);
750 tor_assert(out
->pos
== 0);
754 for (chunk
= out
->chunk
; chunk
; chunk
= chunk
->next
) {
755 char *cp
= memchr(chunk
->data
+pos
, ch
, chunk
->datalen
- pos
);
758 tor_assert(cp
- chunk
->data
<= BUF_MAX_LEN
);
759 out
->pos
= (int)(cp
- chunk
->data
);
760 return out
->chunk_pos
+ out
->pos
;
762 out
->chunk_pos
+= chunk
->datalen
;
769 /** Advance <b>pos</b> by a single character, if there are any more characters
770 * in the buffer. Returns 0 on success, -1 on failure. */
772 buf_pos_inc(buf_pos_t
*pos
)
774 tor_assert(pos
->pos
< BUF_MAX_LEN
);
776 if (pos
->pos
== (ptrdiff_t)pos
->chunk
->datalen
) {
777 if (!pos
->chunk
->next
)
779 pos
->chunk_pos
+= pos
->chunk
->datalen
;
780 pos
->chunk
= pos
->chunk
->next
;
786 /** Return true iff the <b>n</b>-character string in <b>s</b> appears
787 * (verbatim) at <b>pos</b>. */
789 buf_matches_at_pos(const buf_pos_t
*pos
, const char *s
, size_t n
)
795 memcpy(&p
, pos
, sizeof(p
));
798 char ch
= p
.chunk
->data
[p
.pos
];
802 /* If we're out of characters that don't match, we match. Check this
803 * _before_ we test incrementing pos, in case we're at the end of the
807 if (buf_pos_inc(&p
)<0)
812 /** Return the first position in <b>buf</b> at which the <b>n</b>-character
813 * string <b>s</b> occurs, or -1 if it does not occur. */
815 buf_find_string_offset(const buf_t
*buf
, const char *s
, size_t n
)
818 buf_pos_init(buf
, &pos
);
819 while (buf_find_pos_of_char(*s
, &pos
) >= 0) {
820 if (buf_matches_at_pos(&pos
, s
, n
)) {
821 tor_assert(pos
.chunk_pos
+ pos
.pos
<= BUF_MAX_LEN
);
822 return (int)(pos
.chunk_pos
+ pos
.pos
);
824 if (buf_pos_inc(&pos
)<0)
831 /** Return 1 iff <b>buf</b> starts with <b>cmd</b>. <b>cmd</b> must be a null
832 * terminated string, of no more than PEEK_BUF_STARTSWITH_MAX bytes. */
834 buf_peek_startswith(const buf_t
*buf
, const char *cmd
)
836 char tmp
[PEEK_BUF_STARTSWITH_MAX
];
837 size_t clen
= strlen(cmd
);
840 if (BUG(clen
> sizeof(tmp
)))
842 if (buf
->datalen
< clen
)
844 buf_peek(buf
, tmp
, clen
);
845 return fast_memeq(tmp
, cmd
, clen
);
848 /** Return the index within <b>buf</b> at which <b>ch</b> first appears,
849 * or -1 if <b>ch</b> does not appear on buf. */
851 buf_find_offset_of_char(buf_t
*buf
, char ch
)
854 ptrdiff_t offset
= 0;
855 tor_assert(buf
->datalen
<= BUF_MAX_LEN
);
856 for (chunk
= buf
->head
; chunk
; chunk
= chunk
->next
) {
857 char *cp
= memchr(chunk
->data
, ch
, chunk
->datalen
);
859 return offset
+ (cp
- chunk
->data
);
861 offset
+= chunk
->datalen
;
866 /** Try to read a single LF-terminated line from <b>buf</b>, and write it
867 * (including the LF), NUL-terminated, into the *<b>data_len</b> byte buffer
868 * at <b>data_out</b>. Set *<b>data_len</b> to the number of bytes in the
869 * line, not counting the terminating NUL. Return 1 if we read a whole line,
870 * return 0 if we don't have a whole line yet, and return -1 if the line
871 * length exceeds *<b>data_len</b>.
874 buf_get_line(buf_t
*buf
, char *data_out
, size_t *data_len
)
882 offset
= buf_find_offset_of_char(buf
, '\n');
885 sz
= (size_t) offset
;
886 if (sz
+2 > *data_len
) {
890 buf_get_bytes(buf
, data_out
, sz
+1);
891 data_out
[sz
+1] = '\0';
896 /** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
898 buf_set_to_copy(buf_t
**output
,
903 *output
= buf_copy(input
);
907 /** Log an error and exit if <b>buf</b> is corrupted.
910 buf_assert_ok(buf_t
*buf
)
913 tor_assert(buf
->magic
== BUFFER_MAGIC
);
916 tor_assert(!buf
->tail
);
917 tor_assert(buf
->datalen
== 0);
921 tor_assert(buf
->tail
);
922 for (ch
= buf
->head
; ch
; ch
= ch
->next
) {
923 total
+= ch
->datalen
;
924 tor_assert(ch
->datalen
<= ch
->memlen
);
925 tor_assert(ch
->datalen
<= BUF_MAX_LEN
);
926 tor_assert(ch
->data
>= &ch
->mem
[0]);
927 tor_assert(ch
->data
<= &ch
->mem
[0]+ch
->memlen
);
928 if (ch
->data
== &ch
->mem
[0]+ch
->memlen
) {
929 /* LCOV_EXCL_START */
930 static int warned
= 0;
932 log_warn(LD_BUG
, "Invariant violation in buf.c related to #15083");
937 tor_assert(ch
->data
+ch
->datalen
<= &ch
->mem
[0] + ch
->memlen
);
939 tor_assert(ch
== buf
->tail
);
941 tor_assert(buf
->datalen
== total
);