mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Move the tls parts of buffers.c into buffers_tls.c
This commit is contained in:
parent
5921b465e7
commit
150089cbd7
181
src/or/buffers.c
181
src/or/buffers.c
@ -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>.
|
||||
*
|
||||
|
@ -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
175
src/or/buffers_tls.c
Normal 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
19
src/or/buffers_tls.h
Normal 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
|
||||
|
@ -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).
|
||||
|
@ -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 \
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user