]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Get zlib compression working with bufferevents.
authorNick Mathewson <nickm@torproject.org>
Wed, 26 Aug 2009 19:33:19 +0000 (15:33 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 27 Sep 2010 18:22:11 +0000 (14:22 -0400)
src/or/buffers.c
src/or/buffers.h
src/or/connection.c

index b9e1c5347762480132513fa9facda37b94e2c18f..eaa7427848efa01733f7b3a3ede7ff82ee1f09bb 100644 (file)
@@ -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
index 64e1f55c582d784d05ceb849472515200fb3406d..35c1dd2ea595091073b42e0f377e6a5b390a71a3 100644 (file)
@@ -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);
index e688f4c8bbb4b62862fc3f0d98be5dc172cb65bf..b5496d72d5256b588d934e23f935cd4832ba958f 100644 (file)
@@ -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);