aboutsummaryrefslogtreecommitdiff
path: root/src/lib/net/buffers_net.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-12-17 16:41:01 -0500
committerNick Mathewson <nickm@torproject.org>2018-12-17 16:41:01 -0500
commite969d9c6b4b82178fbc840e3d53e12cbb64fee5c (patch)
tree5be34da1967f5358ed84c816c86a4bce7d656a0e /src/lib/net/buffers_net.c
parent5a22b42c3a01ad8d99e977cfd9efa760438129e9 (diff)
parentc8b8b15f0eb2651dea694a057e70e6b8c34dbe05 (diff)
downloadtor-e969d9c6b4b82178fbc840e3d53e12cbb64fee5c.tar.gz
tor-e969d9c6b4b82178fbc840e3d53e12cbb64fee5c.zip
Merge branch 'ticket28179_squashed' into ticket28179_squashed_merged
Diffstat (limited to 'src/lib/net/buffers_net.c')
-rw-r--r--src/lib/net/buffers_net.c131
1 files changed, 100 insertions, 31 deletions
diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c
index b0936e9928..576dc56a52 100644
--- a/src/lib/net/buffers_net.c
+++ b/src/lib/net/buffers_net.c
@@ -21,6 +21,7 @@
#endif
#include <stdlib.h>
+#include <unistd.h>
#ifdef PARANOIA
/** Helper: If PARANOIA is defined, assert that the buffer in local variable
@@ -30,27 +31,36 @@
#define check() STMT_NIL
#endif /* defined(PARANOIA) */
-/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into
+/** Read up to <b>at_most</b> bytes from the file descriptor <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. */
+ * *<b>reached_eof</b> to 1. Uses <b>tor_socket_recv()</b> iff <b>is_socket</b>
+ * is true, otherwise it uses <b>read()</b>. Return -1 on error (and sets
+ * *<b>error</b> to errno), 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)
+ int *reached_eof, int *error, bool is_socket)
{
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 (is_socket)
+ read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0);
+ else
+ read_result = read(fd, CHUNK_WRITE_PTR(chunk), at_most);
if (read_result < 0) {
- int e = tor_socket_errno(fd);
+ int e = is_socket ? tor_socket_errno(fd) : errno;
+
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?");
+ log_warn(LD_NET, "%s() failed: WSAENOBUFS. Not enough ram?",
+ is_socket ? "recv" : "read");
#endif
- *socket_error = e;
+ if (error)
+ *error = e;
return -1;
}
return 0; /* would block. */
@@ -68,16 +78,17 @@ read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most,
}
}
-/** 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.
+/** Read from file descriptor <b>fd</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)
+static int
+buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
+ int *reached_eof,
+ int *socket_error,
+ bool is_socket)
{
/* XXXX It's stupid to overload the return values for these functions:
* "error status" and "number of bytes read" are not mutually exclusive.
@@ -87,7 +98,7 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
check();
tor_assert(reached_eof);
- tor_assert(SOCKET_OK(s));
+ tor_assert(SOCKET_OK(fd));
if (BUG(buf->datalen >= INT_MAX))
return -1;
@@ -108,7 +119,8 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
readlen = cap;
}
- r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error);
+ r = read_to_chunk(buf, chunk, fd, readlen,
+ reached_eof, socket_error, is_socket);
check();
if (r < 0)
return r; /* Error */
@@ -122,22 +134,27 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
}
/** 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.
+ * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</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)
+flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
+ size_t *buf_flushlen, bool is_socket)
{
ssize_t write_result;
if (sz > chunk->datalen)
sz = chunk->datalen;
- write_result = tor_socket_send(s, chunk->data, sz, 0);
+
+ if (is_socket)
+ write_result = tor_socket_send(fd, chunk->data, sz, 0);
+ else
+ write_result = write(fd, chunk->data, sz);
if (write_result < 0) {
- int e = tor_socket_errno(s);
+ int e = is_socket ? tor_socket_errno(fd) : errno;
+
if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
#ifdef _WIN32
if (e == WSAENOBUFS)
@@ -155,15 +172,15 @@ flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz,
}
}
-/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
+/** Write data from <b>buf</b> to the file descriptor <b>fd</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)
+static int
+buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
+ size_t *buf_flushlen, bool is_socket)
{
/* XXXX It's stupid to overload the return values for these functions:
* "error status" and "number of bytes flushed" are not mutually exclusive.
@@ -171,7 +188,7 @@ buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
int r;
size_t flushed = 0;
tor_assert(buf_flushlen);
- tor_assert(SOCKET_OK(s));
+ tor_assert(SOCKET_OK(fd));
if (BUG(*buf_flushlen > buf->datalen)) {
*buf_flushlen = buf->datalen;
}
@@ -188,7 +205,7 @@ buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
else
flushlen0 = buf->head->datalen;
- r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen);
+ r = flush_chunk(fd, buf, buf->head, flushlen0, buf_flushlen, is_socket);
check();
if (r < 0)
return r;
@@ -200,3 +217,55 @@ buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
tor_assert(flushed < INT_MAX);
return (int)flushed;
}
+
+/** 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)
+{
+ return buf_flush_to_fd(buf, s, sz, buf_flushlen, true);
+}
+
+/** 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.
+ */
+int
+buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
+ int *reached_eof,
+ int *socket_error)
+{
+ return buf_read_from_fd(buf, s, at_most, reached_eof, socket_error, true);
+}
+
+/** Write data from <b>buf</b> to the pipe <b>fd</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_pipe(buf_t *buf, int fd, size_t sz,
+ size_t *buf_flushlen)
+{
+ return buf_flush_to_fd(buf, fd, sz, buf_flushlen, false);
+}
+
+/** Read from pipe <b>fd</b>, writing onto end of <b>buf</b>. Read at most
+ * <b>at_most</b> bytes, growing the buffer as necessary. If read() 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.
+ */
+int
+buf_read_from_pipe(buf_t *buf, int fd, size_t at_most,
+ int *reached_eof,
+ int *socket_error)
+{
+ return buf_read_from_fd(buf, fd, at_most, reached_eof, socket_error, false);
+}