Back to index

tor  0.2.3.19-rc
Defines | Functions
buffers.h File Reference

Header file for buffers.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define generic_buffer_new()   buf_new()
#define generic_buffer_len(b)   buf_datalen((b))
#define generic_buffer_add(b, dat, len)   write_to_buf((dat),(len),(b))
#define generic_buffer_get(b, buf, buflen)   fetch_from_buf((buf),(buflen),(b))
#define generic_buffer_clear(b)   buf_clear((b))
#define generic_buffer_free(b)   buf_free((b))

Functions

buf_tbuf_new (void)
 Allocate and return a new buffer with default capacity.
buf_tbuf_new_with_capacity (size_t size)
 Create and return a new buf with default chunk capacity size.
void buf_free (buf_t *buf)
 Release storage held by buf.
void buf_clear (buf_t *buf)
 Remove all data from buf.
buf_tbuf_copy (const buf_t *buf)
 Return a new copy of buf
void buf_shrink (buf_t *buf)
 Resize buf so it won't hold extra memory that we haven't been using lately.
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.
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.
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.
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 sz, 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.
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 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.
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.
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 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.
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 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 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.
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

Header file for buffers.c.

Definition in file buffers.h.


Define Documentation

#define generic_buffer_add (   b,
  dat,
  len 
)    write_to_buf((dat),(len),(b))

Definition at line 81 of file buffers.h.

#define generic_buffer_clear (   b)    buf_clear((b))

Definition at line 83 of file buffers.h.

#define generic_buffer_free (   b)    buf_free((b))

Definition at line 84 of file buffers.h.

#define generic_buffer_get (   b,
  buf,
  buflen 
)    fetch_from_buf((buf),(buflen),(b))

Definition at line 82 of file buffers.h.

#define generic_buffer_len (   b)    buf_datalen((b))

Definition at line 80 of file buffers.h.

#define generic_buffer_new ( )    buf_new()

Definition at line 79 of file buffers.h.


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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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: