commit d8b34e0886c9fd08fb51e0de4fadca7da82056ff
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Jun 28 16:25:06 2018 -0400
Move buffers into container
Split the network-only and compression-only parts of buffers into
the appropriate modules.
---
src/common/include.am | 2 -
src/lib/compress/.may_include | 1 +
src/lib/compress/compress.h | 4 +
src/lib/compress/compress_buf.c | 77 ++++++++++
src/lib/compress/include.am | 3 +-
src/lib/container/.may_include | 7 +-
src/{common => lib/container}/buffers.c | 247 ++------------------------------
src/{common => lib/container}/buffers.h | 14 +-
src/lib/container/include.am | 2 +
src/lib/net/buffers_net.c | 192 +++++++++++++++++++++++++
src/lib/net/buffers_net.h | 26 ++++
src/lib/net/include.am | 2 +
src/lib/tls/buffers_tls.c | 2 +-
src/or/connection.c | 2 +-
src/or/main.c | 1 +
15 files changed, 327 insertions(+), 255 deletions(-)
diff --git a/src/common/include.am b/src/common/include.am
index bb1a3ee42..e68a87b10 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -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 \
diff --git a/src/lib/compress/.may_include b/src/lib/compress/.may_include
index 036177469..68fe9f1c5 100644
--- a/src/lib/compress/.may_include
+++ b/src/lib/compress/.may_include
@@ -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
diff --git a/src/lib/compress/compress.h b/src/lib/compress/compress.h
index f88cf2cb2..ae98e1aae 100644
--- a/src/lib/compress/compress.h
+++ b/src/lib/compress/compress.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) */
diff --git a/src/lib/compress/compress_buf.c b/src/lib/compress/compress_buf.c
new file mode 100644
index 000000000..4b8877238
--- /dev/null
+++ b/src/lib/compress/compress_buf.c
@@ -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;
+}
diff --git a/src/lib/compress/include.am b/src/lib/compress/include.am
index eb3a89c35..75c9032bd 100644
--- a/src/lib/compress/include.am
+++ b/src/lib/compress/include.am
@@ -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 \
diff --git a/src/lib/container/.may_include b/src/lib/container/.may_include
index 2eecb503c..90de5eda4 100644
--- a/src/lib/container/.may_include
+++ b/src/lib/container/.may_include
@@ -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
diff --git a/src/common/buffers.c b/src/lib/container/buffers.c
similarity index 77%
rename from src/common/buffers.c
rename to src/lib/container/buffers.c
index 4e5f56c73..ee1a73e8f 100644
--- a/src/common/buffers.c
+++ b/src/lib/container/buffers.c
@@ -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);
}
}
-
diff --git a/src/common/buffers.h b/src/lib/container/buffers.h
similarity index 90%
rename from src/common/buffers.h
rename to src/lib/container/buffers.h
index 80103af77..8b16fb298 100644
--- a/src/common/buffers.h
+++ b/src/lib/container/buffers.h
@@ -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) */
-
diff --git a/src/lib/container/include.am b/src/lib/container/include.am
index 0e7acdff9..e91ad7d1c 100644
--- a/src/lib/container/include.am
+++ b/src/lib/container/include.am
@@ -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
diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c
new file mode 100644
index 000000000..01be30f5a
--- /dev/null
+++ b/src/lib/net/buffers_net.c
@@ -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;
+}
diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h
new file mode 100644
index 000000000..d03b61376
--- /dev/null
+++ b/src/lib/net/buffers_net.h
@@ -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) */
diff --git a/src/lib/net/include.am b/src/lib/net/include.am
index 6f34479db..a375ac8ad 100644
--- a/src/lib/net/include.am
+++ b/src/lib/net/include.am
@@ -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 \
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index 0f9dd7a4d..243e0eb0b 100644
--- a/src/lib/tls/buffers_tls.c
+++ b/src/lib/tls/buffers_tls.c
@@ -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"
diff --git a/src/or/connection.c b/src/or/connection.c
index 01067e94f..974281331 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -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);
}
-
diff --git a/src/or/main.c b/src/or/main.c
index 0ba38658a..67ebc980c 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -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>