Back to index

tor  0.2.3.18-rc
Classes | Defines | Typedefs | Functions
buffers.c File Reference

Implements a generic interface buffer. More...

#include "or.h"
#include "buffers.h"
#include "config.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "reasons.h"
#include "../common/util.h"
#include "../common/torlog.h"

Go to the source code of this file.

Classes

struct  chunk_t
 A single chunk on a buffer or in a freelist. More...
struct  buf_t
 A resizeable buffer, optimized for reading and writing. More...
struct  buf_pos_t
 Internal structure: represents a position in a buffer. More...

Defines

#define BUFFERS_PRIVATE
#define check()   STMT_NIL
#define CHUNK_HEADER_LEN   STRUCT_OFFSET(chunk_t, mem[0])
#define CHUNK_ALLOC_SIZE(memlen)   (CHUNK_HEADER_LEN + (memlen))
 Return the number of bytes needed to allocate a chunk to hold memlen bytes.
#define CHUNK_SIZE_WITH_ALLOC(memlen)   ((memlen) - CHUNK_HEADER_LEN)
 Return the number of usable bytes in a chunk allocated with malloc(memlen).
#define MIN_READ_LEN   8
 If a read onto the end of a chunk would be smaller than this number, then just start a new chunk.
#define MIN_CHUNK_ALLOC   256
 Every chunk should take up at least this many bytes.
#define MAX_CHUNK_ALLOC   65536
 No chunk should take up more than this many bytes.
#define BUFFER_MAGIC   0xB0FFF312u
 Magic value for buf_t.magic, to catch pointer errors.
#define CONTENT_LENGTH   "\r\nContent-Length: "
#define SOCKS_WARN_INTERVAL   5
 Wait this many seconds before warning the user about using SOCKS unsafely again (requires that WarnUnsafeSocks is turned on).
#define MAX_SOCKS_MESSAGE_LEN   512
 Do not attempt to parse socks messages longer than this.

Typedefs

typedef struct chunk_t chunk_t
 A single chunk on a buffer or in a freelist.
typedef struct buf_pos_t buf_pos_t
 Internal structure: represents a position in a buffer.

Functions

static int parse_socks (const char *data, size_t datalen, socks_request_t *req, int log_sockstype, int safe_socks, ssize_t *drain_out, size_t *want_length_out)
 Implementation helper to implement fetch_from_*_socks.
static int parse_socks_client (const uint8_t *data, size_t datalen, int state, char **reason, ssize_t *drain_out)
 Implementation logic for fetch_from_*_socks_client.
static INLINE char * CHUNK_WRITE_PTR (chunk_t *chunk)
 Return the next character in chunk onto which data can be appended.
static INLINE size_t CHUNK_REMAINING_CAPACITY (const chunk_t *chunk)
 Return the number of bytes that can be written onto chunk without running out of space.
static INLINE void chunk_repack (chunk_t *chunk)
 Move all bytes stored in chunk to the front of chunk->mem, to free up space at the end.
static void chunk_free_unchecked (chunk_t *chunk)
static INLINE chunk_tchunk_new_with_alloc_size (size_t alloc)
static INLINE chunk_tchunk_grow (chunk_t *chunk, size_t sz)
 Expand chunk until it can hold sz bytes, and return a new pointer to chunk.
static INLINE size_t preferred_chunk_size (size_t target)
 Return the allocation size we'd like to use to hold target bytes.
void buf_shrink_freelists (int free_all)
 Remove from the freelists most chunks that have not been used since the last call to buf_shrink_freelists().
void buf_dump_freelist_sizes (int severity)
 Describe the current status of the freelists at log level severity.
static void buf_pullup (buf_t *buf, size_t bytes, int nulterminate)
 Collapse data from the first N chunks from buf into buf->head, growing it as necessary, until buf->head has the first bytes bytes of data from the buffer, or until buf->head has all the data in buf.
void buf_shrink (buf_t *buf)
 Resize buf so it won't hold extra memory that we haven't been using lately.
static INLINE void buf_remove_from_front (buf_t *buf, size_t n)
 Remove the first n bytes from buf.
buf_tbuf_new_with_capacity (size_t size)
 Create and return a new buf with default chunk capacity size.
buf_tbuf_new (void)
 Allocate and return a new buffer with default capacity.
void buf_clear (buf_t *buf)
 Remove all data from buf.
size_t buf_datalen (const buf_t *buf)
 Return the number of bytes stored in buf
size_t buf_allocation (const buf_t *buf)
 Return the total length of all chunks used in buf.
size_t buf_slack (const buf_t *buf)
 Return the number of bytes that can be added to buf without performing any additional allocation.
void buf_free (buf_t *buf)
 Release storage held by buf.
static chunk_tchunk_copy (const chunk_t *in_chunk)
 Return a new copy of in_chunk
buf_tbuf_copy (const buf_t *buf)
 Return a new copy of buf
static chunk_tbuf_add_chunk_with_capacity (buf_t *buf, size_t capacity, int capped)
 Append a new chunk with enough capacity to hold capacity bytes to the tail of buf.
static INLINE int read_to_chunk (buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, int *reached_eof, int *socket_error)
 Read up to at_most bytes from the socket fd into chunk (which must be on buf).
static INLINE int read_to_chunk_tls (buf_t *buf, chunk_t *chunk, tor_tls_t *tls, size_t at_most)
 As read_to_chunk(), but return (negative) error code on error, blocking, or TLS, and the number of bytes read otherwise.
int read_to_buf (tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, int *socket_error)
 Read from socket s, writing onto end of buf.
int read_to_buf_tls (tor_tls_t *tls, size_t at_most, buf_t *buf)
 As read_to_buf, but reads from a TLS connection, and returns a TLS status value rather than the number of bytes read.
static INLINE int flush_chunk (tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen)
 Helper for flush_buf(): try to write sz bytes from chunk chunk of buffer buf onto socket s.
static INLINE int flush_chunk_tls (tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz, size_t *buf_flushlen)
 Helper for flush_buf_tls(): try to write sz bytes from chunk chunk of buffer buf onto socket s.
int flush_buf (tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen)
 Write data from buf to the socket s.
int flush_buf_tls (tor_tls_t *tls, buf_t *buf, size_t flushlen, size_t *buf_flushlen)
 As flush_buf(), but writes data to a TLS connection.
int write_to_buf (const char *string, size_t string_len, buf_t *buf)
 Append string_len bytes from string to the end of buf.
static INLINE void peek_from_buf (char *string, size_t string_len, const buf_t *buf)
 Helper: copy the first string_len bytes from buf onto string.
int fetch_from_buf (char *string, size_t string_len, buf_t *buf)
 Remove string_len bytes from the front of buf, and store them into string.
static INLINE int cell_command_is_var_length (uint8_t command, int linkproto)
 True iff the cell command command is one that implies a variable-length cell in Tor link protocol linkproto.
int fetch_var_cell_from_buf (buf_t *buf, var_cell_t **out, int linkproto)
 Check buf for a variable-length cell according to the rules of link protocol version linkproto.
int move_buf_to_buf (buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
 Move up to *buf_flushlen bytes from buf_in to buf_out, and modify *buf_flushlen appropriately.
static void buf_pos_init (const buf_t *buf, buf_pos_t *out)
 Initialize out to point to the first character of buf.
static off_t buf_find_pos_of_char (char ch, buf_pos_t *out)
 Advance out to the first appearance of ch at the current position of out, or later.
static INLINE int buf_pos_inc (buf_pos_t *pos)
 Advance pos by a single character, if there are any more characters in the buffer.
static int buf_matches_at_pos (const buf_pos_t *pos, const char *s, size_t n)
 Return true iff the n-character string in s appears (verbatim) at pos.
int buf_find_string_offset (const buf_t *buf, const char *s, size_t n)
 Return the first position in buf at which the n-character string s occurs, or -1 if it does not occur.
int fetch_from_buf_http (buf_t *buf, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete)
 There is a (possibly incomplete) http statement on buf, of the form "\%s\\r\\n\\r\\n\%s", headers, body.
static void log_unsafe_socks_warning (int socks_protocol, const char *address, uint16_t port, int safe_socks)
 Warn that the user application has made an unsafe socks request using protocol socks_protocol on port port.
socks_request_tsocks_request_new (void)
 Return a new socks_request_t.
void socks_request_free (socks_request_t *req)
 Free all storage held in the socks_request_t req.
int fetch_from_buf_socks (buf_t *buf, socks_request_t *req, int log_sockstype, int safe_socks)
 There is a (possibly incomplete) socks handshake on buf, of one of the forms.
int fetch_from_buf_socks_client (buf_t *buf, int state, char **reason)
 Inspect a reply from SOCKS server stored in buf according to state, removing the protocol data upon success.
int peek_buf_has_control0_command (buf_t *buf)
 Return 1 iff buf looks more like it has an (obsolete) v0 controller command on it than any valid v1 controller command.
static off_t buf_find_offset_of_char (buf_t *buf, char ch)
 Return the index within buf at which ch first appears, or -1 if ch does not appear on buf.
int fetch_from_buf_line (buf_t *buf, char *data_out, size_t *data_len)
 Try to read a single LF-terminated line from buf, and write it (including the LF), NUL-terminated, into the *data_len byte buffer at data_out.
int write_to_buf_zlib (buf_t *buf, tor_zlib_state_t *state, const char *data, size_t data_len, int done)
 Compress on uncompress the data_len bytes in data using the zlib state state, appending the result to buf.
int generic_buffer_set_to_copy (generic_buffer_t **output, const generic_buffer_t *input)
 Set *output to contain a copy of the data in *input
void assert_buf_ok (buf_t *buf)
 Log an error and exit if buf is corrupted.

Detailed Description

Implements a generic interface buffer.

Buffers are fairly opaque string holders that can read to or flush from: memory, file descriptors, or TLS connections.

Definition in file buffers.c.


Class Documentation

struct chunk_t

A single chunk on a buffer or in a freelist.

Definition at line 66 of file buffers.c.

Collaboration diagram for chunk_t:
Class Members
char * data A pointer to the first byte of data stored in mem.
size_t datalen The number of bytes stored in this chunk.
char mem The actual memory used for storage in this chunk.
size_t memlen The number of usable bytes of storage in mem.
struct chunk_t * next The next chunk on the buffer or freelist.
struct buf_t

A resizeable buffer, optimized for reading and writing.

Definition at line 362 of file buffers.c.

Collaboration diagram for buf_t:
Class Members
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.
uint32_t magic Magic cookie for debugging: Must be set to BUFFER_MAGIC.
chunk_t * tail Last chunk in the list, or NULL for none.
struct buf_pos_t

Internal structure: represents a position in a buffer.

Definition at line 1194 of file buffers.c.

Collaboration diagram for buf_pos_t:
Class Members
const chunk_t * chunk Which chunk are we pointing to?
size_t chunk_pos Total length of all previous chunks.
int pos Which character inside the chunk's data are we pointing to?

Define Documentation

#define BUFFER_MAGIC   0xB0FFF312u

Magic value for buf_t.magic, to catch pointer errors.

Definition at line 360 of file buffers.c.

#define BUFFERS_PRIVATE

Definition at line 13 of file buffers.c.

#define check ( )    STMT_NIL

Definition at line 34 of file buffers.c.

#define CHUNK_ALLOC_SIZE (   memlen)    (CHUNK_HEADER_LEN + (memlen))

Return the number of bytes needed to allocate a chunk to hold memlen bytes.

Definition at line 79 of file buffers.c.

#define CHUNK_HEADER_LEN   STRUCT_OFFSET(chunk_t, mem[0])

Definition at line 75 of file buffers.c.

#define CHUNK_SIZE_WITH_ALLOC (   memlen)    ((memlen) - CHUNK_HEADER_LEN)

Return the number of usable bytes in a chunk allocated with malloc(memlen).

Definition at line 82 of file buffers.c.

#define CONTENT_LENGTH   "\r\nContent-Length: "
#define MAX_CHUNK_ALLOC   65536

No chunk should take up more than this many bytes.

Definition at line 248 of file buffers.c.

#define MAX_SOCKS_MESSAGE_LEN   512

Do not attempt to parse socks messages longer than this.

This value is actually significantly higher than the longest possible socks message.

Definition at line 1533 of file buffers.c.

#define MIN_CHUNK_ALLOC   256

Every chunk should take up at least this many bytes.

Definition at line 246 of file buffers.c.

#define MIN_READ_LEN   8

If a read onto the end of a chunk would be smaller than this number, then just start a new chunk.

Definition at line 244 of file buffers.c.

#define SOCKS_WARN_INTERVAL   5

Wait this many seconds before warning the user about using SOCKS unsafely again (requires that WarnUnsafeSocks is turned on).

Definition at line 1497 of file buffers.c.


Typedef Documentation

typedef struct buf_pos_t buf_pos_t

Internal structure: represents a position in a buffer.

typedef struct chunk_t chunk_t

A single chunk on a buffer or in a freelist.


Function Documentation

void assert_buf_ok ( buf_t buf)

Log an error and exit if buf is corrupted.

Definition at line 2469 of file buffers.c.

{
  tor_assert(buf);
  tor_assert(buf->magic == BUFFER_MAGIC);

  if (! buf->head) {
    tor_assert(!buf->tail);
    tor_assert(buf->datalen == 0);
  } else {
    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]);
      tor_assert(ch->data < &ch->mem[0]+ch->memlen);
      tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen);
      if (!ch->next)
        tor_assert(ch == buf->tail);
    }
    tor_assert(buf->datalen == total);
  }
}

Here is the caller graph for this function:

static chunk_t* buf_add_chunk_with_capacity ( buf_t buf,
size_t  capacity,
int  capped 
) [static]

Append a new chunk with enough capacity to hold capacity bytes to the tail of buf.

If capped, don't allocate a chunk bigger than MAX_CHUNK_ALLOC.

Definition at line 598 of file buffers.c.

{
  chunk_t *chunk;
  if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) {
    chunk = chunk_new_with_alloc_size(buf->default_chunk_size);
  } else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) {
    chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC);
  } else {
    chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity));
  }
  if (buf->tail) {
    tor_assert(buf->head);
    buf->tail->next = chunk;
    buf->tail = chunk;
  } else {
    tor_assert(!buf->head);
    buf->head = buf->tail = chunk;
  }
  check();
  return chunk;
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t buf_allocation ( const buf_t buf)

Return the total length of all chunks used in buf.

Definition at line 528 of file buffers.c.

{
  size_t total = 0;
  const chunk_t *chunk;
  for (chunk = buf->head; chunk; chunk = chunk->next) {
    total += chunk->memlen;
  }
  return total;
}

Here is the caller graph for this function:

void buf_clear ( buf_t buf)

Remove all data from buf.

Definition at line 508 of file buffers.c.

{
  chunk_t *chunk, *next;
  buf->datalen = 0;
  for (chunk = buf->head; chunk; chunk = next) {
    next = chunk->next;
    chunk_free_unchecked(chunk);
  }
  buf->head = buf->tail = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

buf_t* buf_copy ( const buf_t buf)

Return a new copy of buf

Definition at line 576 of file buffers.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t buf_datalen ( const buf_t buf)

Return the number of bytes stored in buf

Definition at line 521 of file buffers.c.

{
  return buf->datalen;
}

Here is the caller graph for this function:

void buf_dump_freelist_sizes ( int  severity)

Describe the current status of the freelists at log level severity.

Definition at line 335 of file buffers.c.

{
#ifdef ENABLE_BUF_FREELISTS
  int i;
  log(severity, LD_MM, "====== Buffer freelists:");
  for (i = 0; freelists[i].alloc_size; ++i) {
    uint64_t total = ((uint64_t)freelists[i].cur_length) *
      freelists[i].alloc_size;
    log(severity, LD_MM,
        U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT
        " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]",
        U64_PRINTF_ARG(total),
        freelists[i].cur_length, (int)freelists[i].alloc_size,
        U64_PRINTF_ARG(freelists[i].n_alloc),
        U64_PRINTF_ARG(freelists[i].n_free),
        U64_PRINTF_ARG(freelists[i].n_hit));
  }
  log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
      U64_PRINTF_ARG(n_freelist_miss));
#else
  (void)severity;
#endif
}

Here is the caller graph for this function:

static off_t buf_find_offset_of_char ( buf_t buf,
char  ch 
) [static]

Return the index within buf at which ch first appears, or -1 if ch does not appear on buf.

Definition at line 2283 of file buffers.c.

{
  chunk_t *chunk;
  off_t offset = 0;
  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;
}

Here is the caller graph for this function:

static off_t buf_find_pos_of_char ( char  ch,
buf_pos_t out 
) [static]

Advance out to the first appearance of ch at the current position of out, or later.

Return -1 if no instances are found; otherwise returns the absolute position of the character.

Definition at line 1213 of file buffers.c.

{
  const chunk_t *chunk;
  int pos;
  tor_assert(out);
  if (out->chunk) {
    if (out->chunk->datalen) {
      tor_assert(out->pos < (off_t)out->chunk->datalen);
    } else {
      tor_assert(out->pos == 0);
    }
  }
  pos = out->pos;
  for (chunk = out->chunk; chunk; chunk = chunk->next) {
    char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos);
    if (cp) {
      out->chunk = chunk;
      tor_assert(cp - chunk->data < INT_MAX);
      out->pos = (int)(cp - chunk->data);
      return out->chunk_pos + out->pos;
    } else {
      out->chunk_pos += chunk->datalen;
      pos = 0;
    }
  }
  return -1;
}

Here is the caller graph for this function:

int buf_find_string_offset ( const buf_t buf,
const char *  s,
size_t  n 
)

Return the first position in buf at which the n-character string s occurs, or -1 if it does not occur.

Definition at line 1286 of file buffers.c.

{
  buf_pos_t pos;
  buf_pos_init(buf, &pos);
  while (buf_find_pos_of_char(*s, &pos) >= 0) {
    if (buf_matches_at_pos(&pos, s, n)) {
      tor_assert(pos.chunk_pos + pos.pos < INT_MAX);
      return (int)(pos.chunk_pos + pos.pos);
    } else {
      if (buf_pos_inc(&pos)<0)
        return -1;
    }
  }
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void buf_free ( buf_t buf)

Release storage held by buf.

Definition at line 551 of file buffers.c.

{
  if (!buf)
    return;

  buf_clear(buf);
  buf->magic = 0xdeadbeef;
  tor_free(buf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int buf_matches_at_pos ( const buf_pos_t pos,
const char *  s,
size_t  n 
) [static]

Return true iff the n-character string in s appears (verbatim) at pos.

Definition at line 1260 of file buffers.c.

{
  buf_pos_t p;
  if (!n)
    return 1;

  memcpy(&p, pos, sizeof(p));

  while (1) {
    char ch = p.chunk->data[p.pos];
    if (ch != *s)
      return 0;
    ++s;
    /* 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;
    if (buf_pos_inc(&p)<0)
      return 0;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

buf_t* buf_new ( void  )

Allocate and return a new buffer with default capacity.

Definition at line 498 of file buffers.c.

{
  buf_t *buf = tor_malloc_zero(sizeof(buf_t));
  buf->magic = BUFFER_MAGIC;
  buf->default_chunk_size = 4096;
  return buf;
}

Here is the caller graph for this function:

buf_t* buf_new_with_capacity ( size_t  size)

Create and return a new buf with default chunk capacity size.

Definition at line 489 of file buffers.c.

{
  buf_t *b = buf_new();
  b->default_chunk_size = preferred_chunk_size(size);
  return b;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int buf_pos_inc ( buf_pos_t pos) [static]

Advance pos by a single character, if there are any more characters in the buffer.

Returns 0 on success, -1 on failure.

Definition at line 1244 of file buffers.c.

{
  ++pos->pos;
  if (pos->pos == (off_t)pos->chunk->datalen) {
    if (!pos->chunk->next)
      return -1;
    pos->chunk_pos += pos->chunk->datalen;
    pos->chunk = pos->chunk->next;
    pos->pos = 0;
  }
  return 0;
}

Here is the caller graph for this function:

static void buf_pos_init ( const buf_t buf,
buf_pos_t out 
) [static]

Initialize out to point to the first character of buf.

Definition at line 1202 of file buffers.c.

{
  out->chunk = buf->head;
  out->pos = 0;
  out->chunk_pos = 0;
}

Here is the caller graph for this function:

static void buf_pullup ( buf_t buf,
size_t  bytes,
int  nulterminate 
) [static]

Collapse data from the first N chunks from buf into buf->head, growing it as necessary, until buf->head has the first bytes bytes of data from the buffer, or until buf->head has all the data in buf.

If nulterminate is true, ensure that there is a 0 byte in buf->head->mem right after all the data.

Definition at line 379 of file buffers.c.

{
  chunk_t *dest, *src;
  size_t capacity;
  if (!buf->head)
    return;

  check();
  if (buf->datalen < bytes)
    bytes = buf->datalen;

  if (nulterminate) {
    capacity = bytes + 1;
    if (buf->head->datalen >= bytes && CHUNK_REMAINING_CAPACITY(buf->head)) {
      *CHUNK_WRITE_PTR(buf->head) = '\0';
      return;
    }
  } else {
    capacity = bytes;
    if (buf->head->datalen >= bytes)
      return;
  }

  if (buf->head->memlen >= capacity) {
    /* We don't need to grow the first chunk, but we might need to repack it.*/
    size_t needed = capacity - buf->head->datalen;
    if (CHUNK_REMAINING_CAPACITY(buf->head) < needed)
      chunk_repack(buf->head);
    tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed);
  } else {
    chunk_t *newhead;
    size_t newsize;
    /* We need to grow the chunk. */
    chunk_repack(buf->head);
    newsize = CHUNK_SIZE_WITH_ALLOC(preferred_chunk_size(capacity));
    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;
    }
  }

  dest = buf->head;
  while (dest->datalen < bytes) {
    size_t n = bytes - dest->datalen;
    src = dest->next;
    tor_assert(src);
    if (n > src->datalen) {
      memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen);
      dest->datalen += src->datalen;
      dest->next = src->next;
      if (buf->tail == src)
        buf->tail = dest;
      chunk_free_unchecked(src);
    } else {
      memcpy(CHUNK_WRITE_PTR(dest), src->data, n);
      dest->datalen += n;
      src->data += n;
      src->datalen -= n;
      tor_assert(dest->datalen == bytes);
    }
  }

  if (nulterminate) {
    tor_assert(CHUNK_REMAINING_CAPACITY(buf->head));
    *CHUNK_WRITE_PTR(buf->head) = '\0';
  }

  check();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE void buf_remove_from_front ( buf_t buf,
size_t  n 
) [static]

Remove the first n bytes from buf.

Definition at line 463 of file buffers.c.

{
  tor_assert(buf->datalen >= n);
  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;
      chunk_free_unchecked(victim);
    }
  }
  check();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void buf_shrink ( buf_t buf)

Resize buf so it won't hold extra memory that we haven't been using lately.

Definition at line 456 of file buffers.c.

{
  (void)buf;
}

Here is the caller graph for this function:

void buf_shrink_freelists ( int  free_all)

Remove from the freelists most chunks that have not been used since the last call to buf_shrink_freelists().

Definition at line 265 of file buffers.c.

{
#ifdef ENABLE_BUF_FREELISTS
  int i;
  disable_control_logging();
  for (i = 0; freelists[i].alloc_size; ++i) {
    int slack = freelists[i].slack;
    assert_freelist_ok(&freelists[i]);
    if (free_all || freelists[i].lowest_length > slack) {
      int n_to_free = free_all ? freelists[i].cur_length :
        (freelists[i].lowest_length - slack);
      int n_to_skip = freelists[i].cur_length - n_to_free;
      int orig_length = freelists[i].cur_length;
      int orig_n_to_free = n_to_free, n_freed=0;
      int orig_n_to_skip = n_to_skip;
      int new_length = n_to_skip;
      chunk_t **chp = &freelists[i].head;
      chunk_t *chunk;
      while (n_to_skip) {
        if (! (*chp)->next) {
          log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for "
                   "%d-byte chunks, but only found %d. (Length %d)",
                   orig_n_to_skip, (int)freelists[i].alloc_size,
                   orig_n_to_skip-n_to_skip, freelists[i].cur_length);
          assert_freelist_ok(&freelists[i]);
          goto done;
        }
        // tor_assert((*chp)->next);
        chp = &(*chp)->next;
        --n_to_skip;
      }
      chunk = *chp;
      *chp = NULL;
      while (chunk) {
        chunk_t *next = chunk->next;
        tor_free(chunk);
        chunk = next;
        --n_to_free;
        ++n_freed;
        ++freelists[i].n_free;
      }
      if (n_to_free) {
        log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been "
                 "messed up somehow.", (int)freelists[i].alloc_size);
        log_warn(LD_BUG, "There were %d chunks at the start.  I decided to "
                 "keep %d. I wanted to free %d.  I freed %d.  I somehow think "
                 "I have %d left to free.",
                 freelists[i].cur_length, n_to_skip, orig_n_to_free,
                 n_freed, n_to_free);
      }
      // tor_assert(!n_to_free);
      freelists[i].cur_length = new_length;
      log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original "
               "length %d, kept %d, dropped %d.",
               (int)freelists[i].alloc_size, orig_length,
               orig_n_to_skip, orig_n_to_free);
    }
    freelists[i].lowest_length = freelists[i].cur_length;
    assert_freelist_ok(&freelists[i]);
  }
 done:
  enable_control_logging();
#else
  (void) free_all;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

size_t buf_slack ( const buf_t buf)

Return the number of bytes that can be added to buf without performing any additional allocation.

Definition at line 541 of file buffers.c.

{
  if (!buf->tail)
    return 0;
  else
    return CHUNK_REMAINING_CAPACITY(buf->tail);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int cell_command_is_var_length ( uint8_t  command,
int  linkproto 
) [static]

True iff the cell command command is one that implies a variable-length cell in Tor link protocol linkproto.

Definition at line 1015 of file buffers.c.

{
  /* If linkproto is v2 (2), CELL_VERSIONS is the only variable-length cells
   * work as implemented here. If it's 1, there are no variable-length cells.
   * Tor does not support other versions right now, and so can't negotiate
   * them.
   */
  switch (linkproto) {
  case 1:
    /* Link protocol version 1 has no variable-length cells. */
    return 0;
  case 2:
    /* In link protocol version 2, VERSIONS is the only variable-length cell */
    return command == CELL_VERSIONS;
  case 0:
  case 3:
  default:
    /* In link protocol version 3 and later, and in version "unknown",
     * commands 128 and higher indicate variable-length. VERSIONS is
     * grandfathered in. */
    return command == CELL_VERSIONS || command >= 128;
  }
}

Here is the caller graph for this function:

static chunk_t* chunk_copy ( const chunk_t in_chunk) [static]

Return a new copy of in_chunk

Definition at line 563 of file buffers.c.

{
  chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen));
  newch->next = NULL;
  if (in_chunk->data) {
    off_t offset = in_chunk->data - in_chunk->mem;
    newch->data = newch->mem + offset;
  }
  return newch;
}

Here is the caller graph for this function:

static void chunk_free_unchecked ( chunk_t chunk) [static]

Definition at line 211 of file buffers.c.

{
  tor_free(chunk);
}

Here is the caller graph for this function:

static INLINE chunk_t* chunk_grow ( chunk_t chunk,
size_t  sz 
) [static]

Expand chunk until it can hold sz bytes, and return a new pointer to chunk.

Old pointers are no longer valid.

Definition at line 231 of file buffers.c.

{
  off_t offset;
  tor_assert(sz > chunk->memlen);
  offset = chunk->data - chunk->mem;
  chunk = tor_realloc(chunk, CHUNK_ALLOC_SIZE(sz));
  chunk->memlen = sz;
  chunk->data = chunk->mem + offset;
  return chunk;
}

Here is the caller graph for this function:

static INLINE chunk_t* chunk_new_with_alloc_size ( size_t  alloc) [static]

Definition at line 216 of file buffers.c.

{
  chunk_t *ch;
  ch = tor_malloc_roundup(&alloc);
  ch->next = NULL;
  ch->datalen = 0;
  ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
  ch->data = &ch->mem[0];
  return ch;
}

Here is the caller graph for this function:

static INLINE size_t CHUNK_REMAINING_CAPACITY ( const chunk_t chunk) [static]

Return the number of bytes that can be written onto chunk without running out of space.

Definition at line 95 of file buffers.c.

{
  return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen);
}

Here is the caller graph for this function:

static INLINE void chunk_repack ( chunk_t chunk) [static]

Move all bytes stored in chunk to the front of chunk->mem, to free up space at the end.

Definition at line 103 of file buffers.c.

{
  if (chunk->datalen && chunk->data != &chunk->mem[0]) {
    memmove(chunk->mem, chunk->data, chunk->datalen);
  }
  chunk->data = &chunk->mem[0];
}

Here is the caller graph for this function:

static INLINE char* CHUNK_WRITE_PTR ( chunk_t chunk) [static]

Return the next character in chunk onto which data can be appended.

If the chunk is full, this might be off the end of chunk->mem.

Definition at line 87 of file buffers.c.

{
  return chunk->data + chunk->datalen;
}

Here is the caller graph for this function:

int fetch_from_buf ( char *  string,
size_t  string_len,
buf_t buf 
)

Remove string_len bytes from the front of buf, and store them into string.

Return the new buffer size. string_len must be <= the number of bytes on the buffer.

Definition at line 997 of file buffers.c.

{
  /* 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. */

  check();
  peek_from_buf(string, string_len, buf);
  buf_remove_from_front(buf, string_len);
  check();
  tor_assert(buf->datalen < INT_MAX);
  return (int)buf->datalen;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fetch_from_buf_http ( buf_t buf,
char **  headers_out,
size_t  max_headerlen,
char **  body_out,
size_t *  body_used,
size_t  max_bodylen,
int  force_complete 
)

There is a (possibly incomplete) http statement on buf, of the form "\%s\\r\\n\\r\\n\%s", headers, body.

(body may contain NULs.) If a) the headers include a Content-Length field and all bytes in the body are present, or b) there's no Content-Length field and all headers are present, then:

  • strdup headers into *headers_out, and NUL-terminate it.
    • memdup body into *body_out, and NUL-terminate it.
    • Then remove them from buf, and return 1.
  • If headers or body is NULL, discard that part of the buf.
    • If a headers or body doesn't fit in the arg, return -1. (We ensure that the headers or body don't exceed max len, even if we're planning to discard them.)
    • If force_complete is true, then succeed even if not all of the content has arrived.

Else, change nothing and return 0.

Definition at line 1322 of file buffers.c.

{
  char *headers, *p;
  size_t headerlen, bodylen, contentlen;
  int crlf_offset;

  check();
  if (!buf->head)
    return 0;

  crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4);
  if (crlf_offset > (int)max_headerlen ||
      (crlf_offset < 0 && buf->datalen > max_headerlen)) {
    log_debug(LD_HTTP,"headers too long.");
    return -1;
  } else if (crlf_offset < 0) {
    log_debug(LD_HTTP,"headers not all here yet.");
    return 0;
  }
  /* Okay, we have a full header.  Make sure it all appears in the first
   * chunk. */
  if ((int)buf->head->datalen < crlf_offset + 4)
    buf_pullup(buf, crlf_offset+4, 0);
  headerlen = crlf_offset + 4;

  headers = buf->head->data;
  bodylen = buf->datalen - headerlen;
  log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);

  if (max_headerlen <= headerlen) {
    log_warn(LD_HTTP,"headerlen %d larger than %d. Failing.",
             (int)headerlen, (int)max_headerlen-1);
    return -1;
  }
  if (max_bodylen <= bodylen) {
    log_warn(LD_HTTP,"bodylen %d larger than %d. Failing.",
             (int)bodylen, (int)max_bodylen-1);
    return -1;
  }

#define CONTENT_LENGTH "\r\nContent-Length: "
  p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH);
  if (p) {
    int i;
    i = atoi(p+strlen(CONTENT_LENGTH));
    if (i < 0) {
      log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like "
               "someone is trying to crash us.");
      return -1;
    }
    contentlen = i;
    /* if content-length is malformed, then our body length is 0. fine. */
    log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen);
    if (bodylen < contentlen) {
      if (!force_complete) {
        log_debug(LD_HTTP,"body not all here yet.");
        return 0; /* not all there yet */
      }
    }
    if (bodylen > contentlen) {
      bodylen = contentlen;
      log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen);
    }
  }
  /* all happy. copy into the appropriate places, and return 1 */
  if (headers_out) {
    *headers_out = tor_malloc(headerlen+1);
    fetch_from_buf(*headers_out, headerlen, buf);
    (*headers_out)[headerlen] = 0; /* NUL terminate it */
  }
  if (body_out) {
    tor_assert(body_used);
    *body_used = bodylen;
    *body_out = tor_malloc(bodylen+1);
    fetch_from_buf(*body_out, bodylen, buf);
    (*body_out)[bodylen] = 0; /* NUL terminate it */
  }
  check();
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fetch_from_buf_line ( buf_t buf,
char *  data_out,
size_t *  data_len 
)

Try to read a single LF-terminated line from buf, and write it (including the LF), NUL-terminated, into the *data_len byte buffer at data_out.

Set *data_len 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 *data_len.

Definition at line 2305 of file buffers.c.

{
  size_t sz;
  off_t offset;

  if (!buf->head)
    return 0;

  offset = buf_find_offset_of_char(buf, '\n');
  if (offset < 0)
    return 0;
  sz = (size_t) offset;
  if (sz+2 > *data_len) {
    *data_len = sz + 2;
    return -1;
  }
  fetch_from_buf(data_out, sz+1, buf);
  data_out[sz+1] = '\0';
  *data_len = sz+1;
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fetch_from_buf_socks ( buf_t buf,
socks_request_t req,
int  log_sockstype,
int  safe_socks 
)

There is a (possibly incomplete) socks handshake on buf, of one of the forms.

  • socks4: "socksheader username\\0"
  • socks4a: "socksheader username\\0 destaddr\\0"
  • socks5 phase one: "version #methods methods"
  • socks5 phase two: "version command 0 addresstype..." If it's a complete and valid handshake, and destaddr fits in MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf, assign to req, and return 1.

If it's invalid or too big, return -1.

Else it's not all there yet, leave buf alone and return 0.

If you want to specify the socks reply, write it into req->reply and set req->replylen, else leave req->replylen alone.

If log_sockstype is non-zero, then do a notice-level log of whether the connection is possibly leaking DNS requests locally or not.

If safe_socks is true, then reject unsafe socks protocols.

If returning 0 or -1, req->address and req->port are undefined.

Definition at line 1586 of file buffers.c.

{
  int res;
  ssize_t n_drain;
  size_t want_length = 128;

  if (buf->datalen < 2) /* version and another byte */
    return 0;

  do {
    n_drain = 0;
    buf_pullup(buf, want_length, 0);
    tor_assert(buf->head && buf->head->datalen >= 2);
    want_length = 0;

    res = parse_socks(buf->head->data, buf->head->datalen, req, log_sockstype,
                      safe_socks, &n_drain, &want_length);

    if (n_drain < 0)
      buf_clear(buf);
    else if (n_drain > 0)
      buf_remove_from_front(buf, n_drain);

  } while (res == 0 && buf->head && want_length < buf->datalen &&
           buf->datalen >= 2);

  return res;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fetch_from_buf_socks_client ( buf_t buf,
int  state,
char **  reason 
)

Inspect a reply from SOCKS server stored in buf according to state, removing the protocol data upon success.

Return 0 on incomplete response, 1 on success and -1 on error, in which case reason is set to a descriptive message (free() when finished with it).

As a special case, 2 is returned when user/pass is required during SOCKS5 handshake and user/pass is configured.

Definition at line 2081 of file buffers.c.

{
  ssize_t drain = 0;
  int r;
  if (buf->datalen < 2)
    return 0;

  buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0);
  tor_assert(buf->head && buf->head->datalen >= 2);

  r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen,
                         state, reason, &drain);
  if (drain > 0)
    buf_remove_from_front(buf, drain);
  else if (drain < 0)
    buf_clear(buf);

  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int fetch_var_cell_from_buf ( buf_t buf,
var_cell_t **  out,
int  linkproto 
)

Check buf for a variable-length cell according to the rules of link protocol version linkproto.

If one is found, pull it off the buffer and assign a newly allocated var_cell_t to *out, and return 1. Return 0 if whatever is on the start of buf_t is not a variable-length cell. Return 1 and set *out to NULL if there seems to be the start of a variable-length cell on buf, but the whole thing isn't there yet.

Definition at line 1047 of file buffers.c.

{
  char hdr[VAR_CELL_HEADER_SIZE];
  var_cell_t *result;
  uint8_t command;
  uint16_t length;
  check();
  *out = NULL;
  if (buf->datalen < VAR_CELL_HEADER_SIZE)
    return 0;
  peek_from_buf(hdr, sizeof(hdr), buf);

  command = get_uint8(hdr+2);
  if (!(cell_command_is_var_length(command, linkproto)))
    return 0;

  length = ntohs(get_uint16(hdr+3));
  if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
    return 1;
  result = var_cell_new(length);
  result->command = command;
  result->circ_id = ntohs(get_uint16(hdr));

  buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
  peek_from_buf((char*) result->payload, length, buf);
  buf_remove_from_front(buf, length);
  check();

  *out = result;
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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

Write data from buf to the socket s.

Write at most sz bytes, decrement *buf_flushlen by the number of bytes actually written, and remove the written bytes from the buffer. Return the number of bytes written on success, -1 on failure. Return 0 if write() would block.

Definition at line 856 of file buffers.c.

{
  /* XXXX024 It's stupid to overload the return values for these functions:
   * "error status" and "number of bytes flushed" are not mutually exclusive.
   */
  int r;
  size_t flushed = 0;
  tor_assert(buf_flushlen);
  tor_assert(SOCKET_OK(s));
  tor_assert(*buf_flushlen <= buf->datalen);
  tor_assert(sz <= *buf_flushlen);

  check();
  while (sz) {
    size_t flushlen0;
    tor_assert(buf->head);
    if (buf->head->datalen >= sz)
      flushlen0 = sz;
    else
      flushlen0 = buf->head->datalen;

    r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen);
    check();
    if (r < 0)
      return r;
    flushed += r;
    sz -= r;
    if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
      break;
  }
  tor_assert(flushed < INT_MAX);
  return (int)flushed;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int flush_buf_tls ( tor_tls_t tls,
buf_t buf,
size_t  flushlen,
size_t *  buf_flushlen 
)

As flush_buf(), but writes data to a TLS connection.

Can write more than flushlen bytes.

Definition at line 894 of file buffers.c.

{
  int r;
  size_t flushed = 0;
  ssize_t sz;
  tor_assert(buf_flushlen);
  tor_assert(*buf_flushlen <= buf->datalen);
  tor_assert(flushlen <= *buf_flushlen);
  sz = (ssize_t) flushlen;

  /* we want to let tls write even if flushlen is zero, because it might
   * have a partial record pending */
  check_no_tls_errors();

  check();
  do {
    size_t flushlen0;
    if (buf->head) {
      if ((ssize_t)buf->head->datalen >= sz)
        flushlen0 = sz;
      else
        flushlen0 = buf->head->datalen;
    } else {
      flushlen0 = 0;
    }

    r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen);
    check();
    if (r < 0)
      return r;
    flushed += r;
    sz -= r;
    if (r == 0) /* Can't flush any more now. */
      break;
  } while (sz > 0);
  tor_assert(flushed < INT_MAX);
  return (int)flushed;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int flush_chunk ( tor_socket_t  s,
buf_t buf,
chunk_t chunk,
size_t  sz,
size_t *  buf_flushlen 
) [static]

Helper for flush_buf(): try to write sz bytes from chunk chunk of buffer buf onto socket s.

On success, deduct the bytes written from *buf_flushlen. Return the number of bytes written on success, 0 on blocking, -1 on failure.

Definition at line 784 of file buffers.c.

{
  ssize_t write_result;

  if (sz > chunk->datalen)
    sz = chunk->datalen;
  write_result = tor_socket_send(s, chunk->data, sz, 0);

  if (write_result < 0) {
    int e = tor_socket_errno(s);
    if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
#ifdef _WIN32
      if (e == WSAENOBUFS)
        log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?");
#endif
      return -1;
    }
    log_debug(LD_NET,"write() would block, returning.");
    return 0;
  } else {
    *buf_flushlen -= write_result;
    buf_remove_from_front(buf, write_result);
    tor_assert(write_result < INT_MAX);
    return (int)write_result;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int flush_chunk_tls ( tor_tls_t tls,
buf_t buf,
chunk_t chunk,
size_t  sz,
size_t *  buf_flushlen 
) [static]

Helper for flush_buf_tls(): try to write sz bytes from chunk chunk of buffer buf onto socket s.

(Tries to write more if there is a forced pending write size.) On success, deduct the bytes written from *buf_flushlen. Return the number of bytes written on success, and a TOR_TLS error code on failure or blocking.

Definition at line 819 of file buffers.c.

{
  int r;
  size_t forced;
  char *data;

  forced = tor_tls_get_forced_write_size(tls);
  if (forced > sz)
    sz = forced;
  if (chunk) {
    data = chunk->data;
    tor_assert(sz <= chunk->datalen);
  } else {
    data = NULL;
    tor_assert(sz == 0);
  }
  r = tor_tls_write(tls, data, sz);
  if (r < 0)
    return r;
  if (*buf_flushlen > (size_t)r)
    *buf_flushlen -= r;
  else
    *buf_flushlen = 0;
  buf_remove_from_front(buf, r);
  log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.",
            r,(int)*buf_flushlen,(int)buf->datalen);
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int generic_buffer_set_to_copy ( generic_buffer_t **  output,
const generic_buffer_t input 
)

Set *output to contain a copy of the data in *input

Definition at line 2431 of file buffers.c.

{
#ifdef USE_BUFFEREVENTS
  struct evbuffer_ptr ptr;
  size_t remaining = evbuffer_get_length(input);
  if (*output) {
    evbuffer_drain(*output, evbuffer_get_length(*output));
  } else {
    if (!(*output = evbuffer_new()))
      return -1;
  }
  evbuffer_ptr_set((struct evbuffer*)input, &ptr, 0, EVBUFFER_PTR_SET);
  while (remaining) {
    struct evbuffer_iovec v[4];
    int n_used, i;
    n_used = evbuffer_peek((struct evbuffer*)input, -1, &ptr, v, 4);
    if (n_used < 0)
      return -1;
    for (i=0;i<n_used;++i) {
      evbuffer_add(*output, v[i].iov_base, v[i].iov_len);
      tor_assert(v[i].iov_len <= remaining);
      remaining -= v[i].iov_len;
      evbuffer_ptr_set((struct evbuffer*)input,
                       &ptr, v[i].iov_len, EVBUFFER_PTR_ADD);
    }
  }
#else
  if (*output)
    buf_free(*output);
  *output = buf_copy(input);
#endif
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void log_unsafe_socks_warning ( int  socks_protocol,
const char *  address,
uint16_t  port,
int  safe_socks 
) [static]

Warn that the user application has made an unsafe socks request using protocol socks_protocol on port port.

Don't warn more than once per SOCKS_WARN_INTERVAL, unless safe_socks is set.

Definition at line 1503 of file buffers.c.

{
  static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL);

  const or_options_t *options = get_options();
  char *m = NULL;
  if (! options->WarnUnsafeSocks)
    return;
  if (safe_socks || (m = rate_limit_log(&socks_ratelim, approx_time()))) {
    log_warn(LD_APP,
             "Your application (using socks%d to port %d) is giving "
             "Tor only an IP address. Applications that do DNS resolves "
             "themselves may leak information. Consider using Socks4A "
             "(e.g. via privoxy or socat) instead. For more information, "
             "please see https://wiki.torproject.org/TheOnionRouter/"
             "TorFAQ#SOCKSAndDNS.%s%s",
             socks_protocol,
             (int)port,
             safe_socks ? " Rejecting." : "",
             m ? m : "");
    tor_free(m);
  }
  control_event_client_status(LOG_WARN,
                              "DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d",
                              socks_protocol, address, (int)port);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int move_buf_to_buf ( buf_t buf_out,
buf_t buf_in,
size_t *  buf_flushlen 
)

Move up to *buf_flushlen bytes from buf_in to buf_out, and modify *buf_flushlen appropriately.

Return the number of bytes actually copied.

Definition at line 1169 of file buffers.c.

{
  /* We can do way better here, but this doesn't turn up in any profiles. */
  char b[4096];
  size_t cp, len;
  len = *buf_flushlen;
  if (len > buf_in->datalen)
    len = buf_in->datalen;

  cp = len; /* Remember the number of bytes we intend to copy. */
  tor_assert(cp < INT_MAX);
  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;
    fetch_from_buf(b, n, buf_in);
    write_to_buf(b, n, buf_out);
    len -= n;
  }
  *buf_flushlen -= cp;
  return (int)cp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int parse_socks ( const char *  data,
size_t  datalen,
socks_request_t req,
int  log_sockstype,
int  safe_socks,
ssize_t *  drain_out,
size_t *  want_length_out 
) [static]

Implementation helper to implement fetch_from_*_socks.

Instead of looking at a buffer's contents, we look at the datalen bytes of data in data. Instead of removing data from the buffer, we set drain_out to the amount of data that should be removed (or -1 if the buffer should be cleared). Instead of pulling more data into the first chunk of the buffer, we set *want_length_out to the number of bytes we'd like to see in the input buffer, if they're available.

Definition at line 1704 of file buffers.c.

{
  unsigned int len;
  char tmpbuf[TOR_ADDR_BUF_LEN+1];
  tor_addr_t destaddr;
  uint32_t destip;
  uint8_t socksver;
  char *next, *startaddr;
  unsigned char usernamelen, passlen;
  struct in_addr in;

  if (datalen < 2) {
    /* We always need at least 2 bytes. */
    *want_length_out = 2;
    return 0;
  }

  if (req->socks_version == 5 && !req->got_auth) {
    /* See if we have received authentication.  Strictly speaking, we should
       also check whether we actually negotiated username/password
       authentication.  But some broken clients will send us authentication
       even if we negotiated SOCKS_NO_AUTH. */
    if (*data == 1) { /* username/pass version 1 */
      /* Format is: authversion [1 byte] == 1
                    usernamelen [1 byte]
                    username    [usernamelen bytes]
                    passlen     [1 byte]
                    password    [passlen bytes] */
      usernamelen = (unsigned char)*(data + 1);
      if (datalen < 2u + usernamelen + 1u) {
        *want_length_out = 2u + usernamelen + 1u;
        return 0;
      }
      passlen = (unsigned char)*(data + 2u + usernamelen);
      if (datalen < 2u + usernamelen + 1u + passlen) {
        *want_length_out = 2u + usernamelen + 1u + passlen;
        return 0;
      }
      req->replylen = 2; /* 2 bytes of response */
      req->reply[0] = 5;
      req->reply[1] = 0; /* authentication successful */
      log_debug(LD_APP,
               "socks5: Accepted username/password without checking.");
      if (usernamelen) {
        req->username = tor_memdup(data+2u, usernamelen);
        req->usernamelen = usernamelen;
      }
      if (passlen) {
        req->password = tor_memdup(data+3u+usernamelen, passlen);
        req->passwordlen = passlen;
      }
      *drain_out = 2u + usernamelen + 1u + passlen;
      req->got_auth = 1;
      *want_length_out = 7; /* Minimal socks5 sommand. */
      return 0;
    } else if (req->auth_type == SOCKS_USER_PASS) {
      /* unknown version byte */
      log_warn(LD_APP, "Socks5 username/password version %d not recognized; "
               "rejecting.", (int)*data);
      return -1;
    }
  }

  socksver = *data;

  switch (socksver) { /* which version of socks? */
    case 5: /* socks5 */

      if (req->socks_version != 5) { /* we need to negotiate a method */
        unsigned char nummethods = (unsigned char)*(data+1);
        int r=0;
        tor_assert(!req->socks_version);
        if (datalen < 2u+nummethods) {
          *want_length_out = 2u+nummethods;
          return 0;
        }
        if (!nummethods)
          return -1;
        req->replylen = 2; /* 2 bytes of response */
        req->reply[0] = 5; /* socks5 reply */
        if (memchr(data+2, SOCKS_NO_AUTH, nummethods)) {
          req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth
                                            method */
          req->socks_version = 5; /* remember we've already negotiated auth */
          log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
          r=0;
        } else if (memchr(data+2, SOCKS_USER_PASS, nummethods)) {
          req->auth_type = SOCKS_USER_PASS;
          req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass"
                                              auth method */
          req->socks_version = 5; /* remember we've already negotiated auth */
          log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
          r=0;
        } else {
          log_warn(LD_APP,
                    "socks5: offered methods don't include 'no auth' or "
                    "username/password. Rejecting.");
          req->reply[1] = '\xFF'; /* reject all methods */
          r=-1;
        }
        /* Remove packet from buf. Some SOCKS clients will have sent extra
         * junk at this point; let's hope it's an authentication message. */
        *drain_out = 2u + nummethods;

        return r;
      }
      if (req->auth_type != SOCKS_NO_AUTH && !req->got_auth) {
        log_warn(LD_APP,
                 "socks5: negotiated authentication, but none provided");
        return -1;
      }
      /* we know the method; read in the request */
      log_debug(LD_APP,"socks5: checking request");
      if (datalen < 7) {/* basic info plus >=1 for addr plus 2 for port */
        *want_length_out = 7;
        return 0; /* not yet */
      }
      req->command = (unsigned char) *(data+1);
      if (req->command != SOCKS_COMMAND_CONNECT &&
          req->command != SOCKS_COMMAND_RESOLVE &&
          req->command != SOCKS_COMMAND_RESOLVE_PTR) {
        /* not a connect or resolve or a resolve_ptr? we don't support it. */
        log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
                 req->command);
        return -1;
      }
      switch (*(data+3)) { /* address type */
        case 1: /* IPv4 address */
        case 4: /* IPv6 address */ {
          const int is_v6 = *(data+3) == 4;
          const unsigned addrlen = is_v6 ? 16 : 4;
          log_debug(LD_APP,"socks5: ipv4 address type");
          if (datalen < 6+addrlen) {/* ip/port there? */
            *want_length_out = 6+addrlen;
            return 0; /* not yet */
          }

          if (is_v6)
            tor_addr_from_ipv6_bytes(&destaddr, data+4);
          else
            tor_addr_from_ipv4n(&destaddr, get_uint32(data+4));

          tor_addr_to_str(tmpbuf, &destaddr, sizeof(tmpbuf), 1);

          if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
            log_warn(LD_APP,
                     "socks5 IP takes %d bytes, which doesn't fit in %d. "
                     "Rejecting.",
                     (int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN);
            return -1;
          }
          strlcpy(req->address,tmpbuf,sizeof(req->address));
          req->port = ntohs(get_uint16(data+4+addrlen));
          *drain_out = 6+addrlen;
          if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
              !addressmap_have_mapping(req->address,0)) {
            log_unsafe_socks_warning(5, req->address, req->port, safe_socks);
            if (safe_socks)
              return -1;
          }
          return 1;
        }
        case 3: /* fqdn */
          log_debug(LD_APP,"socks5: fqdn address type");
          if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
            log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
                     "hostname type. Rejecting.");
            return -1;
          }
          len = (unsigned char)*(data+4);
          if (datalen < 7+len) { /* addr/port there? */
            *want_length_out = 7+len;
            return 0; /* not yet */
          }
          if (len+1 > MAX_SOCKS_ADDR_LEN) {
            log_warn(LD_APP,
                     "socks5 hostname is %d bytes, which doesn't fit in "
                     "%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
            return -1;
          }
          memcpy(req->address,data+5,len);
          req->address[len] = 0;
          req->port = ntohs(get_uint16(data+5+len));
          *drain_out = 5+len+2;
          if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
            log_warn(LD_PROTOCOL,
                     "Your application (using socks5 to port %d) gave Tor "
                     "a malformed hostname: %s. Rejecting the connection.",
                     req->port, escaped(req->address));
            return -1;
          }
          if (log_sockstype)
            log_notice(LD_APP,
                  "Your application (using socks5 to port %d) instructed "
                  "Tor to take care of the DNS resolution itself if "
                  "necessary. This is good.", req->port);
          return 1;
        default: /* unsupported */
          log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.",
                   (int) *(data+3));
          return -1;
      }
      tor_assert(0);
    case 4: { /* socks4 */
      enum {socks4, socks4a} socks4_prot = socks4a;
      const char *authstart, *authend;
      /* http://ss5.sourceforge.net/socks4.protocol.txt */
      /* http://ss5.sourceforge.net/socks4A.protocol.txt */

      req->socks_version = 4;
      if (datalen < SOCKS4_NETWORK_LEN) {/* basic info available? */
        *want_length_out = SOCKS4_NETWORK_LEN;
        return 0; /* not yet */
      }
      // buf_pullup(buf, 1280, 0);
      req->command = (unsigned char) *(data+1);
      if (req->command != SOCKS_COMMAND_CONNECT &&
          req->command != SOCKS_COMMAND_RESOLVE) {
        /* not a connect or resolve? we don't support it. (No resolve_ptr with
         * socks4.) */
        log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.",
                 req->command);
        return -1;
      }

      req->port = ntohs(get_uint16(data+2));
      destip = ntohl(get_uint32(data+4));
      if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) {
        log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting.");
        return -1;
      }
      if (destip >> 8) {
        log_debug(LD_APP,"socks4: destip not in form 0.0.0.x.");
        in.s_addr = htonl(destip);
        tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
        if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
          log_debug(LD_APP,"socks4 addr (%d bytes) too long. Rejecting.",
                    (int)strlen(tmpbuf));
          return -1;
        }
        log_debug(LD_APP,
                  "socks4: successfully read destip (%s)",
                  safe_str_client(tmpbuf));
        socks4_prot = socks4;
      }

      authstart = data + SOCKS4_NETWORK_LEN;
      next = memchr(authstart, 0,
                    datalen-SOCKS4_NETWORK_LEN);
      if (!next) {
        if (datalen >= 1024) {
          log_debug(LD_APP, "Socks4 user name too long; rejecting.");
          return -1;
        }
        log_debug(LD_APP,"socks4: Username not here yet.");
        *want_length_out = datalen+1024; /* More than we need, but safe */
        return 0;
      }
      authend = next;
      tor_assert(next < data+datalen);

      startaddr = NULL;
      if (socks4_prot != socks4a &&
          !addressmap_have_mapping(tmpbuf,0)) {
        log_unsafe_socks_warning(4, tmpbuf, req->port, safe_socks);

        if (safe_socks)
          return -1;
      }
      if (socks4_prot == socks4a) {
        if (next+1 == data+datalen) {
          log_debug(LD_APP,"socks4: No part of destaddr here yet.");
          *want_length_out = datalen + 1024; /* More than we need, but safe */
          return 0;
        }
        startaddr = next+1;
        next = memchr(startaddr, 0, data + datalen - startaddr);
        if (!next) {
          if (datalen >= 1024) {
            log_debug(LD_APP,"socks4: Destaddr too long.");
            return -1;
          }
          log_debug(LD_APP,"socks4: Destaddr not all here yet.");
          *want_length_out = datalen + 1024; /* More than we need, but safe */
          return 0;
        }
        if (MAX_SOCKS_ADDR_LEN <= next-startaddr) {
          log_warn(LD_APP,"socks4: Destaddr too long. Rejecting.");
          return -1;
        }
        // tor_assert(next < buf->cur+buf->datalen);

        if (log_sockstype)
          log_notice(LD_APP,
                     "Your application (using socks4a to port %d) instructed "
                     "Tor to take care of the DNS resolution itself if "
                     "necessary. This is good.", req->port);
      }
      log_debug(LD_APP,"socks4: Everything is here. Success.");
      strlcpy(req->address, startaddr ? startaddr : tmpbuf,
              sizeof(req->address));
      if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
        log_warn(LD_PROTOCOL,
                 "Your application (using socks4 to port %d) gave Tor "
                 "a malformed hostname: %s. Rejecting the connection.",
                 req->port, escaped(req->address));
        return -1;
      }
      if (authend != authstart) {
        req->got_auth = 1;
        req->usernamelen = authend - authstart;
        req->username = tor_memdup(authstart, authend - authstart);
      }
      /* next points to the final \0 on inbuf */
      *drain_out = next - data + 1;
      return 1;
    }
    case 'G': /* get */
    case 'H': /* head */
    case 'P': /* put/post */
    case 'C': /* connect */
      strlcpy((char*)req->reply,
"HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
"<html>\n"
"<head>\n"
"<title>Tor is not an HTTP Proxy</title>\n"
"</head>\n"
"<body>\n"
"<h1>Tor is not an HTTP Proxy</h1>\n"
"<p>\n"
"It appears you have configured your web browser to use Tor as an HTTP proxy."
"\n"
"This is not correct: Tor is a SOCKS proxy, not an HTTP proxy.\n"
"Please configure your client accordingly.\n"
"</p>\n"
"<p>\n"
"See <a href=\"https://www.torproject.org/documentation.html\">"
           "https://www.torproject.org/documentation.html</a> for more "
           "information.\n"
"<!-- Plus this comment, to make the body response more than 512 bytes, so "
"     IE will be willing to display it. Comment comment comment comment "
"     comment comment comment comment comment comment comment comment.-->\n"
"</p>\n"
"</body>\n"
"</html>\n"
             , MAX_SOCKS_REPLY_LEN);
      req->replylen = strlen((char*)req->reply)+1;
      /* fall through */
    default: /* version is not socks4 or socks5 */
      log_warn(LD_APP,
               "Socks version %d not recognized. (Tor is not an http proxy.)",
               *(data));
      {
        /* Tell the controller the first 8 bytes. */
        char *tmp = tor_strndup(data, datalen < 8 ? datalen : 8);
        control_event_client_status(LOG_WARN,
                                    "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
                                    escaped(tmp));
        tor_free(tmp);
      }
      return -1;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int parse_socks_client ( const uint8_t *  data,
size_t  datalen,
int  state,
char **  reason,
ssize_t *  drain_out 
) [static]

Implementation logic for fetch_from_*_socks_client.

Definition at line 2131 of file buffers.c.

{
  unsigned int addrlen;
  *drain_out = 0;
  if (datalen < 2)
    return 0;

  switch (state) {
    case PROXY_SOCKS4_WANT_CONNECT_OK:
      /* Wait for the complete response */
      if (datalen < 8)
        return 0;

      if (data[1] != 0x5a) {
        *reason = tor_strdup(socks4_response_code_to_string(data[1]));
        return -1;
      }

      /* Success */
      *drain_out = 8;
      return 1;

    case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
      /* we don't have any credentials */
      if (data[1] != 0x00) {
        *reason = tor_strdup("server doesn't support any of our "
                             "available authentication methods");
        return -1;
      }

      log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
      *drain_out = -1;
      return 1;

    case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
      /* we have a username and password. return 1 if we can proceed without
       * providing authentication, or 2 otherwise. */
      switch (data[1]) {
        case 0x00:
          log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
                            "doesn't require authentication.");
          *drain_out = -1;
          return 1;
        case 0x02:
          log_info(LD_NET, "SOCKS 5 client: need authentication.");
          *drain_out = -1;
          return 2;
        /* fall through */
      }

      *reason = tor_strdup("server doesn't support any of our available "
                           "authentication methods");
      return -1;

    case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
      /* handle server reply to rfc1929 authentication */
      if (data[1] != 0x00) {
        *reason = tor_strdup("authentication failed");
        return -1;
      }

      log_info(LD_NET, "SOCKS 5 client: authentication successful.");
      *drain_out = -1;
      return 1;

    case PROXY_SOCKS5_WANT_CONNECT_OK:
      /* response is variable length. BND.ADDR, etc, isn't needed
       * (don't bother with buf_pullup()), but make sure to eat all
       * the data used */

      /* wait for address type field to arrive */
      if (datalen < 4)
        return 0;

      switch (data[3]) {
        case 0x01: /* ip4 */
          addrlen = 4;
          break;
        case 0x04: /* ip6 */
          addrlen = 16;
          break;
        case 0x03: /* fqdn (can this happen here?) */
          if (datalen < 5)
            return 0;
          addrlen = 1 + data[4];
          break;
        default:
          *reason = tor_strdup("invalid response to connect request");
          return -1;
      }

      /* wait for address and port */
      if (datalen < 6 + addrlen)
        return 0;

      if (data[1] != 0x00) {
        *reason = tor_strdup(socks5_response_code_to_string(data[1]));
        return -1;
      }

      *drain_out = 6 + addrlen;
      return 1;
  }

  /* shouldn't get here... */
  tor_assert(0);

  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return 1 iff buf looks more like it has an (obsolete) v0 controller command on it than any valid v1 controller command.

Definition at line 2246 of file buffers.c.

{
  if (buf->datalen >= 4) {
    char header[4];
    uint16_t cmd;
    peek_from_buf(header, sizeof(header), buf);
    cmd = ntohs(get_uint16(header+2));
    if (cmd <= 0x14)
      return 1; /* This is definitely not a v1 control command. */
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE void peek_from_buf ( char *  string,
size_t  string_len,
const buf_t buf 
) [static]

Helper: copy the first string_len bytes from buf onto string.

Definition at line 970 of file buffers.c.

{
  chunk_t *chunk;

  tor_assert(string);
  /* make sure we don't ask for too much */
  tor_assert(string_len <= buf->datalen);
  /* assert_buf_ok(buf); */

  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;
  }
}

Here is the caller graph for this function:

static INLINE size_t preferred_chunk_size ( size_t  target) [static]

Return the allocation size we'd like to use to hold target bytes.

Definition at line 253 of file buffers.c.

{
  size_t sz = MIN_CHUNK_ALLOC;
  while (CHUNK_SIZE_WITH_ALLOC(sz) < target) {
    sz <<= 1;
  }
  return sz;
}

Here is the caller graph for this function:

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

Read from socket s, writing onto end of buf.

Read at most at_most bytes, growing the buffer as necessary. If recv() returns 0 (because of EOF), set *reached_eof to 1 and return 0. Return -1 on error; else return the number of bytes read.

Definition at line 682 of file buffers.c.

{
  /* XXXX024 It's stupid to overload the return values for these functions:
   * "error status" and "number of bytes read" are not mutually exclusive.
   */
  int r = 0;
  size_t total_read = 0;

  check();
  tor_assert(reached_eof);
  tor_assert(SOCKET_OK(s));

  while (at_most > total_read) {
    size_t readlen = at_most - total_read;
    chunk_t *chunk;
    if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
      chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
      if (readlen > chunk->memlen)
        readlen = chunk->memlen;
    } else {
      size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
      chunk = buf->tail;
      if (cap < readlen)
        readlen = cap;
    }

    r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error);
    check();
    if (r < 0)
      return r; /* Error */
    tor_assert(total_read+r < INT_MAX);
    total_read += r;
    if ((size_t)r < readlen) { /* eof, block, or no more to read. */
      break;
    }
  }
  return (int)total_read;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int read_to_buf_tls ( tor_tls_t tls,
size_t  at_most,
buf_t buf 
)

As read_to_buf, but reads from a TLS connection, and returns a TLS status value rather than the number of bytes read.

Using TLS on OR connections complicates matters in two ways.

First, a TLS stream has its own read buffer independent of the connection's read buffer. (TLS needs to read an entire frame from the network before it can decrypt any data. Thus, trying to read 1 byte from TLS can require that several KB be read from the network and decrypted. The extra data is stored in TLS's decrypt buffer.) Because the data hasn't been read by Tor (it's still inside the TLS), this means that sometimes a connection "has stuff to read" even when poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is used in connection.c to detect TLS objects with non-empty internal buffers and read from them again.

Second, the TLS stream's events do not correspond directly to network events: sometimes, before a TLS stream can read, the network must be ready to write -- or vice versa.

Definition at line 743 of file buffers.c.

{
  int r = 0;
  size_t total_read = 0;

  check_no_tls_errors();

  check();

  while (at_most > total_read) {
    size_t readlen = at_most - total_read;
    chunk_t *chunk;
    if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
      chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
      if (readlen > chunk->memlen)
        readlen = chunk->memlen;
    } else {
      size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
      chunk = buf->tail;
      if (cap < readlen)
        readlen = cap;
    }

    r = read_to_chunk_tls(buf, chunk, tls, readlen);
    check();
    if (r < 0)
      return r; /* Error */
    tor_assert(total_read+r < INT_MAX);
     total_read += r;
    if ((size_t)r < readlen) /* eof, block, or no more to read. */
      break;
  }
  return (int)total_read;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int read_to_chunk ( buf_t buf,
chunk_t chunk,
tor_socket_t  fd,
size_t  at_most,
int *  reached_eof,
int *  socket_error 
) [static]

Read up to at_most bytes from the socket fd into chunk (which must be on buf).

If we get an EOF, set *reached_eof to 1. Return -1 on error, 0 on eof or blocking, and the number of bytes read otherwise.

Definition at line 625 of file buffers.c.

{
  ssize_t read_result;
  if (at_most > CHUNK_REMAINING_CAPACITY(chunk))
    at_most = CHUNK_REMAINING_CAPACITY(chunk);
  read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0);

  if (read_result < 0) {
    int e = tor_socket_errno(fd);
    if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
#ifdef _WIN32
      if (e == WSAENOBUFS)
        log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?");
#endif
      *socket_error = e;
      return -1;
    }
    return 0; /* would block. */
  } else if (read_result == 0) {
    log_debug(LD_NET,"Encountered eof on fd %d", (int)fd);
    *reached_eof = 1;
    return 0;
  } else { /* actually got bytes. */
    buf->datalen += read_result;
    chunk->datalen += read_result;
    log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
              (int)buf->datalen);
    tor_assert(read_result < INT_MAX);
    return (int)read_result;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE int read_to_chunk_tls ( buf_t buf,
chunk_t chunk,
tor_tls_t tls,
size_t  at_most 
) [static]

As read_to_chunk(), but return (negative) error code on error, blocking, or TLS, and the number of bytes read otherwise.

Definition at line 661 of file buffers.c.

{
  int read_result;

  tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most);
  read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most);
  if (read_result < 0)
    return read_result;
  buf->datalen += read_result;
  chunk->datalen += read_result;
  return read_result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Free all storage held in the socks_request_t req.

Definition at line 1544 of file buffers.c.

{
  if (!req)
    return;
  if (req->username) {
    memset(req->username, 0x10, req->usernamelen);
    tor_free(req->username);
  }
  if (req->password) {
    memset(req->password, 0x04, req->passwordlen);
    tor_free(req->password);
  }
  memset(req, 0xCC, sizeof(socks_request_t));
  tor_free(req);
}

Here is the caller graph for this function:

Return a new socks_request_t.

Definition at line 1537 of file buffers.c.

{
  return tor_malloc_zero(sizeof(socks_request_t));
}

Here is the caller graph for this function:

int write_to_buf ( const char *  string,
size_t  string_len,
buf_t buf 
)

Append string_len bytes from string to the end of buf.

Return the new length of the buffer on success, -1 on failure.

Definition at line 940 of file buffers.c.

{
  if (!string_len)
    return (int)buf->datalen;
  check();

  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);
    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;
  }

  check();
  tor_assert(buf->datalen < INT_MAX);
  return (int)buf->datalen;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int write_to_buf_zlib ( buf_t buf,
tor_zlib_state_t state,
const char *  data,
size_t  data_len,
int  done 
)

Compress on uncompress the data_len bytes in data using the zlib state state, appending the result to buf.

If done is true, flush the data in the state and finish the compression/uncompression. Return -1 on failure, 0 on success.

Definition at line 2332 of file buffers.c.

{
  char *next;
  size_t old_avail, avail;
  int over = 0;
  do {
    int need_new_chunk = 0;
    if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) {
      size_t cap = data_len / 4;
      buf_add_chunk_with_capacity(buf, cap, 1);
    }
    next = CHUNK_WRITE_PTR(buf->tail);
    avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail);
    switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) {
      case TOR_ZLIB_DONE:
        over = 1;
        break;
      case TOR_ZLIB_ERR:
        return -1;
      case TOR_ZLIB_OK:
        if (data_len == 0)
          over = 1;
        break;
      case TOR_ZLIB_BUF_FULL:
        if (avail) {
          /* Zlib says we need more room (ZLIB_BUF_FULL).  Start a new chunk
           * automatically, whether were going to or not. */
          need_new_chunk = 1;
        }
        break;
    }
    buf->datalen += old_avail - avail;
    buf->tail->datalen += old_avail - avail;
    if (need_new_chunk) {
      buf_add_chunk_with_capacity(buf, data_len/4, 1);
    }

  } while (!over);
  check();
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function: