aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-08-26 15:33:19 -0400
committerNick Mathewson <nickm@torproject.org>2010-09-27 14:22:11 -0400
commit0c9b64d449a725dc2f9f043d174b581e3a5d9cb2 (patch)
tree19ecfaf74f334c5881e476d5b92ade3b82970d55
parent9796b9bfa6a757780d6185547e4baf739c53cdac (diff)
downloadtor-0c9b64d449a725dc2f9f043d174b581e3a5d9cb2.tar
tor-0c9b64d449a725dc2f9f043d174b581e3a5d9cb2.tar.gz
Get zlib compression working with bufferevents.
-rw-r--r--src/or/buffers.c55
-rw-r--r--src/or/buffers.h3
-rw-r--r--src/or/connection.c18
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);