mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-12 22:10:12 -04:00
Replace reserve/commit with new iovec-based interface. Add a new evbuffer_peek.
svn:r1296
This commit is contained in:
parent
ed1bbc7a9f
commit
23243b8a98
179
buffer.c
179
buffer.c
@ -134,7 +134,6 @@ static int use_mmap = 1;
|
|||||||
#define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
|
#define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
|
||||||
0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
|
0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
|
||||||
|
|
||||||
|
|
||||||
#define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
|
#define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
|
||||||
#define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
|
#define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
|
||||||
|
|
||||||
@ -463,55 +462,87 @@ evbuffer_get_contiguous_space(const struct evbuffer *buf)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *
|
int
|
||||||
evbuffer_reserve_space(struct evbuffer *buf, size_t size)
|
evbuffer_reserve_space(struct evbuffer *buf, ssize_t size,
|
||||||
|
struct evbuffer_iovec *vec, int n_vecs)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain;
|
||||||
unsigned char *result = NULL;
|
int n = -1;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf, EVTHREAD_WRITE);
|
|
||||||
|
|
||||||
|
EVBUFFER_LOCK(buf, EVTHREAD_WRITE);
|
||||||
if (buf->freeze_end)
|
if (buf->freeze_end)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (n_vecs < 1)
|
||||||
|
goto done;
|
||||||
|
if (n_vecs == 1) {
|
||||||
|
if (evbuffer_expand(buf, size) == -1)
|
||||||
|
goto done;
|
||||||
|
chain = buf->last;
|
||||||
|
|
||||||
if (evbuffer_expand(buf, size) == -1)
|
vec[0].iov_base = CHAIN_SPACE_PTR(chain);
|
||||||
goto done;
|
vec[0].iov_len = CHAIN_SPACE_LEN(chain);
|
||||||
|
n = 1;
|
||||||
chain = buf->last;
|
} else {
|
||||||
|
if (_evbuffer_expand_fast(buf, size)<0)
|
||||||
result = (chain->buffer + chain->misalign + chain->off);
|
goto done;
|
||||||
|
n = _evbuffer_read_setup_vecs(buf, size, vec, &chain, 0);
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
EVBUFFER_UNLOCK(buf, EVTHREAD_WRITE);
|
EVBUFFER_UNLOCK(buf, EVTHREAD_WRITE);
|
||||||
|
return n;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
evbuffer_commit_space(struct evbuffer *buf, size_t size)
|
evbuffer_commit_space(struct evbuffer *buf,
|
||||||
|
struct evbuffer_iovec *vec, int n_vecs)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *prev = buf->previous_to_last;
|
||||||
int result = -1;
|
struct evbuffer_chain *last = buf->last;
|
||||||
|
int result = -1;
|
||||||
|
size_t added;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf, EVTHREAD_WRITE);
|
|
||||||
if (buf->freeze_end) {
|
EVBUFFER_LOCK(buf, EVTHREAD_WRITE);
|
||||||
|
if (buf->freeze_end)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (n_vecs < 1 || n_vecs > 2)
|
||||||
|
goto done;
|
||||||
|
if (n_vecs == 2) {
|
||||||
|
if (!prev || !last ||
|
||||||
|
vec[0].iov_base != CHAIN_SPACE_PTR(prev) ||
|
||||||
|
vec[1].iov_base != CHAIN_SPACE_PTR(last) ||
|
||||||
|
vec[0].iov_len > CHAIN_SPACE_LEN(prev) ||
|
||||||
|
vec[1].iov_len > CHAIN_SPACE_LEN(last))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
prev->off += vec[0].iov_len;
|
||||||
|
last->off += vec[1].iov_len;
|
||||||
|
added = vec[0].iov_len + vec[1].iov_len;
|
||||||
|
} else {
|
||||||
|
/* n_vecs == 1 */
|
||||||
|
struct evbuffer_chain *chain;
|
||||||
|
if (prev && vec[0].iov_base == CHAIN_SPACE_PTR(prev))
|
||||||
|
chain = prev;
|
||||||
|
else if (last && vec[0].iov_base == CHAIN_SPACE_PTR(last))
|
||||||
|
chain = last;
|
||||||
|
else
|
||||||
|
goto done;
|
||||||
|
if (vec[0].iov_len > CHAIN_SPACE_LEN(chain))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
chain->off += vec[0].iov_len;
|
||||||
|
added = vec[0].iov_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
chain = buf->last;
|
buf->total_len += added;
|
||||||
|
buf->n_add_for_cb += added;
|
||||||
if (chain == NULL ||
|
|
||||||
chain->buffer_len - chain->off - chain->misalign < size)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
chain->off += size;
|
|
||||||
buf->total_len += size;
|
|
||||||
buf->n_add_for_cb += size;
|
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
evbuffer_invoke_callbacks(buf);
|
evbuffer_invoke_callbacks(buf);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
EVBUFFER_UNLOCK(buf, EVTHREAD_WRITE);
|
EVBUFFER_UNLOCK(buf, EVTHREAD_WRITE);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1444,6 +1475,12 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen)
|
|||||||
#define IOV_PTR_FIELD buf
|
#define IOV_PTR_FIELD buf
|
||||||
#define IOV_LEN_FIELD len
|
#define IOV_LEN_FIELD len
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define IOV_TYPE_FROM_EVBUFFER_IOV(i,ei) do { \
|
||||||
|
(i)->IOV_PTR_FIELD = (ei)->iov_base; \
|
||||||
|
(i)->IOV_LEN_FIELD = (ei)->iov_len; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EVBUFFER_MAX_READ 4096
|
#define EVBUFFER_MAX_READ 4096
|
||||||
@ -1457,11 +1494,12 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen)
|
|||||||
@param vecs An array of two iovecs or WSABUFs.
|
@param vecs An array of two iovecs or WSABUFs.
|
||||||
@param chainp A pointer to a variable to hold the first chain we're
|
@param chainp A pointer to a variable to hold the first chain we're
|
||||||
reading into.
|
reading into.
|
||||||
|
@param exact DOCDOC
|
||||||
@return The number of buffers we're using.
|
@return The number of buffers we're using.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
_evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
_evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
||||||
IOV_TYPE *vecs, struct evbuffer_chain **chainp)
|
struct evbuffer_iovec *vecs, struct evbuffer_chain **chainp, int exact)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain;
|
||||||
int nvecs;
|
int nvecs;
|
||||||
@ -1477,11 +1515,11 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
|||||||
use the space in the next-to-last chain.
|
use the space in the next-to-last chain.
|
||||||
*/
|
*/
|
||||||
struct evbuffer_chain *prev = buf->previous_to_last;
|
struct evbuffer_chain *prev = buf->previous_to_last;
|
||||||
vecs[0].IOV_PTR_FIELD = CHAIN_SPACE_PTR(prev);
|
vecs[0].iov_base = CHAIN_SPACE_PTR(prev);
|
||||||
vecs[0].IOV_LEN_FIELD = CHAIN_SPACE_LEN(prev);
|
vecs[0].iov_len = CHAIN_SPACE_LEN(prev);
|
||||||
vecs[1].IOV_PTR_FIELD = CHAIN_SPACE_PTR(chain);
|
vecs[1].iov_base = CHAIN_SPACE_PTR(chain);
|
||||||
vecs[1].IOV_LEN_FIELD = CHAIN_SPACE_LEN(chain);
|
vecs[1].iov_len = CHAIN_SPACE_LEN(chain);
|
||||||
if (vecs[0].IOV_LEN_FIELD >= (size_t)howmuch) {
|
if (vecs[0].iov_len >= (size_t)howmuch) {
|
||||||
/* The next-to-last chain has enough
|
/* The next-to-last chain has enough
|
||||||
* space on its own. */
|
* space on its own. */
|
||||||
chain = prev;
|
chain = prev;
|
||||||
@ -1490,18 +1528,19 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
|||||||
/* We'll need both chains. */
|
/* We'll need both chains. */
|
||||||
chain = prev;
|
chain = prev;
|
||||||
nvecs = 2;
|
nvecs = 2;
|
||||||
if (vecs[0].IOV_LEN_FIELD + vecs[1].IOV_LEN_FIELD > (size_t)howmuch) {
|
if (exact &&
|
||||||
vecs[1].IOV_LEN_FIELD = howmuch - vecs[0].IOV_LEN_FIELD;
|
(vecs[0].iov_len + vecs[1].iov_len > (size_t)howmuch)) {
|
||||||
|
vecs[1].iov_len = howmuch - vecs[0].iov_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* There's data in the last chain, so we're
|
/* There's data in the last chain, so we're
|
||||||
* not allowed to use the next-to-last. */
|
* not allowed to use the next-to-last. */
|
||||||
nvecs = 1;
|
nvecs = 1;
|
||||||
vecs[0].IOV_PTR_FIELD = CHAIN_SPACE_PTR(chain);
|
vecs[0].iov_base = CHAIN_SPACE_PTR(chain);
|
||||||
vecs[0].IOV_LEN_FIELD = CHAIN_SPACE_LEN(chain);
|
vecs[0].iov_len = CHAIN_SPACE_LEN(chain);
|
||||||
if (vecs[0].IOV_LEN_FIELD > (size_t)howmuch)
|
if (exact && (vecs[0].iov_len > (size_t)howmuch))
|
||||||
vecs[0].IOV_LEN_FIELD = howmuch;
|
vecs[0].iov_len = howmuch;
|
||||||
}
|
}
|
||||||
|
|
||||||
*chainp = chain;
|
*chainp = chain;
|
||||||
@ -1566,8 +1605,16 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
|||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
IOV_TYPE vecs[2];
|
IOV_TYPE vecs[2];
|
||||||
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, vecs,
|
struct evbuffer_iovec ev_vecs[2];
|
||||||
&chain);
|
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, ev_vecs,
|
||||||
|
&chain, 1);
|
||||||
|
|
||||||
|
if (nvecs == 2) {
|
||||||
|
IOV_TYPE_FROM_EVBUFFER_IOV(&vecs[1], &ev_vecs[1]);
|
||||||
|
IOV_TYPE_FROM_EVBUFFER_IOV(&vecs[0], &ev_vecs[0]);
|
||||||
|
} else if (nvecs == 1) {
|
||||||
|
IOV_TYPE_FROM_EVBUFFER_IOV(&vecs[0], &ev_vecs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
{
|
{
|
||||||
@ -1937,6 +1984,50 @@ done:
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
|
||||||
|
struct evbuffer_ptr *start_at,
|
||||||
|
struct evbuffer_iovec *vec, int n_vec)
|
||||||
|
{
|
||||||
|
struct evbuffer_chain *chain;
|
||||||
|
int idx = 0;
|
||||||
|
size_t len_so_far = 0;
|
||||||
|
|
||||||
|
EVBUFFER_LOCK(buffer, EVTHREAD_READ);
|
||||||
|
|
||||||
|
if (start_at) {
|
||||||
|
chain = start_at->_internal.chain;
|
||||||
|
len_so_far = chain->off
|
||||||
|
- start_at->_internal.pos_in_chain;
|
||||||
|
idx = 1;
|
||||||
|
if (n_vec > 0) {
|
||||||
|
vec[0].iov_base = chain->buffer + chain->misalign
|
||||||
|
+ start_at->_internal.pos_in_chain;
|
||||||
|
vec[0].iov_len = len_so_far;
|
||||||
|
}
|
||||||
|
chain = chain->next;
|
||||||
|
} else {
|
||||||
|
chain = buffer->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (chain) {
|
||||||
|
if (len >= 0 && len_so_far >= len)
|
||||||
|
break;
|
||||||
|
if (idx<n_vec) {
|
||||||
|
vec[idx].iov_base = chain->buffer + chain->misalign;
|
||||||
|
vec[idx].iov_len = chain->off;
|
||||||
|
} else if (len<0)
|
||||||
|
break;
|
||||||
|
++idx;
|
||||||
|
len_so_far += chain->off;
|
||||||
|
chain = chain->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVBUFFER_UNLOCK(buffer, EVTHREAD_READ);
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
|
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
|
||||||
|
@ -118,26 +118,27 @@ read_completed(struct event_overlapped *eo, uintptr_t _, ssize_t nBytes)
|
|||||||
struct evbuffer *evbuf = &buf->buffer;
|
struct evbuffer *evbuf = &buf->buffer;
|
||||||
|
|
||||||
struct evbuffer_chain *chain = buf_o->first_pinned;
|
struct evbuffer_chain *chain = buf_o->first_pinned;
|
||||||
|
struct evbuffer_iovec iov[2];
|
||||||
|
int n_vec;
|
||||||
|
|
||||||
EVBUFFER_LOCK(evbuf, EVTHREAD_WRITE);
|
EVBUFFER_LOCK(evbuf, EVTHREAD_WRITE);
|
||||||
buf->read_in_progress = 0;
|
buf->read_in_progress = 0;
|
||||||
evbuffer_unfreeze(evbuf, 0);
|
evbuffer_unfreeze(evbuf, 0);
|
||||||
|
|
||||||
if (chain == evbuf->previous_to_last) {
|
iov[0].iov_base = buf_o->buffers[0].buf;
|
||||||
ssize_t n = chain->buffer_len - (chain->misalign + chain->off);
|
if (nBytes <= buf_o->buffers[0].len) {
|
||||||
if (n>nBytes)
|
iov[0].iov_len = nBytes;
|
||||||
n=nBytes;
|
n_vec = 1;
|
||||||
chain->off += n;
|
|
||||||
nBytes -= n;
|
|
||||||
evbuf->n_add_for_cb += n;
|
|
||||||
|
|
||||||
evbuffer_commit_space(evbuf, nBytes);
|
|
||||||
} else if (chain == evbuf->last) {
|
|
||||||
evbuffer_commit_space(evbuf, nBytes);
|
|
||||||
} else {
|
} else {
|
||||||
assert(0);
|
iov[0].iov_len = buf_o->buffers[0].len;
|
||||||
|
iov[1].iov_base = buf_o->buffers[1].buf;
|
||||||
|
iov[1].iov_len = nBytes - iov[0].iov_len;
|
||||||
|
n_vec = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (evbuffer_commit_space(evbuf, iov, n_vec) < 0)
|
||||||
|
assert(0); /* XXXX fail nicer. */
|
||||||
|
|
||||||
pin_release(eo, EVBUFFER_MEM_PINNED_R);
|
pin_release(eo, EVBUFFER_MEM_PINNED_R);
|
||||||
|
|
||||||
_evbuffer_decref_and_unlock(evbuf);
|
_evbuffer_decref_and_unlock(evbuf);
|
||||||
@ -244,16 +245,22 @@ done:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IOV_TYPE_FROM_EVBUFFER_IOV(i,ei) do { \
|
||||||
|
(i)->buf = (ei)->iov_base; \
|
||||||
|
(i)->len = (ei)->iov_len; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
int
|
int
|
||||||
evbuffer_launch_read(struct evbuffer *buf, size_t at_most)
|
evbuffer_launch_read(struct evbuffer *buf, size_t at_most)
|
||||||
{
|
{
|
||||||
struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
|
struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
|
||||||
int r = -1;
|
int r = -1, i;
|
||||||
int nvecs;
|
int nvecs;
|
||||||
int npin=0;
|
int npin=0;
|
||||||
struct evbuffer_chain *chain=NULL;
|
struct evbuffer_chain *chain=NULL;
|
||||||
DWORD bytesRead;
|
DWORD bytesRead;
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
|
struct evbuffer_iovec vecs[MAX_VECS];
|
||||||
|
|
||||||
if (!buf_o)
|
if (!buf_o)
|
||||||
return -1;
|
return -1;
|
||||||
@ -271,7 +278,13 @@ evbuffer_launch_read(struct evbuffer *buf, size_t at_most)
|
|||||||
buf_o->read_info.event_overlapped.cb = read_completed;
|
buf_o->read_info.event_overlapped.cb = read_completed;
|
||||||
|
|
||||||
nvecs = _evbuffer_read_setup_vecs(buf, at_most,
|
nvecs = _evbuffer_read_setup_vecs(buf, at_most,
|
||||||
buf_o->read_info.buffers, &chain);
|
vecs, &chain, 1);
|
||||||
|
for (i=0;i<nvecs;++i) {
|
||||||
|
IOV_TYPE_FROM_EVBUFFER_IOV(
|
||||||
|
&buf_o->read_info.buffers[i],
|
||||||
|
&vecs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
buf_o->read_info.n_buffers = nvecs;
|
buf_o->read_info.n_buffers = nvecs;
|
||||||
buf_o->read_info.first_pinned = chain;
|
buf_o->read_info.first_pinned = chain;
|
||||||
npin=0;
|
npin=0;
|
||||||
|
@ -256,7 +256,6 @@ void _evbuffer_decref_and_unlock(struct evbuffer *buffer);
|
|||||||
* is contiguous. Instead, it may be split across two chunks. */
|
* is contiguous. Instead, it may be split across two chunks. */
|
||||||
int _evbuffer_expand_fast(struct evbuffer *, size_t);
|
int _evbuffer_expand_fast(struct evbuffer *, size_t);
|
||||||
|
|
||||||
#ifdef _EVENT_HAVE_SYS_UIO_H
|
|
||||||
/** Helper: prepares for a readv/WSARecv call by expanding the buffer to
|
/** Helper: prepares for a readv/WSARecv call by expanding the buffer to
|
||||||
* hold enough memory to read 'howmuch' bytes in possibly noncontiguous memory.
|
* hold enough memory to read 'howmuch' bytes in possibly noncontiguous memory.
|
||||||
* Sets up the one or two iovecs in 'vecs' to point to the free memory and its
|
* Sets up the one or two iovecs in 'vecs' to point to the free memory and its
|
||||||
@ -264,11 +263,7 @@ int _evbuffer_expand_fast(struct evbuffer *, size_t);
|
|||||||
* Returns the number of vecs used.
|
* Returns the number of vecs used.
|
||||||
*/
|
*/
|
||||||
int _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
int _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
||||||
struct iovec *vecs, struct evbuffer_chain **chainp);
|
struct evbuffer_iovec *vecs, struct evbuffer_chain **chainp, int exact);
|
||||||
#elif defined(WIN32)
|
|
||||||
int _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch,
|
|
||||||
WSABUF *vecs, struct evbuffer_chain **chainp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,18 @@ struct evbuffer_ptr {
|
|||||||
} _internal;
|
} _internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Describes a single extent of memory inside an evbuffer. Used for
|
||||||
|
direct-access functions.
|
||||||
|
|
||||||
|
@see evbuffer_reserve_space, evbuffer_commit_space, evbuffer_peek
|
||||||
|
*/
|
||||||
|
struct evbuffer_iovec {
|
||||||
|
/** The start of the extent of memory. */
|
||||||
|
void *iov_base;
|
||||||
|
/** The length of the extent of memory. */
|
||||||
|
size_t iov_len;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Allocate storage for a new evbuffer.
|
Allocate storage for a new evbuffer.
|
||||||
|
|
||||||
@ -173,18 +185,33 @@ int evbuffer_expand(struct evbuffer *buf, size_t datlen);
|
|||||||
available for reading until it has been committed with
|
available for reading until it has been committed with
|
||||||
evbuffer_commit_space().
|
evbuffer_commit_space().
|
||||||
|
|
||||||
|
The space is made available as one or more extents, represented by
|
||||||
|
an initial pointer and a length. You can force the memory to be
|
||||||
|
available as only one extent. Allowing more, however, makes the
|
||||||
|
function more efficient.
|
||||||
|
|
||||||
Multiple subsequent calls to this function will make the same space
|
Multiple subsequent calls to this function will make the same space
|
||||||
available until evbuffer_commit_space() has been called.
|
available until evbuffer_commit_space() has been called.
|
||||||
|
|
||||||
|
It is an error to do anything that moves around the buffer's internal
|
||||||
|
memory structures before committing the space.
|
||||||
|
|
||||||
|
NOTE: The code currently does not ever use more than two extents.
|
||||||
|
This may change in future versions.
|
||||||
|
|
||||||
@param buf the event buffer in which to reserve space.
|
@param buf the event buffer in which to reserve space.
|
||||||
@param size how much space to make available.
|
@param size how much space to make available, at minimum. The
|
||||||
@return the pointer to the available space or NULL on error.
|
total length of the extents may be greater than the requested
|
||||||
|
length.
|
||||||
|
@param vec an array of one or more evbuffer_iovec structures to
|
||||||
|
hold pointers to the reserved extents of memory.
|
||||||
|
@param n_vec The length of the vec array. Must be at least 1.
|
||||||
|
@return the number of provided extents, or -1 on error.
|
||||||
@see evbuffer_commit_space
|
@see evbuffer_commit_space
|
||||||
*/
|
*/
|
||||||
/* FIXME: This interface is prone to leaving gaps in the buffer and
|
int
|
||||||
* reallocating stuff needlessly. Nothing uses it. It was new in Libevent 2.0.
|
evbuffer_reserve_space(struct evbuffer *buf, ssize_t size,
|
||||||
* It should get re-thought. */
|
struct evbuffer_iovec *vec, int n_vecs);
|
||||||
unsigned char *evbuffer_reserve_space(struct evbuffer *buf, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Commits previously reserved space.
|
Commits previously reserved space.
|
||||||
@ -192,14 +219,23 @@ unsigned char *evbuffer_reserve_space(struct evbuffer *buf, size_t size);
|
|||||||
Commits some of the space previously reserved with
|
Commits some of the space previously reserved with
|
||||||
evbuffer_reserve_space(). It then becomes available for reading.
|
evbuffer_reserve_space(). It then becomes available for reading.
|
||||||
|
|
||||||
|
This function may return an error if the pointer in the extents do
|
||||||
|
not match those returned from evbuffer_reserve_space, or if data
|
||||||
|
has been added to the buffer since the space was reserved.
|
||||||
|
|
||||||
|
If you want to commit less data than you got reserved space for,
|
||||||
|
modify the iov_len pointer of the buffer to a smaller value. Note
|
||||||
|
that you may have received more space than you requested if it was
|
||||||
|
available!
|
||||||
|
|
||||||
@param buf the event buffer in which to reserve space.
|
@param buf the event buffer in which to reserve space.
|
||||||
@param size how much space to commit.
|
@param vec one or two extents returned by evbuffer_reserve_space.
|
||||||
|
@paramm n_vecs the number of extents.
|
||||||
@return 0 on success, -1 on error
|
@return 0 on success, -1 on error
|
||||||
@see evbuffer_reserve_space
|
@see evbuffer_reserve_space
|
||||||
*/
|
*/
|
||||||
|
int evbuffer_commit_space(struct evbuffer *buf,
|
||||||
int evbuffer_commit_space(struct evbuffer *buf, size_t size);
|
struct evbuffer_iovec *vec, int n_vecs);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Append data to the end of an evbuffer.
|
Append data to the end of an evbuffer.
|
||||||
@ -443,6 +479,36 @@ struct evbuffer_cb_info {
|
|||||||
size_t n_deleted;
|
size_t n_deleted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Function to peek at data inside an evbuffer without removing it or
|
||||||
|
copying it out.
|
||||||
|
|
||||||
|
Pointers to the data are returned by filling the 'vec_out' array
|
||||||
|
with pointers to one or more extents of data inside the buffer.
|
||||||
|
|
||||||
|
The total data in the extents that you get back may be more than
|
||||||
|
you requested (if there is more data last extent than you asked
|
||||||
|
for), or less (if you do not provide enough evbuffer_iovecs, or if
|
||||||
|
the buffer does not have as much data as you asked to see).
|
||||||
|
|
||||||
|
@param buffer the evbuffer to peek into,
|
||||||
|
@param len the number of bytes to try to peek. If negative, we
|
||||||
|
will try to fill as much of vec_out as we can.
|
||||||
|
@param start_at an evbuffer_ptr indicating the point at which we
|
||||||
|
should start looking for data. NULL means, "At the start of the
|
||||||
|
buffer."
|
||||||
|
@param vec_out an array of evbuffer_iovec
|
||||||
|
@param n_vec the length of n_vec. If 0, we only count how many
|
||||||
|
extents would be necessary to point to the requested amount of
|
||||||
|
data.
|
||||||
|
@return The number of extents needed. This may be less than n_vec
|
||||||
|
if we didn't need all the evbuffer_iovecs we were given, or more
|
||||||
|
than n_vec if we would need more to return all the data that was
|
||||||
|
requested.
|
||||||
|
*/
|
||||||
|
int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
|
||||||
|
struct evbuffer_ptr *start_at,
|
||||||
|
struct evbuffer_iovec *vec_out, int n_vec);
|
||||||
|
|
||||||
/** Type definition for a callback that is invoked whenever data is added or
|
/** Type definition for a callback that is invoked whenever data is added or
|
||||||
removed from an evbuffer.
|
removed from an evbuffer.
|
||||||
|
|
||||||
|
@ -187,21 +187,26 @@ test_evbuffer(void *ptr)
|
|||||||
evbuffer_validate(evb);
|
evbuffer_validate(evb);
|
||||||
|
|
||||||
|
|
||||||
/* testing reserve and commit */
|
/* testing one-vector reserve and commit */
|
||||||
{
|
{
|
||||||
u_char *buf;
|
struct evbuffer_iovec v[1];
|
||||||
int i, j;
|
char *buf;
|
||||||
|
int i, j, r;
|
||||||
|
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
buf = evbuffer_reserve_space(evb, 10000);
|
r = evbuffer_reserve_space(evb, 10000, v, 1);
|
||||||
tt_assert(buf != NULL);
|
tt_int_op(r, ==, 1);
|
||||||
|
tt_assert(v[0].iov_len >= 10000);
|
||||||
|
tt_assert(v[0].iov_base != NULL);
|
||||||
|
|
||||||
evbuffer_validate(evb);
|
evbuffer_validate(evb);
|
||||||
|
buf = v[0].iov_base;
|
||||||
for (j = 0; j < 10000; ++j) {
|
for (j = 0; j < 10000; ++j) {
|
||||||
buf[j] = j;
|
buf[j] = j;
|
||||||
}
|
}
|
||||||
evbuffer_validate(evb);
|
evbuffer_validate(evb);
|
||||||
|
|
||||||
tt_assert(evbuffer_commit_space(evb, 10000) == 0);
|
tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
|
||||||
evbuffer_validate(evb);
|
evbuffer_validate(evb);
|
||||||
|
|
||||||
tt_assert(evbuffer_get_length(evb) >= 10000);
|
tt_assert(evbuffer_get_length(evb) >= 10000);
|
||||||
@ -216,6 +221,97 @@ test_evbuffer(void *ptr)
|
|||||||
evbuffer_free(evb_two);
|
evbuffer_free(evb_two);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_evbuffer_reserve2(void *ptr)
|
||||||
|
{
|
||||||
|
/* Test the two-vector cases of reserve/commit. */
|
||||||
|
struct evbuffer *buf = evbuffer_new();
|
||||||
|
int n, i;
|
||||||
|
struct evbuffer_iovec v[2];
|
||||||
|
size_t remaining;
|
||||||
|
char *cp, *cp2;
|
||||||
|
|
||||||
|
/* First chunk will necessarily be one chunk. Use 512 bytes of it.*/
|
||||||
|
n = evbuffer_reserve_space(buf, 1024, v, 2);
|
||||||
|
tt_int_op(n, ==, 1);
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 0);
|
||||||
|
tt_assert(v[0].iov_base != NULL);
|
||||||
|
tt_int_op(v[0].iov_len, >=, 1024);
|
||||||
|
memset(v[0].iov_base, 'X', 512);
|
||||||
|
cp = v[0].iov_base;
|
||||||
|
remaining = v[0].iov_len - 512;
|
||||||
|
v[0].iov_len = 512;
|
||||||
|
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 512);
|
||||||
|
|
||||||
|
/* Ask for another same-chunk request, in an existing chunk. Use 8
|
||||||
|
* bytes of it. */
|
||||||
|
n = evbuffer_reserve_space(buf, 32, v, 2);
|
||||||
|
tt_int_op(n, ==, 1);
|
||||||
|
tt_assert(cp + 512 == v[0].iov_base);
|
||||||
|
tt_int_op(remaining, ==, v[0].iov_len);
|
||||||
|
memset(v[0].iov_base, 'Y', 8);
|
||||||
|
v[0].iov_len = 8;
|
||||||
|
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 520);
|
||||||
|
remaining -= 8;
|
||||||
|
|
||||||
|
/* Now ask for a request that will be split. Use only one byte of it,
|
||||||
|
though. */
|
||||||
|
n = evbuffer_reserve_space(buf, remaining+64, v, 2);
|
||||||
|
tt_int_op(n, ==, 2);
|
||||||
|
tt_assert(cp + 520 == v[0].iov_base);
|
||||||
|
tt_int_op(remaining, ==, v[0].iov_len);
|
||||||
|
tt_assert(v[1].iov_base);
|
||||||
|
tt_assert(v[1].iov_len >= 64);
|
||||||
|
cp2 = v[1].iov_base;
|
||||||
|
memset(v[0].iov_base, 'Z', 1);
|
||||||
|
v[0].iov_len = 1;
|
||||||
|
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 521);
|
||||||
|
remaining -= 1;
|
||||||
|
|
||||||
|
/* Now ask for a request that will be split. Use some of the first
|
||||||
|
* part and some of the second. */
|
||||||
|
n = evbuffer_reserve_space(buf, remaining+64, v, 2);
|
||||||
|
tt_int_op(n, ==, 2);
|
||||||
|
tt_assert(cp + 521 == v[0].iov_base);
|
||||||
|
tt_int_op(remaining, ==, v[0].iov_len);
|
||||||
|
tt_assert(v[1].iov_base == cp2);
|
||||||
|
tt_assert(v[1].iov_len >= 64);
|
||||||
|
memset(v[0].iov_base, 'W', 400);
|
||||||
|
v[0].iov_len = 400;
|
||||||
|
memset(v[1].iov_base, 'x', 60);
|
||||||
|
v[1].iov_len = 60;
|
||||||
|
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2));
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 981);
|
||||||
|
|
||||||
|
|
||||||
|
/* Now peek to make sure stuff got made how we like. */
|
||||||
|
memset(v,0,sizeof(v));
|
||||||
|
n = evbuffer_peek(buf, -1, NULL, v, 2);
|
||||||
|
tt_int_op(n, ==, 2);
|
||||||
|
tt_int_op(v[0].iov_len, ==, 921);
|
||||||
|
tt_int_op(v[1].iov_len, ==, 60);
|
||||||
|
|
||||||
|
cp = v[0].iov_base;
|
||||||
|
for (i=0; i<512; ++i)
|
||||||
|
tt_int_op(cp[i], ==, 'X');
|
||||||
|
for (i=512; i<520; ++i)
|
||||||
|
tt_int_op(cp[i], ==, 'Y');
|
||||||
|
for (i=520; i<521; ++i)
|
||||||
|
tt_int_op(cp[i], ==, 'Z');
|
||||||
|
for (i=521; i<921; ++i)
|
||||||
|
tt_int_op(cp[i], ==, 'W');
|
||||||
|
|
||||||
|
cp = v[1].iov_base;
|
||||||
|
for (i=0; i<60; ++i)
|
||||||
|
tt_int_op(cp[i], ==, 'x');
|
||||||
|
|
||||||
|
end:
|
||||||
|
evbuffer_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
static int reference_cb_called;
|
static int reference_cb_called;
|
||||||
static void
|
static void
|
||||||
reference_cb(const void *data, size_t len, void *extra)
|
reference_cb(const void *data, size_t len, void *extra)
|
||||||
@ -233,15 +329,15 @@ test_evbuffer_reference(void *ptr)
|
|||||||
{
|
{
|
||||||
struct evbuffer *src = evbuffer_new();
|
struct evbuffer *src = evbuffer_new();
|
||||||
struct evbuffer *dst = evbuffer_new();
|
struct evbuffer *dst = evbuffer_new();
|
||||||
unsigned char *tmp;
|
struct evbuffer_iovec v[1];
|
||||||
const char *data = "this is what we add as read-only memory.";
|
const char *data = "this is what we add as read-only memory.";
|
||||||
reference_cb_called = 0;
|
reference_cb_called = 0;
|
||||||
|
|
||||||
tt_assert(evbuffer_add_reference(src, data, strlen(data),
|
tt_assert(evbuffer_add_reference(src, data, strlen(data),
|
||||||
reference_cb, (void *)0xdeadaffe) != -1);
|
reference_cb, (void *)0xdeadaffe) != -1);
|
||||||
|
|
||||||
tmp = evbuffer_reserve_space(dst, strlen(data));
|
evbuffer_reserve_space(dst, strlen(data), v, 1);
|
||||||
tt_assert(evbuffer_remove(src, tmp, 10) != -1);
|
tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
|
||||||
|
|
||||||
evbuffer_validate(src);
|
evbuffer_validate(src);
|
||||||
evbuffer_validate(dst);
|
evbuffer_validate(dst);
|
||||||
@ -251,9 +347,12 @@ test_evbuffer_reference(void *ptr)
|
|||||||
evbuffer_validate(src);
|
evbuffer_validate(src);
|
||||||
evbuffer_drain(src, 5);
|
evbuffer_drain(src, 5);
|
||||||
|
|
||||||
tt_assert(evbuffer_remove(src, tmp + 10, strlen(data) - 10) != -1);
|
tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
|
||||||
|
strlen(data) - 10) != -1);
|
||||||
|
|
||||||
evbuffer_commit_space(dst, strlen(data));
|
v[0].iov_len = strlen(data);
|
||||||
|
|
||||||
|
evbuffer_commit_space(dst, v, 1);
|
||||||
evbuffer_validate(src);
|
evbuffer_validate(src);
|
||||||
evbuffer_validate(dst);
|
evbuffer_validate(dst);
|
||||||
|
|
||||||
@ -553,14 +652,25 @@ test_evbuffer_ptr_set(void *ptr)
|
|||||||
{
|
{
|
||||||
struct evbuffer *buf = evbuffer_new();
|
struct evbuffer *buf = evbuffer_new();
|
||||||
struct evbuffer_ptr pos;
|
struct evbuffer_ptr pos;
|
||||||
|
struct evbuffer_iovec v[1];
|
||||||
|
|
||||||
/* create some chains */
|
/* create some chains */
|
||||||
evbuffer_reserve_space(buf, 5000);
|
evbuffer_reserve_space(buf, 5000, v, 1);
|
||||||
evbuffer_commit_space(buf, 5000);
|
v[0].iov_len = 5000;
|
||||||
evbuffer_reserve_space(buf, 4000);
|
memset(v[0].iov_base, 1, v[0].iov_len);
|
||||||
evbuffer_commit_space(buf, 4000);
|
evbuffer_commit_space(buf, v, 1);
|
||||||
evbuffer_reserve_space(buf, 3000);
|
|
||||||
evbuffer_commit_space(buf, 3000);
|
evbuffer_reserve_space(buf, 4000, v, 1);
|
||||||
|
v[0].iov_len = 4000;
|
||||||
|
memset(v[0].iov_base, 2, v[0].iov_len);
|
||||||
|
evbuffer_commit_space(buf, v, 1);
|
||||||
|
|
||||||
|
evbuffer_reserve_space(buf, 3000, v, 1);
|
||||||
|
v[0].iov_len = 3000;
|
||||||
|
memset(v[0].iov_base, 3, v[0].iov_len);
|
||||||
|
evbuffer_commit_space(buf, v, 1);
|
||||||
|
|
||||||
|
tt_int_op(evbuffer_get_length(buf), ==, 12000);
|
||||||
|
|
||||||
tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
|
tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
|
||||||
tt_assert(pos.pos == -1);
|
tt_assert(pos.pos == -1);
|
||||||
@ -865,6 +975,106 @@ end:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_evbuffer_peek(void *info)
|
||||||
|
{
|
||||||
|
struct evbuffer *buf = NULL, *tmp_buf = NULL;
|
||||||
|
int i;
|
||||||
|
struct evbuffer_iovec v[20];
|
||||||
|
struct evbuffer_ptr ptr;
|
||||||
|
|
||||||
|
#define tt_iov_eq(v, s) \
|
||||||
|
tt_int_op((v)->iov_len, ==, strlen(s)); \
|
||||||
|
tt_assert(!memcmp((v)->iov_base, (s), strlen(s)))
|
||||||
|
|
||||||
|
/* Let's make a very fragmented buffer. */
|
||||||
|
buf = evbuffer_new();
|
||||||
|
tmp_buf = evbuffer_new();
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i);
|
||||||
|
evbuffer_add_buffer(buf, tmp_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple peek: get everything. */
|
||||||
|
i = evbuffer_peek(buf, -1, NULL, v, 20);
|
||||||
|
tt_int_op(i, ==, 16); /* we used only 16 chunks. */
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [0]\n");
|
||||||
|
tt_iov_eq(&v[3], "Contents of chunk [3]\n");
|
||||||
|
tt_iov_eq(&v[12], "Contents of chunk [12]\n");
|
||||||
|
tt_iov_eq(&v[15], "Contents of chunk [15]\n");
|
||||||
|
|
||||||
|
/* Just get one chunk worth. */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(buf, -1, NULL, v, 1);
|
||||||
|
tt_int_op(i, ==, 1);
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [0]\n");
|
||||||
|
tt_assert(v[1].iov_base == NULL);
|
||||||
|
|
||||||
|
/* Suppose we want at least the first 40 bytes. */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(buf, 40, NULL, v, 16);
|
||||||
|
tt_int_op(i, ==, 2);
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [0]\n");
|
||||||
|
tt_iov_eq(&v[1], "Contents of chunk [1]\n");
|
||||||
|
tt_assert(v[2].iov_base == NULL);
|
||||||
|
|
||||||
|
/* How many chunks do we need for 100 bytes? */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(buf, 100, NULL, NULL, 0);
|
||||||
|
tt_int_op(i, ==, 5);
|
||||||
|
tt_assert(v[0].iov_base == NULL);
|
||||||
|
|
||||||
|
/* Now we ask for more bytes than we provide chunks for */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(buf, 60, NULL, v, 1);
|
||||||
|
tt_int_op(i, ==, 3);
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [0]\n");
|
||||||
|
tt_assert(v[1].iov_base == NULL);
|
||||||
|
|
||||||
|
/* Now we ask for more bytes than the buffer has. */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(buf, 65536, NULL, v, 20);
|
||||||
|
tt_int_op(i, ==, 16); /* we used only 16 chunks. */
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [0]\n");
|
||||||
|
tt_iov_eq(&v[3], "Contents of chunk [3]\n");
|
||||||
|
tt_iov_eq(&v[12], "Contents of chunk [12]\n");
|
||||||
|
tt_iov_eq(&v[15], "Contents of chunk [15]\n");
|
||||||
|
tt_assert(v[16].iov_base == NULL);
|
||||||
|
|
||||||
|
/* What happens if we try an empty buffer? */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(tmp_buf, -1, NULL, v, 20);
|
||||||
|
tt_int_op(i, ==, 0);
|
||||||
|
tt_assert(v[0].iov_base == NULL);
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
i = evbuffer_peek(tmp_buf, 50, NULL, v, 20);
|
||||||
|
tt_int_op(i, ==, 0);
|
||||||
|
tt_assert(v[0].iov_base == NULL);
|
||||||
|
|
||||||
|
/* Okay, now time to have fun with pointers. */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET);
|
||||||
|
i = evbuffer_peek(buf, 50, &ptr, v, 20);
|
||||||
|
tt_int_op(i, ==, 3);
|
||||||
|
tt_iov_eq(&v[0], " of chunk [1]\n");
|
||||||
|
tt_iov_eq(&v[1], "Contents of chunk [2]\n");
|
||||||
|
tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/
|
||||||
|
|
||||||
|
/* advance to the start of another chain. */
|
||||||
|
memset(v, 0, sizeof(v));
|
||||||
|
evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD);
|
||||||
|
i = evbuffer_peek(buf, 44, &ptr, v, 20);
|
||||||
|
tt_int_op(i, ==, 2);
|
||||||
|
tt_iov_eq(&v[0], "Contents of chunk [2]\n");
|
||||||
|
tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (buf)
|
||||||
|
evbuffer_free(buf);
|
||||||
|
if (tmp_buf)
|
||||||
|
evbuffer_free(tmp_buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check whether evbuffer freezing works right. This is called twice,
|
/* Check whether evbuffer freezing works right. This is called twice,
|
||||||
once with the argument "start" and once with the argument "end".
|
once with the argument "start" and once with the argument "end".
|
||||||
When we test "start", we freeze the start of an evbuffer and make sure
|
When we test "start", we freeze the start of an evbuffer and make sure
|
||||||
@ -886,6 +1096,7 @@ test_evbuffer_freeze(void *ptr)
|
|||||||
char charbuf[128];
|
char charbuf[128];
|
||||||
int r;
|
int r;
|
||||||
size_t orig_length;
|
size_t orig_length;
|
||||||
|
struct evbuffer_iovec v[1];
|
||||||
|
|
||||||
if (!start)
|
if (!start)
|
||||||
tt_str_op(ptr, ==, "end");
|
tt_str_op(ptr, ==, "end");
|
||||||
@ -912,11 +1123,13 @@ test_evbuffer_freeze(void *ptr)
|
|||||||
/* These functions all manipulate the end of buf. */
|
/* These functions all manipulate the end of buf. */
|
||||||
r = evbuffer_add(buf, "abc", 0);
|
r = evbuffer_add(buf, "abc", 0);
|
||||||
FREEZE_EQ(r, 0, -1);
|
FREEZE_EQ(r, 0, -1);
|
||||||
cp = (char*)evbuffer_reserve_space(buf, 10);
|
r = evbuffer_reserve_space(buf, 10, v, 1);
|
||||||
FREEZE_EQ(cp==NULL, 0, 1);
|
FREEZE_EQ(r, 1, -1);
|
||||||
if (cp)
|
if (r == 0) {
|
||||||
memset(cp, 'X', 10);
|
memset(v[0].iov_base, 'X', 10);
|
||||||
r = evbuffer_commit_space(buf, 10);
|
v[0].iov_len = 10;
|
||||||
|
}
|
||||||
|
r = evbuffer_commit_space(buf, v, 1);
|
||||||
FREEZE_EQ(r, 0, -1);
|
FREEZE_EQ(r, 0, -1);
|
||||||
r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
|
r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
|
||||||
FREEZE_EQ(r, 0, -1);
|
FREEZE_EQ(r, 0, -1);
|
||||||
@ -972,6 +1185,7 @@ static const struct testcase_setup_t nil_setup = {
|
|||||||
|
|
||||||
struct testcase_t evbuffer_testcases[] = {
|
struct testcase_t evbuffer_testcases[] = {
|
||||||
{ "evbuffer", test_evbuffer, 0, NULL, NULL },
|
{ "evbuffer", test_evbuffer, 0, NULL, NULL },
|
||||||
|
{ "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
|
||||||
{ "reference", test_evbuffer_reference, 0, NULL, NULL },
|
{ "reference", test_evbuffer_reference, 0, NULL, NULL },
|
||||||
{ "iterative", test_evbuffer_iterative, 0, NULL, NULL },
|
{ "iterative", test_evbuffer_iterative, 0, NULL, NULL },
|
||||||
{ "readln", test_evbuffer_readln, 0, NULL, NULL },
|
{ "readln", test_evbuffer_readln, 0, NULL, NULL },
|
||||||
@ -981,6 +1195,7 @@ struct testcase_t evbuffer_testcases[] = {
|
|||||||
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
|
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
|
||||||
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
|
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
|
||||||
{ "prepend", test_evbuffer_prepend, 0, NULL, NULL },
|
{ "prepend", test_evbuffer_prepend, 0, NULL, NULL },
|
||||||
|
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
|
||||||
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
||||||
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
@ -106,28 +106,38 @@ static enum bufferevent_filter_result
|
|||||||
zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
|
zlib_input_filter(struct evbuffer *src, struct evbuffer *dst,
|
||||||
ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
|
ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
|
||||||
{
|
{
|
||||||
|
struct evbuffer_iovec v_in[1];
|
||||||
|
struct evbuffer_iovec v_out[1];
|
||||||
int nread, nwrite;
|
int nread, nwrite;
|
||||||
int res;
|
int res, n;
|
||||||
|
|
||||||
z_streamp p = ctx;
|
z_streamp p = ctx;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* let's do some decompression */
|
/* let's do some decompression */
|
||||||
p->avail_in = evbuffer_get_contiguous_space(src);
|
n = evbuffer_peek(src, -1, NULL, v_in, 1);
|
||||||
p->next_in = evbuffer_pullup(src, p->avail_in);
|
if (n) {
|
||||||
|
p->avail_in = v_in[0].iov_len;
|
||||||
|
p->next_in = v_in[0].iov_base;
|
||||||
|
} else {
|
||||||
|
p->avail_in = 0;
|
||||||
|
p->next_in = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p->next_out = evbuffer_reserve_space(dst, 4096);
|
evbuffer_reserve_space(dst, 4096, v_out, 1);
|
||||||
p->avail_out = 4096;
|
p->next_out = v_out[0].iov_base;
|
||||||
|
p->avail_out = v_out[0].iov_len;
|
||||||
|
|
||||||
/* we need to flush zlib if we got a flush */
|
/* we need to flush zlib if we got a flush */
|
||||||
res = inflate(p, getstate(state));
|
res = inflate(p, getstate(state));
|
||||||
|
|
||||||
/* let's figure out how much was compressed */
|
/* let's figure out how much was compressed */
|
||||||
nread = evbuffer_get_contiguous_space(src) - p->avail_in;
|
nread = v_in[0].iov_len - p->avail_in;
|
||||||
nwrite = 4096 - p->avail_out;
|
nwrite = v_out[0].iov_len - p->avail_out;
|
||||||
|
|
||||||
evbuffer_drain(src, nread);
|
evbuffer_drain(src, nread);
|
||||||
evbuffer_commit_space(dst, nwrite);
|
v_out[0].iov_len = nwrite;
|
||||||
|
evbuffer_commit_space(dst, v_out, 1);
|
||||||
|
|
||||||
if (res==Z_BUF_ERROR) {
|
if (res==Z_BUF_ERROR) {
|
||||||
/* We're out of space, or out of decodeable input.
|
/* We're out of space, or out of decodeable input.
|
||||||
@ -150,29 +160,38 @@ static enum bufferevent_filter_result
|
|||||||
zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
|
zlib_output_filter(struct evbuffer *src, struct evbuffer *dst,
|
||||||
ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
|
ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
|
||||||
{
|
{
|
||||||
|
struct evbuffer_iovec v_in[1];
|
||||||
|
struct evbuffer_iovec v_out[1];
|
||||||
int nread, nwrite;
|
int nread, nwrite;
|
||||||
int res;
|
int res, n;
|
||||||
|
|
||||||
z_streamp p = ctx;
|
z_streamp p = ctx;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* let's do some compression */
|
/* let's do some compression */
|
||||||
p->avail_in = evbuffer_get_contiguous_space(src);
|
n = evbuffer_peek(src, -1, NULL, v_in, 1);
|
||||||
p->next_in = evbuffer_pullup(src, p->avail_in);
|
if (n) {
|
||||||
|
p->avail_in = v_in[0].iov_len;
|
||||||
p->next_out = evbuffer_reserve_space(dst, 4096);
|
p->next_in = v_in[0].iov_base;
|
||||||
p->avail_out = 4096;
|
} else {
|
||||||
|
p->avail_in = 0;
|
||||||
|
p->next_in = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
evbuffer_reserve_space(dst, 4096, v_out, 1);
|
||||||
|
p->next_out = v_out[0].iov_base;
|
||||||
|
p->avail_out = v_out[0].iov_len;
|
||||||
|
|
||||||
/* we need to flush zlib if we got a flush */
|
/* we need to flush zlib if we got a flush */
|
||||||
res = deflate(p, getstate(state));
|
res = deflate(p, getstate(state));
|
||||||
|
|
||||||
/* let's figure out how much was compressed */
|
/* let's figure out how much was decompressed */
|
||||||
nread = evbuffer_get_contiguous_space(src) - p->avail_in;
|
nread = v_in[0].iov_len - p->avail_in;
|
||||||
nwrite = 4096 - p->avail_out;
|
nwrite = v_out[0].iov_len - p->avail_out;
|
||||||
|
|
||||||
evbuffer_drain(src, nread);
|
evbuffer_drain(src, nread);
|
||||||
evbuffer_commit_space(dst, nwrite);
|
v_out[0].iov_len = nwrite;
|
||||||
|
evbuffer_commit_space(dst, v_out, 1);
|
||||||
|
|
||||||
if (res==Z_BUF_ERROR) {
|
if (res==Z_BUF_ERROR) {
|
||||||
/* We're out of space, or out of decodeable input.
|
/* We're out of space, or out of decodeable input.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user