aboutsummaryrefslogtreecommitdiff
path: root/src/or/buffers.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-07-31 14:51:04 -0400
committerNick Mathewson <nickm@torproject.org>2010-09-27 12:28:43 -0400
commit4836014168067dc4ded2285a04a69ea169bb95a9 (patch)
tree7385f44899b213ebfb978ee0fd2ae2e550e05239 /src/or/buffers.c
parent051491780090c610c06882ead4b2cf17bc6c93df (diff)
downloadtor-4836014168067dc4ded2285a04a69ea169bb95a9.tar
tor-4836014168067dc4ded2285a04a69ea169bb95a9.tar.gz
Clone fetch_var_cell_from_buf() for evbuffers.
Diffstat (limited to 'src/or/buffers.c')
-rw-r--r--src/or/buffers.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 5a34bd2bd..c038ba11e 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1008,6 +1008,98 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
return 1;
}
+#ifdef USE_BUFFEREVENTS
+static size_t
+inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out)
+{
+ int n_vecs, i;
+
+ if (evbuffer_get_length(buf) < n)
+ n = evbuffer_get_length(buf);
+ if (n == 0)
+ return 0;
+ n_vecs = evbuffer_peek(buf, n, NULL, NULL, 0);
+ if (n_vecs <= 0)
+ return -1;
+ if (n_vecs == 1) {
+ struct evbuffer_iovec v;
+ i = evbuffer_peek(buf, n, NULL, &v, 1);
+ tor_assert(i == 1);
+ *data = v.iov_base;
+ *free_out = 0;
+ return v.iov_len;
+ } else {
+ struct evbuffer_iovec *vecs =
+ tor_malloc(sizeof(struct evbuffer_iovec)*n_vecs);
+ size_t copied = 0;
+ i = evbuffer_peek(buf, n, NULL, vecs, n_vecs);
+ tor_assert(i == n_vecs);
+ *data = tor_malloc(n);
+ for (i=0; i < n_vecs; ++i) {
+ size_t copy = n - copied;
+ if (copy > vecs[i].iov_len)
+ copy = vecs[i].iov_len;
+ tor_assert(copied+copy <= n);
+ memcpy(data+copied, vecs[i].iov_base, copy);
+ copied += copy;
+ }
+ *free_out = 0;
+ return copied;
+ }
+}
+
+/** As fetch_var_cell_from_buf, buf works on an evbuffer. */
+int
+fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
+ int linkproto)
+{
+ char *hdr = NULL;
+ int free_hdr = 0;
+ size_t n;
+ size_t buf_len;
+ uint8_t command;
+ uint16_t cell_length;
+ var_cell_t *cell;
+ int result;
+ if (linkproto == 1)
+ return 0;
+
+ *out = NULL;
+ buf_len = evbuffer_get_length(buf);
+ if (buf_len < VAR_CELL_HEADER_SIZE) {
+ result = 0;
+ goto done;
+ }
+ n = inspect_evbuffer(buf, &hdr, VAR_CELL_HEADER_SIZE, &free_hdr);
+ tor_assert(n == VAR_CELL_HEADER_SIZE);
+
+ command = get_uint8(hdr+2);
+ if (!(CELL_COMMAND_IS_VAR_LENGTH(command))) {
+ result = 0;
+ goto done;
+ }
+
+ cell_length = ntohs(get_uint16(hdr+3));
+ if (buf_len < (size_t)(VAR_CELL_HEADER_SIZE+cell_length)) {
+ result = 1; /* Not all here yet. */
+ goto done;
+ }
+
+ cell = var_cell_new(cell_length);
+ cell->command = command;
+ cell->circ_id = ntohs(get_uint16(hdr));
+ evbuffer_drain(buf, VAR_CELL_HEADER_SIZE);
+ evbuffer_remove(buf, cell->payload, cell_length);
+ *out = cell;
+ result = 1;
+
+ done:
+ if (free_hdr && hdr)
+ tor_free(hdr);
+ return result;
+}
+#endif
+
/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
* <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
* Return the number of bytes actually copied.