diff options
author | Nick Mathewson <nickm@torproject.org> | 2009-08-26 15:33:19 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2010-09-27 14:22:11 -0400 |
commit | 0c9b64d449a725dc2f9f043d174b581e3a5d9cb2 (patch) | |
tree | 19ecfaf74f334c5881e476d5b92ade3b82970d55 | |
parent | 9796b9bfa6a757780d6185547e4baf739c53cdac (diff) | |
download | tor-0c9b64d449a725dc2f9f043d174b581e3a5d9cb2.tar tor-0c9b64d449a725dc2f9f043d174b581e3a5d9cb2.tar.gz |
Get zlib compression working with bufferevents.
-rw-r--r-- | src/or/buffers.c | 55 | ||||
-rw-r--r-- | src/or/buffers.h | 3 | ||||
-rw-r--r-- | src/or/connection.c | 18 |
3 files changed, 71 insertions, 5 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index b9e1c5347..eaa742784 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -2190,6 +2190,61 @@ write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state, return 0; } +#ifdef USE_BUFFEREVENTS +int +write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, + int done) +{ + char *next; + size_t old_avail, avail; + int over = 0, n; + struct evbuffer_iovec vec[1]; + do { + int need_new_chunk = 0; + { + size_t cap = data_len / 4; + if (cap < 128) + cap = 128; + /* XXXX NM this strategy is fragmentation-prone. We should really have + * two iovecs, and write first into the one, and then into the + * second if the first gets full. */ + n = evbuffer_reserve_space(buf, cap, vec, 1); + tor_assert(n == 1); + } + + next = vec[0].iov_base; + avail = old_avail = vec[0].iov_len; + + switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) { + case TOR_ZLIB_DONE: + over = 1; + break; + case TOR_ZLIB_ERR: + return -1; + case TOR_ZLIB_OK: + if (data_len == 0) + over = 1; + break; + case TOR_ZLIB_BUF_FULL: + if (avail) { + /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk + * automatically, whether were going to or not. */ + need_new_chunk = 1; + } + break; + } + + /* XXXX possible infinite loop on BUF_FULL. */ + vec[0].iov_len = old_avail - avail; + evbuffer_commit_space(buf, vec, 1); + + } while (!over); + check(); + return 0; +} +#endif + /** Log an error and exit if <b>buf</b> is corrupted. */ void diff --git a/src/or/buffers.h b/src/or/buffers.h index 64e1f55c5..35c1dd2ea 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -60,6 +60,9 @@ int fetch_from_evbuffer_http(struct evbuffer *buf, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete); int peek_evbuffer_has_control0_command(struct evbuffer *buf); +int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, + int done); #endif void assert_buf_ok(buf_t *buf); diff --git a/src/or/connection.c b/src/or/connection.c index e688f4c8b..b5496d72d 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -3088,11 +3088,19 @@ _connection_write_to_buf_impl(const char *string, size_t len, return; IF_HAS_BUFFEREVENT(conn, { - if (bufferevent_write(conn->bufev, string, len)<0) { - /* XXXX mark for close? */ - log_warn(LD_NET, "bufferevent_write failed! That shouldn't happen."); - } - return; + if (zlib) { + int done = zlib < 0; + r = write_to_evbuffer_zlib(bufferevent_get_output(conn->bufev), + TO_DIR_CONN(conn)->zlib_state, + string, len, done); + } else { + r = bufferevent_write(conn->bufev, string, len); + } + if (r < 0) { + /* XXXX mark for close? */ + log_warn(LD_NET, "bufferevent_write failed! That shouldn't happen."); + } + return; }); old_datalen = buf_datalen(conn->outbuf); |