diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/buffers.c | 17 | ||||
-rw-r--r-- | src/or/connection.c | 39 | ||||
-rw-r--r-- | src/or/main.c | 12 | ||||
-rw-r--r-- | src/or/or.h | 5 |
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); |