mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Move buffers into container
Split the network-only and compression-only parts of buffers into the appropriate modules.
This commit is contained in:
parent
be40ad51b6
commit
d8b34e0886
@ -25,7 +25,6 @@ endif
|
||||
|
||||
LIBOR_A_SRC = \
|
||||
src/common/address_set.c \
|
||||
src/common/buffers.c \
|
||||
src/common/compat.c \
|
||||
src/common/util.c \
|
||||
src/common/token_bucket.c \
|
||||
@ -60,7 +59,6 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
|
||||
COMMONHEADERS = \
|
||||
src/common/address_set.h \
|
||||
src/common/buffers.h \
|
||||
src/common/compat.h \
|
||||
src/common/compat_libevent.h \
|
||||
src/common/handles.h \
|
||||
|
@ -2,6 +2,7 @@ orconfig.h
|
||||
lib/arch/*.h
|
||||
lib/cc/*.h
|
||||
lib/compress/*.h
|
||||
lib/container/*.h
|
||||
lib/ctime/*.h
|
||||
lib/intmath/*.h
|
||||
lib/log/*.h
|
||||
|
@ -92,4 +92,8 @@ size_t tor_compress_state_size(const tor_compress_state_t *state);
|
||||
void tor_compress_init(void);
|
||||
void tor_compress_log_init_warnings(void);
|
||||
|
||||
struct buf_t;
|
||||
int buf_add_compress(struct buf_t *buf, struct tor_compress_state_t *state,
|
||||
const char *data, size_t data_len, int done);
|
||||
|
||||
#endif /* !defined(TOR_COMPRESS_H) */
|
||||
|
77
src/lib/compress/compress_buf.c
Normal file
77
src/lib/compress/compress_buf.c
Normal file
@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2003, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define BUFFERS_PRIVATE
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include "lib/container/buffers.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
|
||||
#ifdef PARANOIA
|
||||
/** Helper: If PARANOIA is defined, assert that the buffer in local variable
|
||||
* <b>buf</b> is well-formed. */
|
||||
#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
|
||||
#else
|
||||
#define check() STMT_NIL
|
||||
#endif /* defined(PARANOIA) */
|
||||
|
||||
/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the
|
||||
* compression state <b>state</b>, appending the result to <b>buf</b>. If
|
||||
* <b>done</b> is true, flush the data in the state and finish the
|
||||
* compression/uncompression. Return -1 on failure, 0 on success. */
|
||||
int
|
||||
buf_add_compress(buf_t *buf, tor_compress_state_t *state,
|
||||
const char *data, size_t data_len,
|
||||
const int done)
|
||||
{
|
||||
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_compress_process(state, &next, &avail,
|
||||
&data, &data_len, done)) {
|
||||
case TOR_COMPRESS_DONE:
|
||||
over = 1;
|
||||
break;
|
||||
case TOR_COMPRESS_ERROR:
|
||||
return -1;
|
||||
case TOR_COMPRESS_OK:
|
||||
if (data_len == 0) {
|
||||
tor_assert_nonfatal(!done);
|
||||
over = 1;
|
||||
}
|
||||
break;
|
||||
case TOR_COMPRESS_BUFFER_FULL:
|
||||
if (avail) {
|
||||
/* The compression module says we need more room
|
||||
* (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically,
|
||||
* whether were going to or not. */
|
||||
need_new_chunk = 1;
|
||||
}
|
||||
if (data_len == 0 && !done) {
|
||||
/* We've consumed all the input data, though, so there's no
|
||||
* point in forging ahead right now. */
|
||||
over = 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;
|
||||
}
|
@ -5,8 +5,9 @@ if UNITTESTS_ENABLED
|
||||
noinst_LIBRARIES += src/lib/libtor-compress-testing.a
|
||||
endif
|
||||
|
||||
src_lib_libtor_compress_a_SOURCES = \
|
||||
src_lib_libtor_compress_a_SOURCES = \
|
||||
src/lib/compress/compress.c \
|
||||
src/lib/compress/compress_buf.c \
|
||||
src/lib/compress/compress_lzma.c \
|
||||
src/lib/compress/compress_none.c \
|
||||
src/lib/compress/compress_zlib.c \
|
||||
|
@ -9,9 +9,10 @@ lib/smartlist_core/*.h
|
||||
lib/string/*.h
|
||||
lib/testsupport/testsupport.h
|
||||
lib/intmath/*.h
|
||||
lib/log/*.h
|
||||
|
||||
# XXXX I am unsure about this one. It's only here for buffers.c
|
||||
lib/time/*.h
|
||||
|
||||
ht.h
|
||||
siphash.h
|
||||
|
||||
# XXX I'd like to remove this.
|
||||
lib/log/util_bug.h
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
n * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
@ -21,16 +21,22 @@
|
||||
#define BUFFERS_PRIVATE
|
||||
#include "orconfig.h"
|
||||
#include <stddef.h>
|
||||
#include "common/buffers.h"
|
||||
#include "common/compat.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "common/util.h"
|
||||
#include "lib/container/buffers.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/log/torlog.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
#include "lib/ctime/di_ops.h"
|
||||
#include "lib/malloc/util_malloc.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "lib/time/compat_time.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define PARANOIA
|
||||
|
||||
#ifdef PARANOIA
|
||||
@ -506,177 +512,6 @@ buf_get_total_allocation(void)
|
||||
return total_bytes_allocated_in_chunks;
|
||||
}
|
||||
|
||||
/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into
|
||||
* <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set
|
||||
* *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking,
|
||||
* and the number of bytes read otherwise. */
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
* error; else return the number of bytes read.
|
||||
*/
|
||||
/* XXXX indicate "read blocked" somehow? */
|
||||
int
|
||||
buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
|
||||
int *reached_eof,
|
||||
int *socket_error)
|
||||
{
|
||||
/* XXXX 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));
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
/** Helper for buf_flush_to_socket(): 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
|
||||
* written on success, 0 on blocking, -1 on failure.
|
||||
*/
|
||||
static inline int
|
||||
flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz,
|
||||
size_t *buf_flushlen)
|
||||
{
|
||||
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_drain(buf, write_result);
|
||||
tor_assert(write_result < INT_MAX);
|
||||
return (int)write_result;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
* from the buffer. Return the number of bytes written on success,
|
||||
* -1 on failure. Return 0 if write() would block.
|
||||
*/
|
||||
int
|
||||
buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
|
||||
size_t *buf_flushlen)
|
||||
{
|
||||
/* XXXX 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));
|
||||
if (BUG(*buf_flushlen > buf->datalen)) {
|
||||
*buf_flushlen = buf->datalen;
|
||||
}
|
||||
if (BUG(sz > *buf_flushlen)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/** Append <b>string_len</b> bytes from <b>string</b> to the end of
|
||||
* <b>buf</b>.
|
||||
*
|
||||
@ -1037,65 +872,6 @@ buf_get_line(buf_t *buf, char *data_out, size_t *data_len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the
|
||||
* compression state <b>state</b>, appending the result to <b>buf</b>. If
|
||||
* <b>done</b> is true, flush the data in the state and finish the
|
||||
* compression/uncompression. Return -1 on failure, 0 on success. */
|
||||
int
|
||||
buf_add_compress(buf_t *buf, tor_compress_state_t *state,
|
||||
const char *data, size_t data_len,
|
||||
const int done)
|
||||
{
|
||||
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_compress_process(state, &next, &avail,
|
||||
&data, &data_len, done)) {
|
||||
case TOR_COMPRESS_DONE:
|
||||
over = 1;
|
||||
break;
|
||||
case TOR_COMPRESS_ERROR:
|
||||
return -1;
|
||||
case TOR_COMPRESS_OK:
|
||||
if (data_len == 0) {
|
||||
tor_assert_nonfatal(!done);
|
||||
over = 1;
|
||||
}
|
||||
break;
|
||||
case TOR_COMPRESS_BUFFER_FULL:
|
||||
if (avail) {
|
||||
/* The compression module says we need more room
|
||||
* (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically,
|
||||
* whether were going to or not. */
|
||||
need_new_chunk = 1;
|
||||
}
|
||||
if (data_len == 0 && !done) {
|
||||
/* We've consumed all the input data, though, so there's no
|
||||
* point in forging ahead right now. */
|
||||
over = 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;
|
||||
}
|
||||
|
||||
/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
|
||||
int
|
||||
buf_set_to_copy(buf_t **output,
|
||||
@ -1143,4 +919,3 @@ buf_assert_ok(buf_t *buf)
|
||||
tor_assert(buf->datalen == total);
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
#ifndef TOR_BUFFERS_H
|
||||
#define TOR_BUFFERS_H
|
||||
|
||||
#include "common/compat.h"
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/testsupport/testsupport.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct buf_t buf_t;
|
||||
|
||||
struct tor_compress_state_t;
|
||||
@ -35,21 +37,12 @@ size_t buf_slack(const buf_t *buf);
|
||||
uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now);
|
||||
size_t buf_get_total_allocation(void);
|
||||
|
||||
int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
|
||||
int *reached_eof,
|
||||
int *socket_error);
|
||||
|
||||
int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
|
||||
size_t *buf_flushlen);
|
||||
|
||||
int buf_add(buf_t *buf, const char *string, size_t string_len);
|
||||
void buf_add_string(buf_t *buf, const char *string);
|
||||
void buf_add_printf(buf_t *buf, const char *format, ...)
|
||||
CHECK_PRINTF(2, 3);
|
||||
void buf_add_vprintf(buf_t *buf, const char *format, va_list args)
|
||||
CHECK_PRINTF(2, 0);
|
||||
int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state,
|
||||
const char *data, size_t data_len, int done);
|
||||
int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
|
||||
void buf_move_all(buf_t *buf_out, buf_t *buf_in);
|
||||
void buf_peek(const buf_t *buf, char *string, size_t string_len);
|
||||
@ -128,4 +121,3 @@ CHUNK_WRITE_PTR(chunk_t *chunk)
|
||||
#endif /* defined(BUFFERS_PRIVATE) */
|
||||
|
||||
#endif /* !defined(TOR_BUFFERS_H) */
|
||||
|
@ -7,6 +7,7 @@ endif
|
||||
|
||||
src_lib_libtor_container_a_SOURCES = \
|
||||
src/lib/container/bloomfilt.c \
|
||||
src/lib/container/buffers.c \
|
||||
src/lib/container/map.c \
|
||||
src/lib/container/order.c \
|
||||
src/lib/container/smartlist.c
|
||||
@ -19,6 +20,7 @@ src_lib_libtor_container_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
noinst_HEADERS += \
|
||||
src/lib/container/bitarray.h \
|
||||
src/lib/container/bloomfilt.h \
|
||||
src/lib/container/buffers.h \
|
||||
src/lib/container/map.h \
|
||||
src/lib/container/order.h \
|
||||
src/lib/container/smartlist.h
|
||||
|
192
src/lib/net/buffers_net.c
Normal file
192
src/lib/net/buffers_net.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define BUFFERS_PRIVATE
|
||||
#include "lib/net/buffers_net.h"
|
||||
#include "lib/container/buffers.h"
|
||||
#include "lib/log/torlog.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef PARANOIA
|
||||
/** Helper: If PARANOIA is defined, assert that the buffer in local variable
|
||||
* <b>buf</b> is well-formed. */
|
||||
#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
|
||||
#else
|
||||
#define check() STMT_NIL
|
||||
#endif /* defined(PARANOIA) */
|
||||
|
||||
/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into
|
||||
* <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set
|
||||
* *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking,
|
||||
* and the number of bytes read otherwise. */
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
* error; else return the number of bytes read.
|
||||
*/
|
||||
/* XXXX indicate "read blocked" somehow? */
|
||||
int
|
||||
buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
|
||||
int *reached_eof,
|
||||
int *socket_error)
|
||||
{
|
||||
/* XXXX 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));
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
/** Helper for buf_flush_to_socket(): 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
|
||||
* written on success, 0 on blocking, -1 on failure.
|
||||
*/
|
||||
static inline int
|
||||
flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz,
|
||||
size_t *buf_flushlen)
|
||||
{
|
||||
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_drain(buf, write_result);
|
||||
tor_assert(write_result < INT_MAX);
|
||||
return (int)write_result;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
* from the buffer. Return the number of bytes written on success,
|
||||
* -1 on failure. Return 0 if write() would block.
|
||||
*/
|
||||
int
|
||||
buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
|
||||
size_t *buf_flushlen)
|
||||
{
|
||||
/* XXXX 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));
|
||||
if (BUG(*buf_flushlen > buf->datalen)) {
|
||||
*buf_flushlen = buf->datalen;
|
||||
}
|
||||
if (BUG(sz > *buf_flushlen)) {
|
||||
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;
|
||||
}
|
26
src/lib/net/buffers_net.h
Normal file
26
src/lib/net/buffers_net.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file buffers.h
|
||||
* \brief Header file for buffers.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_BUFFERS_NET_H
|
||||
#define TOR_BUFFERS_NET_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "lib/net/socket.h"
|
||||
|
||||
struct buf_t;
|
||||
int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most,
|
||||
int *reached_eof,
|
||||
int *socket_error);
|
||||
|
||||
int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz,
|
||||
size_t *buf_flushlen);
|
||||
|
||||
#endif /* !defined(TOR_BUFFERS_H) */
|
@ -8,6 +8,7 @@ endif
|
||||
src_lib_libtor_net_a_SOURCES = \
|
||||
src/lib/net/address.c \
|
||||
src/lib/net/alertsock.c \
|
||||
src/lib/net/buffers_net.c \
|
||||
src/lib/net/gethostname.c \
|
||||
src/lib/net/ipv4.c \
|
||||
src/lib/net/ipv6.c \
|
||||
@ -22,6 +23,7 @@ src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
noinst_HEADERS += \
|
||||
src/lib/net/address.h \
|
||||
src/lib/net/alertsock.h \
|
||||
src/lib/net/buffers_net.h \
|
||||
src/lib/net/gethostname.h \
|
||||
src/lib/net/ipv4.h \
|
||||
src/lib/net/ipv6.h \
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define BUFFERS_PRIVATE
|
||||
#include "orconfig.h"
|
||||
#include <stddef.h>
|
||||
#include "common/buffers.h"
|
||||
#include "lib/container/buffers.h"
|
||||
#include "lib/tls/buffers_tls.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/log/torlog.h"
|
||||
|
@ -103,6 +103,7 @@
|
||||
#include "or/transports.h"
|
||||
#include "or/routerparse.h"
|
||||
#include "lib/sandbox/sandbox.h"
|
||||
#include "lib/net/buffers_net.h"
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
@ -5315,4 +5316,3 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted,
|
||||
tor_free(warn);
|
||||
tor_free(ext_source);
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@
|
||||
#include "lib/memarea/memarea.h"
|
||||
#include "lib/sandbox/sandbox.h"
|
||||
#include "lib/fs/lockfile.h"
|
||||
#include "lib/net/buffers_net.h"
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user