aboutsummaryrefslogtreecommitdiff
path: root/src/common/buffers.h
blob: 22a5f7bfa3b64829b3c6c81d7bc2000d32a14f85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file buffers.h
 * \brief Header file for buffers.c.
 **/

#ifndef TOR_BUFFERS_H
#define TOR_BUFFERS_H

#include "compat.h"
#include "compat.h"
#include "torint.h"
#include "testsupport.h"

typedef struct buf_t buf_t;

struct tor_compress_state_t;

buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
size_t buf_get_default_chunk_size(const buf_t *buf);
void buf_free_(buf_t *buf);
#define buf_free(b) FREE_AND_NULL(buf_t, buf_free_, (b))
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);

MOCK_DECL(size_t, buf_datalen, (const buf_t *buf));
size_t buf_allocation(const buf_t *buf);
size_t buf_slack(const buf_t *buf);

uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now);
size_t buf_get_total_allocation(void);

int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
                         int *reached_eof,
                         int *socket_error);

int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
                        size_t *buf_flushlen);

int buf_add(buf_t *buf, const char *string, size_t string_len);
void buf_add_string(buf_t *buf, const char *string);
void buf_add_printf(buf_t *buf, const char *format, ...)
  CHECK_PRINTF(2, 3);
void buf_add_vprintf(buf_t *buf, const char *format, va_list args)
  CHECK_PRINTF(2, 0);
int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state,
                          const char *data, size_t data_len, int done);
int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
void buf_move_all(buf_t *buf_out, buf_t *buf_in);
void buf_peek(const buf_t *buf, char *string, size_t string_len);
void buf_drain(buf_t *buf, size_t n);
int buf_get_bytes(buf_t *buf, char *string, size_t string_len);
int buf_get_line(buf_t *buf, char *data_out, size_t *data_len);

#define PEEK_BUF_STARTSWITH_MAX 16
int buf_peek_startswith(const buf_t *buf, const char *cmd);

int buf_set_to_copy(buf_t **output,
                    const buf_t *input);

void buf_assert_ok(buf_t *buf);

int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
void buf_pullup(buf_t *buf, size_t bytes,
                const char **head_out, size_t *len_out);
char *buf_extract(buf_t *buf, size_t *sz_out);

#ifdef BUFFERS_PRIVATE
#ifdef TOR_UNIT_TESTS
buf_t *buf_new_with_data(const char *cp, size_t sz);
#endif
size_t buf_preferred_chunk_size(size_t target);

#define DEBUG_CHUNK_ALLOC
/** A single chunk on a buffer. */
typedef struct chunk_t {
  struct chunk_t *next; /**< The next chunk on the buffer. */
  size_t datalen; /**< The number of bytes stored in this chunk */
  size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */
#ifdef DEBUG_CHUNK_ALLOC
  size_t DBG_alloc;
#endif
  char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
  uint32_t inserted_time; /**< Timestamp when this chunk was inserted. */
  char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in
                * this chunk. */
} chunk_t;

/** Magic value for buf_t.magic, to catch pointer errors. */
#define BUFFER_MAGIC 0xB0FFF312u
/** A resizeable buffer, optimized for reading and writing. */
struct buf_t {
  uint32_t magic; /**< Magic cookie for debugging: Must be set to
                   *   BUFFER_MAGIC. */
  size_t datalen; /**< How many bytes is this buffer holding right now? */
  size_t default_chunk_size; /**< Don't allocate any chunks smaller than
                              * this for this buffer. */
  chunk_t *head; /**< First chunk in the list, or NULL for none. */
  chunk_t *tail; /**< Last chunk in the list, or NULL for none. */
};

chunk_t *buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped);
/** If a read onto the end of a chunk would be smaller than this number, then
 * just start a new chunk. */
#define MIN_READ_LEN 8

/** Return the number of bytes that can be written onto <b>chunk</b> without
 * running out of space. */
static inline size_t
CHUNK_REMAINING_CAPACITY(const chunk_t *chunk)
{
  return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen);
}

/** Return the next character in <b>chunk</b> onto which data can be appended.
 * If the chunk is full, this might be off the end of chunk->mem. */
static inline char *
CHUNK_WRITE_PTR(chunk_t *chunk)
{
  return chunk->data + chunk->datalen;
}

#endif /* defined(BUFFERS_PRIVATE) */

#endif /* !defined(TOR_BUFFERS_H) */