aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/buffers.c17
-rw-r--r--src/or/connection.c39
-rw-r--r--src/or/main.c12
-rw-r--r--src/or/or.h5
4 files changed, 53 insertions, 20 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 30212e33d5..68f51e7eb6 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -576,21 +576,19 @@ flush_buf_impl(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
return 0;
} else {
*buf_flushlen -= write_result;
-
buf_remove_from_front(buf, write_result);
-
return write_result;
}
}
/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
- * *<b>buf_flushlen</b> bytes, decrement *<b>buf_flushlen</b> by
+ * <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
-flush_buf(int s, buf_t *buf, size_t *buf_flushlen)
+flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
int r;
size_t flushed = 0;
@@ -600,11 +598,12 @@ flush_buf(int s, buf_t *buf, size_t *buf_flushlen)
tor_assert(buf_flushlen);
tor_assert(s>=0);
tor_assert(*buf_flushlen <= buf->datalen);
+ tor_assert(sz <= *buf_flushlen);
- if (*buf_flushlen == 0) /* nothing to flush */
+ if (sz == 0) /* nothing to flush */
return 0;
- flushlen0 = *buf_flushlen;
+ flushlen0 = sz;
_split_range(buf, buf->cur, &flushlen0, &flushlen1);
r = flush_buf_impl(s, buf, flushlen0, buf_flushlen);
@@ -653,7 +652,7 @@ flush_buf_tls_impl(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen)
/** As flush_buf(), but writes data to a TLS connection.
*/
int
-flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen)
+flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
int r;
size_t flushed=0;
@@ -661,12 +660,14 @@ flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen)
assert_buf_ok(buf);
tor_assert(tls);
tor_assert(buf_flushlen);
+ tor_assert(*buf_flushlen <= buf->datalen);
+ tor_assert(sz <= *buf_flushlen);
/* we want to let tls write even if flushlen is zero, because it might
* have a partial record pending */
check_no_tls_errors();
- flushlen0 = *buf_flushlen;
+ flushlen0 = sz;
_split_range(buf, buf->cur, &flushlen0, &flushlen1);
r = flush_buf_tls_impl(tls, buf, flushlen0, buf_flushlen);
diff --git a/src/or/connection.c b/src/or/connection.c
index 893a9c7609..0e68b3ee12 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -23,7 +23,6 @@ static int connection_finished_connecting(connection_t *conn);
static int connection_reached_eof(connection_t *conn);
static int connection_read_to_buf(connection_t *conn, int *max_to_read);
static int connection_process_inbuf(connection_t *conn, int package_partial);
-static int connection_bucket_read_limit(connection_t *conn);
static void client_check_address_changed(int sock);
static uint32_t last_interface_ip = 0;
@@ -983,6 +982,29 @@ connection_bucket_read_limit(connection_t *conn)
return at_most;
}
+/** How many bytes at most can we write onto this connection? */
+int
+connection_bucket_write_limit(connection_t *conn)
+{
+ int at_most;
+
+ /* do a rudimentary round-robin so one circuit can't hog a connection */
+ if (connection_speaks_cells(conn)) {
+ at_most = 32*(CELL_NETWORK_SIZE);
+ } else {
+ at_most = 32*(RELAY_PAYLOAD_SIZE);
+ }
+
+ if (at_most > conn->outbuf_flushlen)
+ at_most = conn->outbuf_flushlen;
+
+#if 0 /* don't enable til we actually do write limiting */
+ if (at_most > global_write_bucket)
+ at_most = global_write_bucket;
+#endif
+ return at_most;
+}
+
/** We just read num_read onto conn. Decrement buckets appropriately. */
static void
connection_read_bucket_decrement(connection_t *conn, int num_read)
@@ -1317,6 +1339,7 @@ connection_handle_write(connection_t *conn)
int e;
socklen_t len=sizeof(e);
int result;
+ int max_to_write;
time_t now = time(NULL);
tor_assert(!connection_is_listener(conn));
@@ -1359,6 +1382,8 @@ connection_handle_write(connection_t *conn)
return -1;
}
+ max_to_write = connection_bucket_write_limit(conn);
+
if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_READING) {
if (conn->state == OR_CONN_STATE_HANDSHAKING) {
connection_stop_writing(conn);
@@ -1371,7 +1396,8 @@ connection_handle_write(connection_t *conn)
}
/* else open, or closing */
- result = flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
+ result = flush_buf_tls(conn->tls, conn->outbuf,
+ max_to_write, &conn->outbuf_flushlen);
switch (result) {
case TOR_TLS_ERROR:
case TOR_TLS_CLOSE:
@@ -1403,7 +1429,8 @@ connection_handle_write(connection_t *conn)
}
} else {
CONN_LOG_PROTECT(conn,
- result = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen));
+ result = flush_buf(conn->s, conn->outbuf,
+ max_to_write, &conn->outbuf_flushlen));
if (result < 0) {
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(conn, conn->cpath_layer);
@@ -1429,7 +1456,8 @@ connection_handle_write(connection_t *conn)
return 0;
}
-/* DOCDOC */
+/* A controller event has just happened with such urgency that we
+ * need to write it onto controller <b>conn</b> immediately. */
void
_connection_controller_force_write(connection_t *conn)
{
@@ -1445,7 +1473,8 @@ _connection_controller_force_write(connection_t *conn)
return;
CONN_LOG_PROTECT(conn,
- result = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen));
+ result = flush_buf(conn->s, conn->outbuf,
+ conn->outbuf_flushlen, &conn->outbuf_flushlen));
if (result < 0) {
connection_close_immediate(conn); /* Don't flush; connection is dead. */
connection_mark_for_close(conn);
diff --git a/src/or/main.c b/src/or/main.c
index 7e155d145f..525a81c57e 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -439,8 +439,9 @@ conn_close_if_marked(int i)
debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
if (conn->s >= 0 && connection_wants_to_flush(conn)) {
- /* -1 means it's an incomplete edge connection, or that the socket
+ /* s == -1 means it's an incomplete edge connection, or that the socket
* has already been closed as unflushable. */
+ int sz = connection_bucket_write_limit(conn);
if (!conn->hold_open_until_flushed)
info(LD_NET,
"Conn (addr %s, fd %d, type %s, state %d) marked, but wants to flush %d bytes. "
@@ -449,14 +450,15 @@ conn_close_if_marked(int i)
(int)conn->outbuf_flushlen, conn->marked_for_close_file, conn->marked_for_close);
if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN) {
- retval = flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
+ retval = flush_buf_tls(conn->tls, conn->outbuf, sz, &conn->outbuf_flushlen);
} else
retval = -1; /* never flush non-open broken tls connections */
} else {
- retval = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
+ retval = flush_buf(conn->s, conn->outbuf, sz, &conn->outbuf_flushlen);
}
- if (retval >= 0 &&
- conn->hold_open_until_flushed && connection_wants_to_flush(conn)) {
+ if (retval >= 0 && /* Technically, we could survive things like
+ TLS_WANT_WRITE here. But don't bother for now. */
+ conn->hold_open_until_flushed && connection_wants_to_flush(conn)) {
LOG_FN_CONN(conn,
(LOG_INFO,LD_NET,"Holding conn (fd %d) open for more flushing.",conn->s));
/* XXX should we reset timestamp_lastwritten here? */
diff --git a/src/or/or.h b/src/or/or.h
index 7bf8a5bad4..535bfc2600 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1363,8 +1363,8 @@ const char *_buf_peek_raw_buffer(const buf_t *buf);
int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof);
int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf);
-int flush_buf(int s, buf_t *buf, size_t *buf_flushlen);
-int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen);
+int flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen);
+int flush_buf_tls(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 fetch_from_buf(char *string, size_t string_len, buf_t *buf);
@@ -1541,6 +1541,7 @@ int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_
int retry_all_listeners(int force, smartlist_t *replaced_conns,
smartlist_t *new_conns);
+int connection_bucket_write_limit(connection_t *conn);
void connection_bucket_init(void);
void connection_bucket_refill(struct timeval *now);