2006-02-09 06:46:49 +01:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
2018-06-28 23:21:15 +02:00
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2019-01-16 18:32:32 +01:00
|
|
|
* Copyright (c) 2007-2019, The Tor Project, Inc. */
|
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-07 19:04:12 +02:00
|
|
|
/**
|
|
|
|
* \file buffers.c
|
2016-10-15 02:08:51 +02:00
|
|
|
* \brief Implements a generic buffer interface.
|
|
|
|
*
|
|
|
|
* A buf_t is a (fairly) opaque byte-oriented FIFO that can read to or flush
|
|
|
|
* from memory, sockets, file descriptors, TLS connections, or another buf_t.
|
|
|
|
* Buffers are implemented as linked lists of memory chunks.
|
|
|
|
*
|
|
|
|
* All socket-backed and TLS-based connection_t objects have a pair of
|
|
|
|
* buffers: one for incoming data, and one for outcoming data. These are fed
|
|
|
|
* and drained from functions in connection.c, trigged by events that are
|
|
|
|
* monitored in main.c.
|
2018-07-02 02:22:55 +02:00
|
|
|
*
|
|
|
|
* This module only handles the buffer implementation itself. To use a buffer
|
|
|
|
* with the network, a compressor, or a TLS connection, see the other buffer_*
|
|
|
|
* modules.
|
2004-05-07 19:04:12 +02:00
|
|
|
**/
|
2017-08-08 18:23:39 +02:00
|
|
|
|
2008-02-21 00:20:36 +01:00
|
|
|
#define BUFFERS_PRIVATE
|
2017-08-08 18:23:39 +02:00
|
|
|
#include "orconfig.h"
|
|
|
|
#include <stddef.h>
|
2018-06-28 22:25:06 +02:00
|
|
|
#include "lib/container/buffers.h"
|
2018-06-21 18:20:52 +02:00
|
|
|
#include "lib/cc/torint.h"
|
2018-07-10 21:20:28 +02:00
|
|
|
#include "lib/log/log.h"
|
2018-06-28 22:25:06 +02:00
|
|
|
#include "lib/log/util_bug.h"
|
|
|
|
#include "lib/ctime/di_ops.h"
|
2018-07-10 21:16:57 +02:00
|
|
|
#include "lib/malloc/malloc.h"
|
2018-06-28 22:25:06 +02:00
|
|
|
#include "lib/string/printf.h"
|
|
|
|
#include "lib/time/compat_time.h"
|
|
|
|
|
2008-06-11 19:56:52 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2018-06-28 22:25:06 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2007-12-26 19:09:36 +01:00
|
|
|
//#define PARANOIA
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
#ifdef PARANOIA
|
2008-02-12 21:20:52 +01:00
|
|
|
/** Helper: If PARANOIA is defined, assert that the buffer in local variable
|
|
|
|
* <b>buf</b> is well-formed. */
|
2017-08-08 21:16:39 +02:00
|
|
|
#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
|
2005-04-27 02:53:44 +02:00
|
|
|
#else
|
2007-06-17 20:22:39 +02:00
|
|
|
#define check() STMT_NIL
|
2017-09-15 22:24:44 +02:00
|
|
|
#endif /* defined(PARANOIA) */
|
2005-04-27 02:53:44 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/* Implementation notes:
|
|
|
|
*
|
|
|
|
* After flirting with memmove, and dallying with ring-buffers, we're finally
|
|
|
|
* getting up to speed with the 1970s and implementing buffers as a linked
|
|
|
|
* list of small chunks. Each buffer has such a list; data is removed from
|
|
|
|
* the head of the list, and added at the tail. The list is singly linked,
|
|
|
|
* and the buffer keeps a pointer to the head and the tail.
|
|
|
|
*
|
|
|
|
* Every chunk, except the tail, contains at least one byte of data. Data in
|
|
|
|
* each chunk is contiguous.
|
|
|
|
*
|
|
|
|
* When you need to treat the first N characters on a buffer as a contiguous
|
|
|
|
* string, use the buf_pullup function to make them so. Don't do this more
|
|
|
|
* than necessary.
|
|
|
|
*
|
|
|
|
* The major free Unix kernels have handled buffers like this since, like,
|
|
|
|
* forever.
|
2005-06-08 19:27:11 +02:00
|
|
|
*/
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/* Chunk manipulation functions */
|
|
|
|
|
2017-08-01 01:30:30 +02:00
|
|
|
#define CHUNK_HEADER_LEN offsetof(chunk_t, mem[0])
|
2008-07-31 14:18:14 +02:00
|
|
|
|
2016-10-14 15:38:12 +02:00
|
|
|
/* We leave this many NUL bytes at the end of the buffer. */
|
2017-02-13 15:10:11 +01:00
|
|
|
#ifdef DISABLE_MEMORY_SENTINELS
|
|
|
|
#define SENTINEL_LEN 0
|
|
|
|
#else
|
2016-10-14 15:38:12 +02:00
|
|
|
#define SENTINEL_LEN 4
|
2017-02-13 15:10:11 +01:00
|
|
|
#endif
|
2016-10-14 15:38:12 +02:00
|
|
|
|
|
|
|
/* Header size plus NUL bytes at the end */
|
|
|
|
#define CHUNK_OVERHEAD (CHUNK_HEADER_LEN + SENTINEL_LEN)
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes needed to allocate a chunk to hold
|
|
|
|
* <b>memlen</b> bytes. */
|
2016-10-14 15:38:12 +02:00
|
|
|
#define CHUNK_ALLOC_SIZE(memlen) (CHUNK_OVERHEAD + (memlen))
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of usable bytes in a chunk allocated with
|
|
|
|
* malloc(<b>memlen</b>). */
|
2016-10-14 15:38:12 +02:00
|
|
|
#define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_OVERHEAD)
|
|
|
|
|
|
|
|
#define DEBUG_SENTINEL
|
|
|
|
|
2017-02-13 15:10:11 +01:00
|
|
|
#if defined(DEBUG_SENTINEL) && !defined(DISABLE_MEMORY_SENTINELS)
|
2016-10-14 15:38:12 +02:00
|
|
|
#define DBG_S(s) s
|
|
|
|
#else
|
|
|
|
#define DBG_S(s) (void)0
|
|
|
|
#endif
|
|
|
|
|
2017-02-13 15:10:11 +01:00
|
|
|
#ifdef DISABLE_MEMORY_SENTINELS
|
|
|
|
#define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL
|
|
|
|
#else
|
2016-10-14 15:38:12 +02:00
|
|
|
#define CHUNK_SET_SENTINEL(chunk, alloclen) do { \
|
|
|
|
uint8_t *a = (uint8_t*) &(chunk)->mem[(chunk)->memlen]; \
|
|
|
|
DBG_S(uint8_t *b = &((uint8_t*)(chunk))[(alloclen)-SENTINEL_LEN]); \
|
|
|
|
DBG_S(tor_assert(a == b)); \
|
|
|
|
memset(a,0,SENTINEL_LEN); \
|
|
|
|
} while (0)
|
2017-09-15 22:24:44 +02:00
|
|
|
#endif /* defined(DISABLE_MEMORY_SENTINELS) */
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
|
|
|
|
* to free up space at the end. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline void
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_repack(chunk_t *chunk)
|
2005-06-17 20:49:55 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (chunk->datalen && chunk->data != &chunk->mem[0]) {
|
|
|
|
memmove(chunk->mem, chunk->data, chunk->datalen);
|
|
|
|
}
|
|
|
|
chunk->data = &chunk->mem[0];
|
2005-06-17 20:49:55 +02:00
|
|
|
}
|
|
|
|
|
2014-04-29 11:18:34 +02:00
|
|
|
/** Keep track of total size of allocated chunks for consistency asserts */
|
|
|
|
static size_t total_bytes_allocated_in_chunks = 0;
|
2008-01-13 01:20:44 +01:00
|
|
|
static void
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_chunk_free_unchecked(chunk_t *chunk)
|
2008-01-13 01:20:44 +01:00
|
|
|
{
|
2013-11-16 00:38:52 +01:00
|
|
|
if (!chunk)
|
|
|
|
return;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
tor_assert(CHUNK_ALLOC_SIZE(chunk->memlen) == chunk->DBG_alloc);
|
|
|
|
#endif
|
2014-03-05 20:36:32 +01:00
|
|
|
tor_assert(total_bytes_allocated_in_chunks >=
|
|
|
|
CHUNK_ALLOC_SIZE(chunk->memlen));
|
2013-11-16 00:38:52 +01:00
|
|
|
total_bytes_allocated_in_chunks -= CHUNK_ALLOC_SIZE(chunk->memlen);
|
2008-01-13 01:20:44 +01:00
|
|
|
tor_free(chunk);
|
|
|
|
}
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline chunk_t *
|
2008-01-13 01:20:44 +01:00
|
|
|
chunk_new_with_alloc_size(size_t alloc)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
2012-08-13 19:27:32 +02:00
|
|
|
ch = tor_malloc(alloc);
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->next = NULL;
|
|
|
|
ch->datalen = 0;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
ch->DBG_alloc = alloc;
|
|
|
|
#endif
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
|
2013-11-16 00:38:52 +01:00
|
|
|
total_bytes_allocated_in_chunks += alloc;
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->data = &ch->mem[0];
|
2016-10-14 15:38:12 +02:00
|
|
|
CHUNK_SET_SENTINEL(ch, alloc);
|
2008-01-13 01:20:44 +01:00
|
|
|
return ch;
|
|
|
|
}
|
2007-07-27 20:33:37 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a
|
|
|
|
* new pointer to <b>chunk</b>. Old pointers are no longer valid. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline chunk_t *
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_grow(chunk_t *chunk, size_t sz)
|
|
|
|
{
|
|
|
|
off_t offset;
|
2016-10-14 15:38:12 +02:00
|
|
|
const size_t memlen_orig = chunk->memlen;
|
|
|
|
const size_t orig_alloc = CHUNK_ALLOC_SIZE(memlen_orig);
|
|
|
|
const size_t new_alloc = CHUNK_ALLOC_SIZE(sz);
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(sz > chunk->memlen);
|
|
|
|
offset = chunk->data - chunk->mem;
|
2016-10-14 15:38:12 +02:00
|
|
|
chunk = tor_realloc(chunk, new_alloc);
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk->memlen = sz;
|
|
|
|
chunk->data = chunk->mem + offset;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
2016-10-14 15:38:12 +02:00
|
|
|
tor_assert(chunk->DBG_alloc == orig_alloc);
|
|
|
|
chunk->DBG_alloc = new_alloc;
|
2014-01-03 19:56:46 +01:00
|
|
|
#endif
|
2016-10-14 15:38:12 +02:00
|
|
|
total_bytes_allocated_in_chunks += new_alloc - orig_alloc;
|
|
|
|
CHUNK_SET_SENTINEL(chunk, new_alloc);
|
2007-12-26 01:12:08 +01:00
|
|
|
return chunk;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Every chunk should take up at least this many bytes. */
|
|
|
|
#define MIN_CHUNK_ALLOC 256
|
2008-02-12 21:20:52 +01:00
|
|
|
/** No chunk should take up more than this many bytes. */
|
2007-12-26 01:12:08 +01:00
|
|
|
#define MAX_CHUNK_ALLOC 65536
|
|
|
|
|
|
|
|
/** Return the allocation size we'd like to use to hold <b>target</b>
|
|
|
|
* bytes. */
|
2017-09-05 20:15:38 +02:00
|
|
|
size_t
|
|
|
|
buf_preferred_chunk_size(size_t target)
|
2007-04-23 16:42:27 +02:00
|
|
|
{
|
2016-10-17 20:52:44 +02:00
|
|
|
tor_assert(target <= SIZE_T_CEILING - CHUNK_OVERHEAD);
|
2016-09-13 15:07:12 +02:00
|
|
|
if (CHUNK_ALLOC_SIZE(target) >= MAX_CHUNK_ALLOC)
|
|
|
|
return CHUNK_ALLOC_SIZE(target);
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t sz = MIN_CHUNK_ALLOC;
|
|
|
|
while (CHUNK_SIZE_WITH_ALLOC(sz) < target) {
|
|
|
|
sz <<= 1;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
return sz;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Collapse data from the first N chunks from <b>buf</b> into buf->head,
|
|
|
|
* growing it as necessary, until buf->head has the first <b>bytes</b> bytes
|
|
|
|
* of data from the buffer, or until buf->head has all the data in <b>buf</b>.
|
2017-08-08 18:07:25 +02:00
|
|
|
*
|
|
|
|
* Set *<b>head_out</b> to point to the first byte of available data, and
|
|
|
|
* *<b>len_out</b> to the number of bytes of data available at
|
|
|
|
* *<b>head_out</b>. Note that *<b>len_out</b> may be more or less than
|
|
|
|
* <b>bytes</b>, depending on the number of bytes available.
|
2015-09-02 14:50:26 +02:00
|
|
|
*/
|
2017-08-08 17:51:36 +02:00
|
|
|
void
|
2017-08-08 18:07:25 +02:00
|
|
|
buf_pullup(buf_t *buf, size_t bytes, const char **head_out, size_t *len_out)
|
2007-12-26 01:12:08 +01:00
|
|
|
{
|
|
|
|
chunk_t *dest, *src;
|
|
|
|
size_t capacity;
|
2017-08-08 18:07:25 +02:00
|
|
|
if (!buf->head) {
|
|
|
|
*head_out = NULL;
|
|
|
|
*len_out = 0;
|
2005-05-03 01:17:08 +02:00
|
|
|
return;
|
2017-08-08 18:07:25 +02:00
|
|
|
}
|
2005-05-03 01:17:08 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
if (buf->datalen < bytes)
|
|
|
|
bytes = buf->datalen;
|
|
|
|
|
2015-09-01 20:36:25 +02:00
|
|
|
capacity = bytes;
|
2017-08-08 18:07:25 +02:00
|
|
|
if (buf->head->datalen >= bytes) {
|
|
|
|
*head_out = buf->head->data;
|
|
|
|
*len_out = buf->head->datalen;
|
2015-09-01 20:36:25 +02:00
|
|
|
return;
|
2017-08-08 18:07:25 +02:00
|
|
|
}
|
2005-06-08 19:27:11 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (buf->head->memlen >= capacity) {
|
|
|
|
/* We don't need to grow the first chunk, but we might need to repack it.*/
|
2011-12-14 22:38:43 +01:00
|
|
|
size_t needed = capacity - buf->head->datalen;
|
|
|
|
if (CHUNK_REMAINING_CAPACITY(buf->head) < needed)
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_repack(buf->head);
|
2011-12-14 22:38:43 +01:00
|
|
|
tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed);
|
2005-06-08 19:27:11 +02:00
|
|
|
} else {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *newhead;
|
|
|
|
size_t newsize;
|
|
|
|
/* We need to grow the chunk. */
|
|
|
|
chunk_repack(buf->head);
|
2017-09-05 20:15:38 +02:00
|
|
|
newsize = CHUNK_SIZE_WITH_ALLOC(buf_preferred_chunk_size(capacity));
|
2007-12-26 01:12:08 +01:00
|
|
|
newhead = chunk_grow(buf->head, newsize);
|
|
|
|
tor_assert(newhead->memlen >= capacity);
|
|
|
|
if (newhead != buf->head) {
|
|
|
|
if (buf->tail == buf->head)
|
|
|
|
buf->tail = newhead;
|
|
|
|
buf->head = newhead;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2005-06-08 19:27:11 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
dest = buf->head;
|
|
|
|
while (dest->datalen < bytes) {
|
|
|
|
size_t n = bytes - dest->datalen;
|
|
|
|
src = dest->next;
|
|
|
|
tor_assert(src);
|
2015-03-03 22:20:17 +01:00
|
|
|
if (n >= src->datalen) {
|
2007-12-26 01:12:08 +01:00
|
|
|
memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen);
|
|
|
|
dest->datalen += src->datalen;
|
|
|
|
dest->next = src->next;
|
|
|
|
if (buf->tail == src)
|
|
|
|
buf->tail = dest;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_chunk_free_unchecked(src);
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
|
|
|
memcpy(CHUNK_WRITE_PTR(dest), src->data, n);
|
|
|
|
dest->datalen += n;
|
|
|
|
src->data += n;
|
|
|
|
src->datalen -= n;
|
|
|
|
tor_assert(dest->datalen == bytes);
|
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
check();
|
2017-08-08 18:07:25 +02:00
|
|
|
*head_out = buf->head->data;
|
|
|
|
*len_out = buf->head->datalen;
|
2003-10-14 03:34:31 +02:00
|
|
|
}
|
|
|
|
|
2014-01-04 19:30:56 +01:00
|
|
|
#ifdef TOR_UNIT_TESTS
|
2016-12-14 01:13:57 +01:00
|
|
|
/* Write sz bytes from cp into a newly allocated buffer buf.
|
|
|
|
* Returns NULL when passed a NULL cp or zero sz.
|
|
|
|
* Asserts on failure: only for use in unit tests.
|
|
|
|
* buf must be freed using buf_free(). */
|
|
|
|
buf_t *
|
|
|
|
buf_new_with_data(const char *cp, size_t sz)
|
|
|
|
{
|
|
|
|
/* Validate arguments */
|
|
|
|
if (!cp || sz <= 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tor_assert(sz < SSIZE_T_CEILING);
|
|
|
|
|
|
|
|
/* Allocate a buffer */
|
|
|
|
buf_t *buf = buf_new_with_capacity(sz);
|
|
|
|
tor_assert(buf);
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_assert_ok(buf);
|
2016-12-14 01:13:57 +01:00
|
|
|
tor_assert(!buf->head);
|
|
|
|
|
|
|
|
/* Allocate a chunk that is sz bytes long */
|
|
|
|
buf->head = chunk_new_with_alloc_size(CHUNK_ALLOC_SIZE(sz));
|
|
|
|
buf->tail = buf->head;
|
|
|
|
tor_assert(buf->head);
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_assert_ok(buf);
|
2016-12-14 01:13:57 +01:00
|
|
|
tor_assert(buf_allocation(buf) >= sz);
|
|
|
|
|
|
|
|
/* Copy the data and size the buffers */
|
|
|
|
tor_assert(sz <= buf_slack(buf));
|
|
|
|
tor_assert(sz <= CHUNK_REMAINING_CAPACITY(buf->head));
|
|
|
|
memcpy(&buf->head->mem[0], cp, sz);
|
|
|
|
buf->datalen = sz;
|
|
|
|
buf->head->datalen = sz;
|
|
|
|
buf->head->data = &buf->head->mem[0];
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_assert_ok(buf);
|
2016-12-14 01:13:57 +01:00
|
|
|
|
|
|
|
/* Make sure everything is large enough */
|
|
|
|
tor_assert(buf_allocation(buf) >= sz);
|
|
|
|
tor_assert(buf_allocation(buf) >= buf_datalen(buf) + buf_slack(buf));
|
|
|
|
/* Does the buffer implementation allocate more than the requested size?
|
|
|
|
* (for example, by rounding up). If so, these checks will fail. */
|
|
|
|
tor_assert(buf_datalen(buf) == sz);
|
|
|
|
tor_assert(buf_slack(buf) == 0);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2017-09-15 22:24:44 +02:00
|
|
|
#endif /* defined(TOR_UNIT_TESTS) */
|
2014-01-04 19:30:56 +01:00
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Remove the first <b>n</b> bytes from buf. */
|
2017-08-08 17:51:36 +02:00
|
|
|
void
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_drain(buf_t *buf, size_t n)
|
2005-09-30 03:09:52 +02:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(buf->datalen >= n);
|
2007-12-26 01:12:08 +01:00
|
|
|
while (n) {
|
|
|
|
tor_assert(buf->head);
|
|
|
|
if (buf->head->datalen > n) {
|
|
|
|
buf->head->datalen -= n;
|
|
|
|
buf->head->data += n;
|
|
|
|
buf->datalen -= n;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
chunk_t *victim = buf->head;
|
|
|
|
n -= victim->datalen;
|
|
|
|
buf->datalen -= victim->datalen;
|
|
|
|
buf->head = victim->next;
|
|
|
|
if (buf->tail == victim)
|
|
|
|
buf->tail = NULL;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_chunk_free_unchecked(victim);
|
2007-07-30 19:47:43 +02:00
|
|
|
}
|
2005-05-03 01:32:23 +02:00
|
|
|
}
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2003-10-14 03:34:31 +02:00
|
|
|
}
|
|
|
|
|
2008-02-16 00:39:04 +01:00
|
|
|
/** Create and return a new buf with default chunk capacity <b>size</b>.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
buf_t *
|
2005-09-30 03:09:52 +02:00
|
|
|
buf_new_with_capacity(size_t size)
|
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_t *b = buf_new();
|
2017-09-05 20:15:38 +02:00
|
|
|
b->default_chunk_size = buf_preferred_chunk_size(size);
|
2007-12-26 01:12:08 +01:00
|
|
|
return b;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-07 19:04:12 +02:00
|
|
|
/** Allocate and return a new buffer with default capacity. */
|
2005-06-11 20:52:12 +02:00
|
|
|
buf_t *
|
|
|
|
buf_new(void)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_t *buf = tor_malloc_zero(sizeof(buf_t));
|
|
|
|
buf->magic = BUFFER_MAGIC;
|
|
|
|
buf->default_chunk_size = 4096;
|
|
|
|
return buf;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2014-01-04 19:30:56 +01:00
|
|
|
size_t
|
|
|
|
buf_get_default_chunk_size(const buf_t *buf)
|
|
|
|
{
|
|
|
|
return buf->default_chunk_size;
|
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Remove all data from <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
buf_clear(buf_t *buf)
|
2004-02-28 20:14:11 +01:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk, *next;
|
2004-02-28 20:14:11 +01:00
|
|
|
buf->datalen = 0;
|
2007-12-26 01:12:08 +01:00
|
|
|
for (chunk = buf->head; chunk; chunk = next) {
|
|
|
|
next = chunk->next;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_chunk_free_unchecked(chunk);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
buf->head = buf->tail = NULL;
|
2004-02-28 20:14:11 +01:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Return the number of bytes stored in <b>buf</b> */
|
2014-01-23 15:42:14 +01:00
|
|
|
MOCK_IMPL(size_t,
|
|
|
|
buf_datalen, (const buf_t *buf))
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
|
|
|
return buf->datalen;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the total length of all chunks used in <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
size_t
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_allocation(const buf_t *buf)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t total = 0;
|
|
|
|
const chunk_t *chunk;
|
|
|
|
for (chunk = buf->head; chunk; chunk = chunk->next) {
|
2013-11-20 17:56:35 +01:00
|
|
|
total += CHUNK_ALLOC_SIZE(chunk->memlen);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
return total;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes that can be added to <b>buf</b> without
|
|
|
|
* performing any additional allocation. */
|
|
|
|
size_t
|
|
|
|
buf_slack(const buf_t *buf)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!buf->tail)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return CHUNK_REMAINING_CAPACITY(buf->tail);
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Release storage held by <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2017-11-17 18:27:25 +01:00
|
|
|
buf_free_(buf_t *buf)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
if (!buf)
|
|
|
|
return;
|
2009-07-31 17:11:45 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_clear(buf);
|
|
|
|
buf->magic = 0xdeadbeef;
|
|
|
|
tor_free(buf);
|
|
|
|
}
|
|
|
|
|
2011-07-18 21:36:20 +02:00
|
|
|
/** Return a new copy of <b>in_chunk</b> */
|
|
|
|
static chunk_t *
|
|
|
|
chunk_copy(const chunk_t *in_chunk)
|
|
|
|
{
|
|
|
|
chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen));
|
2014-01-03 19:56:46 +01:00
|
|
|
total_bytes_allocated_in_chunks += CHUNK_ALLOC_SIZE(in_chunk->memlen);
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
newch->DBG_alloc = CHUNK_ALLOC_SIZE(in_chunk->memlen);
|
|
|
|
#endif
|
2011-07-18 21:36:20 +02:00
|
|
|
newch->next = NULL;
|
|
|
|
if (in_chunk->data) {
|
|
|
|
off_t offset = in_chunk->data - in_chunk->mem;
|
|
|
|
newch->data = newch->mem + offset;
|
|
|
|
}
|
|
|
|
return newch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a new copy of <b>buf</b> */
|
|
|
|
buf_t *
|
|
|
|
buf_copy(const buf_t *buf)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
|
|
|
buf_t *out = buf_new();
|
|
|
|
out->default_chunk_size = buf->default_chunk_size;
|
|
|
|
for (ch = buf->head; ch; ch = ch->next) {
|
|
|
|
chunk_t *newch = chunk_copy(ch);
|
|
|
|
if (out->tail) {
|
|
|
|
out->tail->next = newch;
|
|
|
|
out->tail = newch;
|
|
|
|
} else {
|
|
|
|
out->head = out->tail = newch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out->datalen = buf->datalen;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-01-06 01:54:22 +01:00
|
|
|
/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
|
|
|
|
* the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
|
|
|
|
* than MAX_CHUNK_ALLOC. */
|
2017-08-08 21:06:40 +02:00
|
|
|
chunk_t *
|
2007-12-29 06:16:30 +01:00
|
|
|
buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
2007-12-26 01:12:08 +01:00
|
|
|
{
|
|
|
|
chunk_t *chunk;
|
2016-07-08 21:24:21 +02:00
|
|
|
|
2007-12-29 06:16:30 +01:00
|
|
|
if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk = chunk_new_with_alloc_size(buf->default_chunk_size);
|
2007-12-29 06:16:30 +01:00
|
|
|
} else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) {
|
|
|
|
chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC);
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
2017-09-05 20:15:38 +02:00
|
|
|
chunk = chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity));
|
2007-05-10 00:39:49 +02:00
|
|
|
}
|
2013-11-16 00:38:52 +01:00
|
|
|
|
2017-11-21 18:28:16 +01:00
|
|
|
chunk->inserted_time = monotime_coarse_get_stamp();
|
2013-11-16 00:38:52 +01:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (buf->tail) {
|
|
|
|
tor_assert(buf->head);
|
|
|
|
buf->tail->next = chunk;
|
|
|
|
buf->tail = chunk;
|
|
|
|
} else {
|
|
|
|
tor_assert(!buf->head);
|
|
|
|
buf->head = buf->tail = chunk;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
return chunk;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2013-11-16 00:38:52 +01:00
|
|
|
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
|
2017-11-21 18:28:16 +01:00
|
|
|
* timestamp units. Requires the current monotonic timestamp as its
|
|
|
|
* input <b>now</b>.
|
2013-11-16 00:38:52 +01:00
|
|
|
*/
|
|
|
|
uint32_t
|
|
|
|
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
|
|
|
|
{
|
|
|
|
if (buf->head) {
|
|
|
|
return now - buf->head->inserted_time;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
buf_get_total_allocation(void)
|
|
|
|
{
|
|
|
|
return total_bytes_allocated_in_chunks;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Append <b>string_len</b> bytes from <b>string</b> to the end of
|
|
|
|
* <b>buf</b>.
|
|
|
|
*
|
2004-05-02 00:08:43 +02:00
|
|
|
* Return the new length of the buffer on success, -1 on failure.
|
|
|
|
*/
|
2005-04-26 22:53:22 +02:00
|
|
|
int
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_add(buf_t *buf, const char *string, size_t string_len)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!string_len)
|
2008-02-22 04:44:36 +01:00
|
|
|
return (int)buf->datalen;
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2017-02-13 21:51:55 +01:00
|
|
|
if (BUG(buf->datalen >= INT_MAX))
|
|
|
|
return -1;
|
|
|
|
if (BUG(buf->datalen >= INT_MAX - string_len))
|
|
|
|
return -1;
|
|
|
|
|
2007-12-29 06:16:30 +01:00
|
|
|
while (string_len) {
|
|
|
|
size_t copy;
|
|
|
|
if (!buf->tail || !CHUNK_REMAINING_CAPACITY(buf->tail))
|
|
|
|
buf_add_chunk_with_capacity(buf, string_len, 1);
|
|
|
|
|
|
|
|
copy = CHUNK_REMAINING_CAPACITY(buf->tail);
|
2007-12-26 01:12:08 +01:00
|
|
|
if (copy > string_len)
|
|
|
|
copy = string_len;
|
|
|
|
memcpy(CHUNK_WRITE_PTR(buf->tail), string, copy);
|
|
|
|
string_len -= copy;
|
|
|
|
string += copy;
|
|
|
|
buf->datalen += copy;
|
|
|
|
buf->tail->datalen += copy;
|
2003-12-14 09:15:41 +01:00
|
|
|
}
|
2003-10-14 03:34:31 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(buf->datalen < INT_MAX);
|
|
|
|
return (int)buf->datalen;
|
2003-03-17 03:42:45 +01:00
|
|
|
}
|
|
|
|
|
2017-09-06 15:07:50 +02:00
|
|
|
/** Add a nul-terminated <b>string</b> to <b>buf</b>, not including the
|
|
|
|
* terminating NUL. */
|
|
|
|
void
|
|
|
|
buf_add_string(buf_t *buf, const char *string)
|
|
|
|
{
|
|
|
|
buf_add(buf, string, strlen(string));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** As tor_snprintf, but write the results into a buf_t */
|
|
|
|
void
|
|
|
|
buf_add_printf(buf_t *buf, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap,format);
|
|
|
|
buf_add_vprintf(buf, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** As tor_vsnprintf, but write the results into a buf_t. */
|
|
|
|
void
|
|
|
|
buf_add_vprintf(buf_t *buf, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
/* XXXX Faster implementations are easy enough, but let's optimize later */
|
|
|
|
char *tmp;
|
|
|
|
tor_vasprintf(&tmp, format, args);
|
|
|
|
buf_add(buf, tmp, strlen(tmp));
|
|
|
|
tor_free(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a heap-allocated string containing the contents of <b>buf</b>, plus
|
|
|
|
* a NUL byte. If <b>sz_out</b> is provided, set *<b>sz_out</b> to the length
|
|
|
|
* of the returned string, not including the terminating NUL. */
|
|
|
|
char *
|
|
|
|
buf_extract(buf_t *buf, size_t *sz_out)
|
|
|
|
{
|
|
|
|
tor_assert(buf);
|
|
|
|
|
|
|
|
size_t sz = buf_datalen(buf);
|
|
|
|
char *result;
|
|
|
|
result = tor_malloc(sz+1);
|
|
|
|
buf_peek(buf, result, sz);
|
|
|
|
result[sz] = 0;
|
|
|
|
if (sz_out)
|
|
|
|
*sz_out = sz;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Helper: copy the first <b>string_len</b> bytes from <b>buf</b>
|
|
|
|
* onto <b>string</b>.
|
2005-06-11 20:52:12 +02:00
|
|
|
*/
|
2017-08-08 17:51:36 +02:00
|
|
|
void
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_peek(const buf_t *buf, char *string, size_t string_len)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(string);
|
2005-12-14 21:40:40 +01:00
|
|
|
/* make sure we don't ask for too much */
|
|
|
|
tor_assert(string_len <= buf->datalen);
|
2017-08-08 21:16:39 +02:00
|
|
|
/* buf_assert_ok(buf); */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk = buf->head;
|
|
|
|
while (string_len) {
|
|
|
|
size_t copy = string_len;
|
|
|
|
tor_assert(chunk);
|
|
|
|
if (chunk->datalen < copy)
|
|
|
|
copy = chunk->datalen;
|
|
|
|
memcpy(string, chunk->data, copy);
|
|
|
|
string_len -= copy;
|
|
|
|
string += copy;
|
|
|
|
chunk = chunk->next;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-14 21:40:40 +01:00
|
|
|
/** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store
|
|
|
|
* them into <b>string</b>. Return the new buffer size. <b>string_len</b>
|
|
|
|
* must be \<= the number of bytes on the buffer.
|
2005-04-26 22:53:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_get_bytes(buf_t *buf, char *string, size_t string_len)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
|
|
|
/* There must be string_len bytes in buf; write them onto string,
|
|
|
|
* then memmove buf back (that is, remove them from buf).
|
|
|
|
*
|
|
|
|
* Return the number of bytes still on the buffer. */
|
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_peek(buf, string, string_len);
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_drain(buf, string_len);
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(buf->datalen < INT_MAX);
|
|
|
|
return (int)buf->datalen;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2007-04-25 09:20:04 +02:00
|
|
|
/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
|
|
|
|
* <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
|
2007-04-21 19:26:12 +02:00
|
|
|
* Return the number of bytes actually copied.
|
|
|
|
*/
|
|
|
|
int
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
|
2007-04-21 19:26:12 +02:00
|
|
|
{
|
2010-10-15 17:38:33 +02:00
|
|
|
/* We can do way better here, but this doesn't turn up in any profiles. */
|
2007-04-21 19:26:12 +02:00
|
|
|
char b[4096];
|
|
|
|
size_t cp, len;
|
2017-02-13 21:51:55 +01:00
|
|
|
|
|
|
|
if (BUG(buf_out->datalen >= INT_MAX))
|
|
|
|
return -1;
|
|
|
|
if (BUG(buf_out->datalen >= INT_MAX - *buf_flushlen))
|
|
|
|
return -1;
|
|
|
|
|
2007-04-21 19:26:12 +02:00
|
|
|
len = *buf_flushlen;
|
|
|
|
if (len > buf_in->datalen)
|
|
|
|
len = buf_in->datalen;
|
|
|
|
|
|
|
|
cp = len; /* Remember the number of bytes we intend to copy. */
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(cp < INT_MAX);
|
2007-04-21 19:26:12 +02:00
|
|
|
while (len) {
|
|
|
|
/* This isn't the most efficient implementation one could imagine, since
|
|
|
|
* it does two copies instead of 1, but I kinda doubt that this will be
|
|
|
|
* critical path. */
|
|
|
|
size_t n = len > sizeof(b) ? sizeof(b) : len;
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_get_bytes(buf_in, b, n);
|
|
|
|
buf_add(buf_out, b, n);
|
2007-04-21 19:26:12 +02:00
|
|
|
len -= n;
|
|
|
|
}
|
|
|
|
*buf_flushlen -= cp;
|
2008-02-22 04:44:36 +01:00
|
|
|
return (int)cp;
|
2007-04-21 19:26:12 +02:00
|
|
|
}
|
|
|
|
|
2017-09-06 15:30:50 +02:00
|
|
|
/** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
buf_move_all(buf_t *buf_out, buf_t *buf_in)
|
|
|
|
{
|
|
|
|
tor_assert(buf_out);
|
|
|
|
if (!buf_in)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf_out->head == NULL) {
|
|
|
|
buf_out->head = buf_in->head;
|
|
|
|
buf_out->tail = buf_in->tail;
|
|
|
|
} else {
|
|
|
|
buf_out->tail->next = buf_in->head;
|
|
|
|
buf_out->tail = buf_in->tail;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_out->datalen += buf_in->datalen;
|
|
|
|
buf_in->head = buf_in->tail = NULL;
|
|
|
|
buf_in->datalen = 0;
|
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Internal structure: represents a position in a buffer. */
|
2007-12-29 18:36:03 +01:00
|
|
|
typedef struct buf_pos_t {
|
2007-12-30 01:13:07 +01:00
|
|
|
const chunk_t *chunk; /**< Which chunk are we pointing to? */
|
2008-02-21 22:15:31 +01:00
|
|
|
int pos;/**< Which character inside the chunk's data are we pointing to? */
|
2008-02-20 18:48:39 +01:00
|
|
|
size_t chunk_pos; /**< Total length of all previous chunks. */
|
2007-12-30 01:13:07 +01:00
|
|
|
} buf_pos_t;
|
2007-12-29 18:36:03 +01:00
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Initialize <b>out</b> to point to the first character of <b>buf</b>.*/
|
2007-12-29 18:36:03 +01:00
|
|
|
static void
|
2007-12-30 01:13:07 +01:00
|
|
|
buf_pos_init(const buf_t *buf, buf_pos_t *out)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
out->chunk = buf->head;
|
|
|
|
out->pos = 0;
|
2008-02-20 18:48:39 +01:00
|
|
|
out->chunk_pos = 0;
|
2007-12-29 18:36:03 +01:00
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Advance <b>out</b> to the first appearance of <b>ch</b> at the current
|
|
|
|
* position of <b>out</b>, or later. Return -1 if no instances are found;
|
|
|
|
* otherwise returns the absolute position of the character. */
|
2008-02-22 04:44:36 +01:00
|
|
|
static off_t
|
2007-12-30 01:13:07 +01:00
|
|
|
buf_find_pos_of_char(char ch, buf_pos_t *out)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
2007-12-30 01:13:07 +01:00
|
|
|
const chunk_t *chunk;
|
2008-02-20 17:57:39 +01:00
|
|
|
int pos;
|
2008-02-20 18:48:39 +01:00
|
|
|
tor_assert(out);
|
2008-02-21 00:38:57 +01:00
|
|
|
if (out->chunk) {
|
2008-02-21 00:58:48 +01:00
|
|
|
if (out->chunk->datalen) {
|
|
|
|
tor_assert(out->pos < (off_t)out->chunk->datalen);
|
|
|
|
} else {
|
|
|
|
tor_assert(out->pos == 0);
|
2008-02-21 00:38:57 +01:00
|
|
|
}
|
|
|
|
}
|
2008-02-20 17:57:39 +01:00
|
|
|
pos = out->pos;
|
2007-12-29 18:36:03 +01:00
|
|
|
for (chunk = out->chunk; chunk; chunk = chunk->next) {
|
2008-02-21 22:15:31 +01:00
|
|
|
char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos);
|
2007-12-29 18:36:03 +01:00
|
|
|
if (cp) {
|
|
|
|
out->chunk = chunk;
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(cp - chunk->data < INT_MAX);
|
|
|
|
out->pos = (int)(cp - chunk->data);
|
2008-02-20 18:48:39 +01:00
|
|
|
return out->chunk_pos + out->pos;
|
2007-12-29 18:36:03 +01:00
|
|
|
} else {
|
2008-02-20 18:48:39 +01:00
|
|
|
out->chunk_pos += chunk->datalen;
|
2007-12-29 18:36:03 +01:00
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Advance <b>pos</b> by a single character, if there are any more characters
|
2009-05-27 23:55:51 +02:00
|
|
|
* in the buffer. Returns 0 on success, -1 on failure. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2007-12-29 18:36:03 +01:00
|
|
|
buf_pos_inc(buf_pos_t *pos)
|
|
|
|
{
|
2008-02-20 18:48:39 +01:00
|
|
|
++pos->pos;
|
2008-02-20 22:57:48 +01:00
|
|
|
if (pos->pos == (off_t)pos->chunk->datalen) {
|
2007-12-29 18:36:03 +01:00
|
|
|
if (!pos->chunk->next)
|
|
|
|
return -1;
|
2008-02-20 18:48:39 +01:00
|
|
|
pos->chunk_pos += pos->chunk->datalen;
|
2007-12-29 18:36:03 +01:00
|
|
|
pos->chunk = pos->chunk->next;
|
|
|
|
pos->pos = 0;
|
|
|
|
}
|
2007-12-30 01:13:07 +01:00
|
|
|
return 0;
|
2007-12-29 18:36:03 +01:00
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Return true iff the <b>n</b>-character string in <b>s</b> appears
|
|
|
|
* (verbatim) at <b>pos</b>. */
|
2007-12-29 18:36:03 +01:00
|
|
|
static int
|
2008-02-19 23:52:50 +01:00
|
|
|
buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
buf_pos_t p;
|
2008-02-21 03:10:38 +01:00
|
|
|
if (!n)
|
|
|
|
return 1;
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
memcpy(&p, pos, sizeof(p));
|
2007-12-29 18:36:03 +01:00
|
|
|
|
2008-02-21 03:10:38 +01:00
|
|
|
while (1) {
|
2007-12-30 01:13:07 +01:00
|
|
|
char ch = p.chunk->data[p.pos];
|
2007-12-29 18:36:03 +01:00
|
|
|
if (ch != *s)
|
|
|
|
return 0;
|
|
|
|
++s;
|
2008-02-21 03:10:38 +01:00
|
|
|
/* If we're out of characters that don't match, we match. Check this
|
|
|
|
* _before_ we test incrementing pos, in case we're at the end of the
|
|
|
|
* string. */
|
|
|
|
if (--n == 0)
|
|
|
|
return 1;
|
2007-12-30 01:13:07 +01:00
|
|
|
if (buf_pos_inc(&p)<0)
|
2007-12-29 18:36:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Return the first position in <b>buf</b> at which the <b>n</b>-character
|
|
|
|
* string <b>s</b> occurs, or -1 if it does not occur. */
|
2017-08-08 17:51:36 +02:00
|
|
|
int
|
2008-02-19 23:52:50 +01:00
|
|
|
buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
buf_pos_t pos;
|
|
|
|
buf_pos_init(buf, &pos);
|
2007-12-30 01:13:07 +01:00
|
|
|
while (buf_find_pos_of_char(*s, &pos) >= 0) {
|
|
|
|
if (buf_matches_at_pos(&pos, s, n)) {
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(pos.chunk_pos + pos.pos < INT_MAX);
|
|
|
|
return (int)(pos.chunk_pos + pos.pos);
|
2007-12-29 18:36:03 +01:00
|
|
|
} else {
|
2007-12-30 01:13:07 +01:00
|
|
|
if (buf_pos_inc(&pos)<0)
|
2007-12-29 18:36:03 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-02-21 04:22:03 +01:00
|
|
|
/** Return 1 iff <b>buf</b> starts with <b>cmd</b>. <b>cmd</b> must be a null
|
2017-06-21 17:10:58 +02:00
|
|
|
* terminated string, of no more than PEEK_BUF_STARTSWITH_MAX bytes. */
|
2012-02-21 04:22:03 +01:00
|
|
|
int
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_peek_startswith(const buf_t *buf, const char *cmd)
|
2012-02-21 04:22:03 +01:00
|
|
|
{
|
2017-06-21 17:10:58 +02:00
|
|
|
char tmp[PEEK_BUF_STARTSWITH_MAX];
|
2017-06-21 16:35:35 +02:00
|
|
|
size_t clen = strlen(cmd);
|
2017-09-13 03:09:18 +02:00
|
|
|
if (clen == 0)
|
|
|
|
return 1;
|
2017-06-21 17:10:58 +02:00
|
|
|
if (BUG(clen > sizeof(tmp)))
|
|
|
|
return 0;
|
|
|
|
if (buf->datalen < clen)
|
|
|
|
return 0;
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_peek(buf, tmp, clen);
|
2017-06-21 17:10:58 +02:00
|
|
|
return fast_memeq(tmp, cmd, clen);
|
2012-02-21 04:22:03 +01:00
|
|
|
}
|
|
|
|
|
2008-02-06 17:58:05 +01:00
|
|
|
/** Return the index within <b>buf</b> at which <b>ch</b> first appears,
|
|
|
|
* or -1 if <b>ch</b> does not appear on buf. */
|
2008-02-22 04:44:36 +01:00
|
|
|
static off_t
|
2007-12-29 03:33:42 +01:00
|
|
|
buf_find_offset_of_char(buf_t *buf, char ch)
|
|
|
|
{
|
|
|
|
chunk_t *chunk;
|
2008-02-22 04:44:36 +01:00
|
|
|
off_t offset = 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
for (chunk = buf->head; chunk; chunk = chunk->next) {
|
|
|
|
char *cp = memchr(chunk->data, ch, chunk->datalen);
|
|
|
|
if (cp)
|
|
|
|
return offset + (cp - chunk->data);
|
|
|
|
else
|
|
|
|
offset += chunk->datalen;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-07-31 19:44:43 +02:00
|
|
|
/** Try to read a single LF-terminated line from <b>buf</b>, and write it
|
|
|
|
* (including the LF), NUL-terminated, into the *<b>data_len</b> byte buffer
|
|
|
|
* at <b>data_out</b>. Set *<b>data_len</b> to the number of bytes in the
|
|
|
|
* line, not counting the terminating NUL. Return 1 if we read a whole line,
|
|
|
|
* return 0 if we don't have a whole line yet, and return -1 if the line
|
|
|
|
* length exceeds *<b>data_len</b>.
|
2006-11-14 01:06:31 +01:00
|
|
|
*/
|
|
|
|
int
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_get_line(buf_t *buf, char *data_out, size_t *data_len)
|
2006-11-14 01:06:31 +01:00
|
|
|
{
|
|
|
|
size_t sz;
|
2008-02-22 04:44:36 +01:00
|
|
|
off_t offset;
|
2006-11-14 01:06:31 +01:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!buf->head)
|
|
|
|
return 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
|
|
|
|
offset = buf_find_offset_of_char(buf, '\n');
|
|
|
|
if (offset < 0)
|
2006-11-14 01:06:31 +01:00
|
|
|
return 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
sz = (size_t) offset;
|
2006-11-14 01:06:31 +01:00
|
|
|
if (sz+2 > *data_len) {
|
2007-12-29 03:33:42 +01:00
|
|
|
*data_len = sz + 2;
|
2006-11-14 01:06:31 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2017-08-08 21:54:15 +02:00
|
|
|
buf_get_bytes(buf, data_out, sz+1);
|
2006-11-14 01:06:31 +01:00
|
|
|
data_out[sz+1] = '\0';
|
|
|
|
*data_len = sz+1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-07-18 21:36:20 +02:00
|
|
|
/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
|
|
|
|
int
|
2016-08-02 19:40:19 +02:00
|
|
|
buf_set_to_copy(buf_t **output,
|
|
|
|
const buf_t *input)
|
2011-07-18 21:36:20 +02:00
|
|
|
{
|
|
|
|
if (*output)
|
|
|
|
buf_free(*output);
|
|
|
|
*output = buf_copy(input);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Log an error and exit if <b>buf</b> is corrupted.
|
2004-05-02 00:08:43 +02:00
|
|
|
*/
|
2005-09-30 03:09:52 +02:00
|
|
|
void
|
2017-08-08 21:16:39 +02:00
|
|
|
buf_assert_ok(buf_t *buf)
|
2004-03-03 23:49:15 +01:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(buf);
|
|
|
|
tor_assert(buf->magic == BUFFER_MAGIC);
|
2007-04-23 16:42:27 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (! buf->head) {
|
|
|
|
tor_assert(!buf->tail);
|
|
|
|
tor_assert(buf->datalen == 0);
|
2007-04-23 16:42:27 +02:00
|
|
|
} else {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *ch;
|
|
|
|
size_t total = 0;
|
|
|
|
tor_assert(buf->tail);
|
|
|
|
for (ch = buf->head; ch; ch = ch->next) {
|
|
|
|
total += ch->datalen;
|
|
|
|
tor_assert(ch->datalen <= ch->memlen);
|
|
|
|
tor_assert(ch->data >= &ch->mem[0]);
|
2015-03-03 22:25:26 +01:00
|
|
|
tor_assert(ch->data <= &ch->mem[0]+ch->memlen);
|
|
|
|
if (ch->data == &ch->mem[0]+ch->memlen) {
|
2017-09-28 14:35:24 +02:00
|
|
|
/* LCOV_EXCL_START */
|
2015-03-03 22:25:26 +01:00
|
|
|
static int warned = 0;
|
|
|
|
if (! warned) {
|
|
|
|
log_warn(LD_BUG, "Invariant violation in buf.c related to #15083");
|
|
|
|
warned = 1;
|
|
|
|
}
|
2017-09-28 14:35:24 +02:00
|
|
|
/* LCOV_EXCL_STOP */
|
2015-03-03 22:25:26 +01:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen);
|
|
|
|
if (!ch->next)
|
|
|
|
tor_assert(ch == buf->tail);
|
|
|
|
}
|
|
|
|
tor_assert(buf->datalen == total);
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|