diff options
author | Nick Mathewson <nickm@torproject.org> | 2009-07-31 14:51:04 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2010-09-27 12:28:43 -0400 |
commit | 4836014168067dc4ded2285a04a69ea169bb95a9 (patch) | |
tree | 7385f44899b213ebfb978ee0fd2ae2e550e05239 /src/or/buffers.c | |
parent | 051491780090c610c06882ead4b2cf17bc6c93df (diff) | |
download | tor-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.c | 92 |
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. |