Move the tls parts of buffers.c into buffers_tls.c

This commit is contained in:
Nick Mathewson 2017-08-08 15:06:40 -04:00
parent 5921b465e7
commit 150089cbd7
8 changed files with 222 additions and 185 deletions

View File

@ -27,7 +27,6 @@
#include "util.h"
#include "torint.h"
#include "torlog.h"
#include "tortls.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -101,22 +100,6 @@
} while (0)
#endif
/** Return the next character in <b>chunk</b> onto which data can be appended.
* If the chunk is full, this might be off the end of chunk->mem. */
static inline char *
CHUNK_WRITE_PTR(chunk_t *chunk)
{
return chunk->data + chunk->datalen;
}
/** Return the number of bytes that can be written onto <b>chunk</b> without
* running out of space. */
static inline size_t
CHUNK_REMAINING_CAPACITY(const chunk_t *chunk)
{
return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen);
}
/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
* to free up space at the end. */
static inline void
@ -183,9 +166,6 @@ chunk_grow(chunk_t *chunk, size_t sz)
return chunk;
}
/** If a read onto the end of a chunk would be smaller than this number, then
* just start a new chunk. */
#define MIN_READ_LEN 8
/** Every chunk should take up at least this many bytes. */
#define MIN_CHUNK_ALLOC 256
/** No chunk should take up more than this many bytes. */
@ -479,7 +459,7 @@ buf_copy(const buf_t *buf)
/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
* the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
* than MAX_CHUNK_ALLOC. */
static chunk_t *
chunk_t *
buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
{
chunk_t *chunk;
@ -564,23 +544,6 @@ read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, 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. */
static inline int
read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
size_t at_most)
{
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;
}
/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most
* <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0
* (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on
@ -633,67 +596,6 @@ read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof,
return (int)total_read;
}
/** 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.
*/
int
read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf)
{
int r = 0;
size_t total_read = 0;
check_no_tls_errors();
check();
if (BUG(buf->datalen >= INT_MAX))
return -1;
if (BUG(buf->datalen >= INT_MAX - at_most))
return -1;
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;
}
/** Helper for flush_buf(): try to write <b>sz</b> bytes from chunk
* <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct
* the bytes written from *<b>buf_flushlen</b>. Return the number of bytes
@ -728,43 +630,6 @@ flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz,
}
}
/** Helper for flush_buf_tls(): try to write <b>sz</b> bytes from chunk
* <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write
* more if there is a forced pending write size.) On success, deduct the
* bytes written from *<b>buf_flushlen</b>. Return the number of bytes
* written on success, and a TOR_TLS error code on failure or blocking.
*/
static inline int
flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
size_t sz, size_t *buf_flushlen)
{
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;
}
/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
* <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
* the number of bytes actually written, and remove the written bytes
@ -806,50 +671,6 @@ flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen)
return (int)flushed;
}
/** As flush_buf(), but writes data to a TLS connection. Can write more than
* <b>flushlen</b> bytes.
*/
int
flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t flushlen,
size_t *buf_flushlen)
{
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;
}
/** Append <b>string_len</b> bytes from <b>string</b> to the end of
* <b>buf</b>.
*

View File

@ -19,9 +19,7 @@
typedef struct buf_t buf_t;
struct tor_tls_t;
struct tor_compress_state_t;
struct ext_or_cmd_t;
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
@ -39,11 +37,8 @@ size_t buf_get_total_allocation(void);
int read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof,
int *socket_error);
int read_to_buf_tls(struct tor_tls_t *tls, size_t at_most, buf_t *buf);
int flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen);
int flush_buf_tls(struct tor_tls_t *tls, buf_t *buf, size_t sz,
size_t *buf_flushlen);
int write_to_buf(const char *string, size_t string_len, buf_t *buf);
int write_to_buf_compress(buf_t *buf, struct tor_compress_state_t *state,
@ -100,6 +95,28 @@ struct buf_t {
chunk_t *head; /**< First chunk in the list, or NULL for none. */
chunk_t *tail; /**< Last chunk in the list, or NULL for none. */
};
chunk_t *buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped);
/** If a read onto the end of a chunk would be smaller than this number, then
* just start a new chunk. */
#define MIN_READ_LEN 8
/** Return the number of bytes that can be written onto <b>chunk</b> without
* running out of space. */
static inline size_t
CHUNK_REMAINING_CAPACITY(const chunk_t *chunk)
{
return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen);
}
/** Return the next character in <b>chunk</b> onto which data can be appended.
* If the chunk is full, this might be off the end of chunk->mem. */
static inline char *
CHUNK_WRITE_PTR(chunk_t *chunk)
{
return chunk->data + chunk->datalen;
}
#endif
#endif

175
src/or/buffers_tls.c Normal file
View File

@ -0,0 +1,175 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define BUFFERS_PRIVATE
#include "orconfig.h"
#include <stddef.h>
#include "buffers.h"
#include "buffers_tls.h"
#include "compat.h"
#include "compress.h"
#include "util.h"
#include "torint.h"
#include "torlog.h"
#include "tortls.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/** As read_to_chunk(), but return (negative) error code on error, blocking,
* or TLS, and the number of bytes read otherwise. */
static inline int
read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
size_t at_most)
{
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;
}
/** 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.
*/
int
read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf)
{
int r = 0;
size_t total_read = 0;
check_no_tls_errors();
if (BUG(buf->datalen >= INT_MAX))
return -1;
if (BUG(buf->datalen >= INT_MAX - at_most))
return -1;
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);
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;
}
/** Helper for flush_buf_tls(): try to write <b>sz</b> bytes from chunk
* <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write
* more if there is a forced pending write size.) On success, deduct the
* bytes written from *<b>buf_flushlen</b>. Return the number of bytes
* written on success, and a TOR_TLS error code on failure or blocking.
*/
static inline int
flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
size_t sz, size_t *buf_flushlen)
{
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;
}
/** As flush_buf(), but writes data to a TLS connection. Can write more than
* <b>flushlen</b> bytes.
*/
int
flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t flushlen,
size_t *buf_flushlen)
{
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();
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);
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;
}

19
src/or/buffers_tls.h Normal file
View File

@ -0,0 +1,19 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BUFFERS_TLS_H
#define TOR_BUFFERS_TLS_H
struct buf_t;
struct tor_tls_t;
int read_to_buf_tls(struct tor_tls_t *tls, size_t at_most,
struct buf_t *buf);
int flush_buf_tls(struct tor_tls_t *tls, struct buf_t *buf, size_t sz,
size_t *buf_flushlen);
#endif

View File

@ -58,6 +58,7 @@
#include "or.h"
#include "bridges.h"
#include "buffers.h"
#include "buffers_tls.h"
/*
* Define this so we get channel internal functions, since we're implementing
* part of a subclass (channel_tls_t).

View File

@ -21,6 +21,7 @@ LIBTOR_A_SOURCES = \
src/or/addressmap.c \
src/or/bridges.c \
src/or/buffers.c \
src/or/buffers_tls.c \
src/or/channel.c \
src/or/channelpadding.c \
src/or/channeltls.c \
@ -156,6 +157,7 @@ ORHEADERS = \
src/or/addressmap.h \
src/or/bridges.h \
src/or/buffers.h \
src/or/buffers_tls.h \
src/or/channel.h \
src/or/channelpadding.h \
src/or/channeltls.h \

View File

@ -52,6 +52,7 @@
#include "backtrace.h"
#include "bridges.h"
#include "buffers.h"
#include "buffers_tls.h"
#include "channel.h"
#include "channeltls.h"
#include "channelpadding.h"

View File

@ -7,6 +7,7 @@
#define PROTO_HTTP_PRIVATE
#include "or.h"
#include "buffers.h"
#include "buffers_tls.h"
#include "ext_orport.h"
#include "proto_cell.h"
#include "proto_ext_or.h"