#include "util-internal.h"
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include "event2/event-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/buffer_compat.h"
#include "event2/util.h"
#include "defer-internal.h"
#include "evbuffer-internal.h"
#include "log-internal.h"
#include "regress.h"
static int
evbuffer_validate_(struct evbuffer *buf)
{
struct evbuffer_chain *chain;
size_t sum = 0;
int found_last_with_datap = 0;
if (buf->first == NULL) {
tt_assert(buf->last == NULL);
tt_assert(buf->total_len == 0);
}
chain = buf->first;
tt_assert(buf->last_with_datap);
if (buf->last_with_datap == &buf->first)
found_last_with_datap = 1;
while (chain != NULL) {
if (&chain->next == buf->last_with_datap)
found_last_with_datap = 1;
sum += chain->off;
if (chain->next == NULL) {
tt_assert(buf->last == chain);
}
tt_assert(chain->buffer_len >= chain->misalign + chain->off);
chain = chain->next;
}
if (buf->first)
tt_assert(*buf->last_with_datap);
if (*buf->last_with_datap) {
chain = *buf->last_with_datap;
if (chain->off == 0 || buf->total_len == 0) {
tt_assert(chain->off == 0)
tt_assert(chain == buf->first);
tt_assert(buf->total_len == 0);
}
chain = chain->next;
while (chain != NULL) {
tt_assert(chain->off == 0);
chain = chain->next;
}
} else {
tt_assert(buf->last_with_datap == &buf->first);
}
tt_assert(found_last_with_datap);
tt_assert(sum == buf->total_len);
return 1;
end:
return 0;
}
static void
evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp)
{
struct evbuffer_chain *chain;
size_t a, w, u;
int n = 0;
u = a = w = 0;
chain = buf->first;
while (chain && chain->off==0) {
++n;
a += chain->buffer_len;
chain = chain->next;
}
if (chain) {
++n;
a += chain->buffer_len;
u += chain->off;
if (chain->next && chain->next->off)
w += (size_t)(chain->buffer_len - (chain->misalign + chain->off));
chain = chain->next;
}
while (chain && chain->off) {
++n;
a += chain->buffer_len;
w += (size_t)chain->misalign;
u += chain->off;
if (chain->next && chain->next->off)
w += (size_t) (chain->buffer_len - (chain->misalign + chain->off));
chain = chain->next;
}
while (chain) {
++n;
a += chain->buffer_len;
}
*allocatedp = a;
*wastedp = w;
*usedp = u;
}
#define evbuffer_validate(buf) \
TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
static void
test_evbuffer(void *ptr)
{
static char buffer[512], *tmp;
struct evbuffer *evb = evbuffer_new();
struct evbuffer *evb_two = evbuffer_new();
size_t sz_tmp;
int i;
evbuffer_validate(evb);
evbuffer_add_printf(evb, "%s/%d", "hello", 1);
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb) == 7);
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));
evbuffer_add_buffer(evb, evb_two);
evbuffer_validate(evb);
evbuffer_drain(evb, strlen("hello/"));
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb) == 1);
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));
evbuffer_add_printf(evb_two, "%s", "/hello");
evbuffer_validate(evb);
evbuffer_add_buffer(evb, evb_two);
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb_two) == 0);
tt_assert(evbuffer_get_length(evb) == 7);
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0);
memset(buffer, 0, sizeof(buffer));
evbuffer_add(evb, buffer, sizeof(buffer));
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb) == 7 + 512);
tmp = (char *)evbuffer_pullup(evb, 7 + 512);
tt_assert(tmp);
tt_assert(!strncmp(tmp, "1/hello", 7));
tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
evbuffer_validate(evb);
evbuffer_prepend(evb, "something", 9);
evbuffer_validate(evb);
evbuffer_prepend(evb, "else", 4);
evbuffer_validate(evb);
tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
evbuffer_validate(evb);
evbuffer_drain(evb, -1);
evbuffer_validate(evb);
evbuffer_drain(evb_two, -1);
evbuffer_validate(evb);
for (i = 0; i < 3; ++i) {
evbuffer_add(evb_two, buffer, sizeof(buffer));
evbuffer_validate(evb_two);
evbuffer_add_buffer(evb, evb_two);
evbuffer_validate(evb);
evbuffer_validate(evb_two);
}
tt_assert(evbuffer_get_length(evb_two) == 0);
tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));
sz_tmp = (size_t)(sizeof(buffer)*2.5);
evbuffer_remove_buffer(evb, evb_two, sz_tmp);
tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
evbuffer_validate(evb);
if (memcmp(evbuffer_pullup(
evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
memcmp(evbuffer_pullup(
evb_two, -1), buffer, sizeof(buffer)) != 0)
tt_abort_msg("Pullup did not preserve content");
evbuffer_validate(evb);
{
struct evbuffer_iovec v[1];
char *buf;
int i, j, r;
for (i = 0; i < 3; ++i) {
r = evbuffer_reserve_space(evb, 10000, v, 1);
tt_int_op(r, ==, 1);
tt_assert(v[0].iov_len >= 10000);
tt_assert(v[0].iov_base != NULL);
evbuffer_validate(evb);
buf = v[0].iov_base;
for (j = 0; j < 10000; ++j) {
buf[j] = j;
}
evbuffer_validate(evb);
tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb) >= 10000);
evbuffer_drain(evb, j * 5000);
evbuffer_validate(evb);
}
}
end:
evbuffer_free(evb);
evbuffer_free(evb_two);
}
static void
no_cleanup(const void *data, size_t datalen, void *extra)
{
}
static void
test_evbuffer_remove_buffer_with_empty(void *ptr)
{
struct evbuffer *src = evbuffer_new();
struct evbuffer *dst = evbuffer_new();
char buf[2];
evbuffer_validate(src);
evbuffer_validate(dst);
evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
evbuffer_add(dst, buf, sizeof(buf));
evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
evbuffer_validate(src);
evbuffer_validate(dst);
evbuffer_remove_buffer(src, dst, 3);
evbuffer_validate(src);
evbuffer_validate(dst);
end:
evbuffer_free(src);
evbuffer_free(dst);
}
static void
test_evbuffer_reserve2(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
int n, i;
struct evbuffer_iovec v[2];
size_t remaining;
char *cp, *cp2;
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;
evbuffer_validate(buf);
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
tt_int_op(evbuffer_get_length(buf), ==, 512);
evbuffer_validate(buf);
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;
evbuffer_validate(buf);
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;
evbuffer_validate(buf);
n = evbuffer_reserve_space(buf, remaining+64, v, 2);
evbuffer_validate(buf);
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);
evbuffer_validate(buf);
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 void
test_evbuffer_reserve_many(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
struct evbuffer_iovec v[8];
int n;
size_t sz;
int add_data = ptr && !strcmp(ptr, "add");
int fill_first = ptr && !strcmp(ptr, "fill");
char *cp1, *cp2;
n = evbuffer_reserve_space(buf, 128, v, 2);
evbuffer_validate(buf);
tt_int_op(n, ==, 1);
tt_assert(v[0].iov_len >= 128);
sz = v[0].iov_len;
cp1 = v[0].iov_base;
if (add_data) {
*(char*)v[0].iov_base = 'X';
v[0].iov_len = 1;
n = evbuffer_commit_space(buf, v, 1);
tt_int_op(n, ==, 0);
} else if (fill_first) {
memset(v[0].iov_base, 'X', v[0].iov_len);
n = evbuffer_commit_space(buf, v, 1);
tt_int_op(n, ==, 0);
n = evbuffer_reserve_space(buf, 128, v, 2);
tt_int_op(n, ==, 1);
sz = v[0].iov_len;
tt_assert(v[0].iov_base != cp1);
cp1 = v[0].iov_base;
}
n = evbuffer_reserve_space(buf, sz+128, v, 2);
evbuffer_validate(buf);
tt_int_op(n, ==, 2);
sz = v[0].iov_len + v[1].iov_len;
tt_int_op(sz, >=, v[0].iov_len+128);
if (add_data) {
tt_assert(v[0].iov_base == cp1 + 1);
} else {
tt_assert(v[0].iov_base == cp1);
}
cp1 = v[0].iov_base;
cp2 = v[1].iov_base;
n = evbuffer_reserve_space(buf, sz+128, v, 3);
evbuffer_validate(buf);
tt_int_op(n, ==, 3);
tt_assert(cp1 == v[0].iov_base);
tt_assert(cp2 == v[1].iov_base);
sz = v[0].iov_len + v[1].iov_len + v[2].iov_len;
n = evbuffer_reserve_space(buf, sz+128, v, 2);
evbuffer_validate(buf);
if (add_data) {
tt_int_op(n, ==, 2);
tt_assert(cp1 == v[0].iov_base);
} else {
tt_int_op(n, ==, 1);
}
end:
evbuffer_free(buf);
}
static void
test_evbuffer_expand(void *ptr)
{
char data[4096];
struct evbuffer *buf;
size_t a,w,u;
void *buffer;
memset(data, 'X', sizeof(data));
buf = evbuffer_new();
tt_int_op(evbuffer_expand(buf, 20000), ==, 0);
evbuffer_validate(buf);
a=w=u=0;
evbuffer_get_waste(buf, &a,&w,&u);
tt_assert(w == 0);
tt_assert(u == 0);
tt_assert(a >= 20000);
tt_assert(buf->first);
tt_assert(buf->first == buf->last);
tt_assert(buf->first->off == 0);
tt_assert(buf->first->buffer_len >= 20000);
buffer = buf->first->buffer;
evbuffer_add(buf, data, 1024);
tt_int_op(evbuffer_expand(buf, 1024), ==, 0);
tt_assert(buf->first->buffer == buffer);
evbuffer_validate(buf);
evbuffer_free(buf);
buf = evbuffer_new();
evbuffer_add(buf, data, 400);
{
int n = (int)(buf->first->buffer_len - buf->first->off - 1);
tt_assert(n < (int)sizeof(data));
evbuffer_add(buf, data, n);
}
tt_assert(buf->first == buf->last);
tt_assert(buf->first->off == buf->first->buffer_len - 1);
evbuffer_drain(buf, buf->first->off - 1);
tt_assert(1 == evbuffer_get_length(buf));
tt_assert(buf->first->misalign > 0);
tt_assert(buf->first->off == 1);
buffer = buf->first->buffer;
tt_assert(evbuffer_expand(buf, 40) == 0);
tt_assert(buf->first == buf->last);
tt_assert(buf->first->off == 1);
tt_assert(buf->first->buffer == buffer);
tt_assert(buf->first->misalign == 0);
evbuffer_validate(buf);
evbuffer_free(buf);
buf = evbuffer_new();
evbuffer_add(buf, data, sizeof(data));
evbuffer_add(buf, data, sizeof(data));
evbuffer_add(buf, data, sizeof(data));
evbuffer_validate(buf);
evbuffer_expand(buf, 1024);
evbuffer_validate(buf);
evbuffer_pullup(buf, -1);
evbuffer_validate(buf);
end:
evbuffer_free(buf);
}
static int reference_cb_called;
static void
reference_cb(const void *data, size_t len, void *extra)
{
tt_str_op(data, ==, "this is what we add as read-only memory.");
tt_int_op(len, ==, strlen(data));
tt_want(extra == (void *)0xdeadaffe);
++reference_cb_called;
end:
;
}
static void
test_evbuffer_reference(void *ptr)
{
struct evbuffer *src = evbuffer_new();
struct evbuffer *dst = evbuffer_new();
struct evbuffer_iovec v[1];
const char *data = "this is what we add as read-only memory.";
reference_cb_called = 0;
tt_assert(evbuffer_add_reference(src, data, strlen(data),
reference_cb, (void *)0xdeadaffe) != -1);
evbuffer_reserve_space(dst, strlen(data), v, 1);
tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
evbuffer_validate(src);
evbuffer_validate(dst);
evbuffer_prepend(src, "aaaaa", 5);
evbuffer_validate(src);
evbuffer_drain(src, 5);
tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
strlen(data) - 10) != -1);
v[0].iov_len = strlen(data);
evbuffer_commit_space(dst, v, 1);
evbuffer_validate(src);
evbuffer_validate(dst);
tt_int_op(reference_cb_called, ==, 1);
tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)),
data, strlen(data)));
evbuffer_validate(dst);
end:
evbuffer_free(dst);
evbuffer_free(src);
}
static struct event_base *addfile_test_event_base = NULL;
static int addfile_test_done_writing = 0;
static int addfile_test_total_written = 0;
static int addfile_test_total_read = 0;
static void
addfile_test_writecb(evutil_socket_t fd, short what, void *arg)
{
struct evbuffer *b = arg;
int r;
evbuffer_validate(b);
while (evbuffer_get_length(b)) {
r = evbuffer_write(b, fd);
if (r > 0) {
addfile_test_total_written += r;
TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written));
} else {
int e = evutil_socket_geterror(fd);
if (EVUTIL_ERR_RW_RETRIABLE(e))
return;
tt_fail_perror("write");
event_base_loopexit(addfile_test_event_base,NULL);
}
evbuffer_validate(b);
}
addfile_test_done_writing = 1;
return;
end:
event_base_loopexit(addfile_test_event_base,NULL);
}
static void
addfile_test_readcb(evutil_socket_t fd, short what, void *arg)
{
struct evbuffer *b = arg;
int e, r = 0;
do {
r = evbuffer_read(b, fd, 1024);
if (r > 0) {
addfile_test_total_read += r;
TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read));
}
} while (r > 0);
if (r < 0) {
e = evutil_socket_geterror(fd);
if (! EVUTIL_ERR_RW_RETRIABLE(e)) {
tt_fail_perror("read");
event_base_loopexit(addfile_test_event_base,NULL);
}
}
if (addfile_test_done_writing &&
addfile_test_total_read >= addfile_test_total_written) {
event_base_loopexit(addfile_test_event_base,NULL);
}
}
static void
test_evbuffer_add_file(void *ptr)
{
struct basic_test_data *testdata = ptr;
const char *impl = testdata->setup_data;
struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new();
char *tmpfilename = NULL;
char *data = NULL;
const char *expect_data;
size_t datalen, expect_len;
const char *compare;
int fd = -1;
int want_ismapping = -1, want_cansendfile = -1;
unsigned flags = 0;
int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
view_from_offset = 0;
struct evbuffer_file_segment *seg = NULL;
ev_off_t starting_offset = 0, mapping_len = -1;
ev_off_t segment_offset = 0, segment_len = -1;
struct event *rev=NULL, *wev=NULL;
struct event_base *base = testdata->base;
evutil_socket_t pair[2] = {-1, -1};
struct evutil_weakrand_state seed = { 123456789U };
tt_assert(impl);
if (strstr(impl, "nosegment")) {
use_segment = 0;
}
if (strstr(impl, "bigfile")) {
use_bigfile = 1;
}
if (strstr(impl, "map_offset")) {
map_from_offset = 1;
}
if (strstr(impl, "offset_in_segment")) {
view_from_offset = 1;
}
if (strstr(impl, "sendfile")) {
flags = EVBUF_FS_DISABLE_MMAP;
want_cansendfile = 1;
want_ismapping = 0;
} else if (strstr(impl, "mmap")) {
flags = EVBUF_FS_DISABLE_SENDFILE;
want_ismapping = 1;
want_cansendfile = 0;
} else if (strstr(impl, "linear")) {
flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
want_ismapping = 0;
want_cansendfile = 0;
} else if (strstr(impl, "default")) {
;
} else {
TT_DIE(("Didn't recognize the implementation"));
}
if (use_bigfile) {
unsigned int i;
datalen = 1024*512;
data = malloc(1024*512);
tt_assert(data);
for (i = 0; i < datalen; ++i)
data[i] = (char)evutil_weakrand_(&seed);
} else {
data = strdup("here is a relatively small string.");
tt_assert(data);
datalen = strlen(data);
}
fd = regress_make_tmpfile(data, datalen, &tmpfilename);
if (map_from_offset) {
starting_offset = datalen/4 + 1;
mapping_len = datalen / 2 - 1;
expect_data = data + starting_offset;
expect_len = mapping_len;
} else {
expect_data = data;
expect_len = datalen;
}
if (view_from_offset) {
tt_assert(use_segment);
segment_offset = expect_len / 3;
segment_len = expect_len / 2;
expect_data = expect_data + segment_offset;
expect_len = segment_len;
}
if (use_segment) {
seg = evbuffer_file_segment_new(fd, starting_offset,
mapping_len, flags);
tt_assert(seg);
if (want_ismapping >= 0) {
if (seg->is_mapping != (unsigned)want_ismapping)
tt_skip();
}
if (want_cansendfile >= 0) {
if (seg->can_sendfile != (unsigned)want_cansendfile)
tt_skip();
}
}
evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
#if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1)
tt_abort_msg("ersatz_socketpair failed");
#else
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
tt_abort_msg("socketpair failed");
#endif
evutil_make_socket_nonblocking(pair[0]);
evutil_make_socket_nonblocking(pair[1]);
tt_assert(fd != -1);
if (use_segment) {
tt_assert(evbuffer_add_file_segment(src, seg,
segment_offset, segment_len)!=-1);
} else {
tt_assert(evbuffer_add_file(src, fd, starting_offset,
mapping_len) != -1);
}
evbuffer_validate(src);
addfile_test_event_base = base;
wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST,
addfile_test_writecb, src);
rev = event_new(base, pair[1], EV_READ|EV_PERSIST,
addfile_test_readcb, dest);
event_add(wev, NULL);
event_add(rev, NULL);
event_base_dispatch(base);
evbuffer_validate(src);
evbuffer_validate(dest);
tt_assert(addfile_test_done_writing);
tt_int_op(addfile_test_total_written, ==, expect_len);
tt_int_op(addfile_test_total_read, ==, expect_len);
compare = (char *)evbuffer_pullup(dest, expect_len);
tt_assert(compare != NULL);
if (memcmp(compare, expect_data, expect_len)) {
tt_abort_msg("Data from add_file differs.");
}
evbuffer_validate(dest);
end:
if (data)
free(data);
if (seg)
evbuffer_file_segment_free(seg);
if (src)
evbuffer_free(src);
if (dest)
evbuffer_free(dest);
if (pair[0] >= 0)
evutil_closesocket(pair[0]);
if (pair[1] >= 0)
evutil_closesocket(pair[1]);
if (wev)
event_free(wev);
if (rev)
event_free(rev);
if (tmpfilename) {
unlink(tmpfilename);
free(tmpfilename);
}
}
static int file_segment_cleanup_cb_called_count = 0;
static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL;
static int file_segment_cleanup_cb_called_with_flags = 0;
static void* file_segment_cleanup_cb_called_with_arg = NULL;
static void
file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg)
{
++file_segment_cleanup_cb_called_count;
file_segment_cleanup_cb_called_with = seg;
file_segment_cleanup_cb_called_with_flags = flags;
file_segment_cleanup_cb_called_with_arg = arg;
}
static void
test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
{
char *tmpfilename = NULL;
int fd = -1;
struct evbuffer *evb = NULL;
struct evbuffer_file_segment *seg = NULL, *segptr;
char const* arg = "token";
fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename);
tt_int_op(fd, >=, 0);
evb = evbuffer_new();
tt_assert(evb);
segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0);
tt_assert(seg);
evbuffer_file_segment_add_cleanup_cb(
seg, &file_segment_cleanup_cp, (void*)arg);
tt_assert(fd != -1);
tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1);
evbuffer_validate(evb);
tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
evbuffer_file_segment_free(seg);
seg = NULL;
tt_int_op(file_segment_cleanup_cb_called_count, ==, 0);
evbuffer_free(evb);
evb = NULL;
tt_int_op(file_segment_cleanup_cb_called_count, ==, 1);
tt_assert(file_segment_cleanup_cb_called_with == segptr);
tt_assert(file_segment_cleanup_cb_called_with_flags == 0);
tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg);
end:
if (evb)
evbuffer_free(evb);
if (seg)
evbuffer_file_segment_free(seg);
if (tmpfilename) {
unlink(tmpfilename);
free(tmpfilename);
}
}
#ifndef EVENT__DISABLE_MM_REPLACEMENT
static void *
failing_malloc(size_t how_much)
{
errno = ENOMEM;
return NULL;
}
#endif
static void
test_evbuffer_readln(void *ptr)
{
struct evbuffer *evb = evbuffer_new();
struct evbuffer *evb_tmp = evbuffer_new();
const char *s;
char *cp = NULL;
size_t sz;
#define tt_line_eq(content) \
TT_STMT_BEGIN \
if (!cp || sz != strlen(content) || strcmp(cp, content)) { \
TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
} \
TT_STMT_END
s = "complex silly newline\r\n\n\r\n\n\rmore\0\n";
evbuffer_add(evb, s, strlen(s)+2);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
tt_line_eq("complex silly newline");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6))
tt_abort_msg("Not as expected");
tt_uint_op(evbuffer_get_length(evb), ==, 0);
evbuffer_validate(evb);
s = "\nno newline";
evbuffer_add(evb, s, strlen(s));
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
tt_line_eq("");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
tt_assert(!cp);
evbuffer_validate(evb);
evbuffer_drain(evb, evbuffer_get_length(evb));
tt_assert(evbuffer_get_length(evb) == 0);
evbuffer_validate(evb);
s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n";
evbuffer_add(evb, s, strlen(s));
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
tt_line_eq("Line with\rin the middle");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
tt_line_eq("Line with good crlf");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
tt_line_eq("");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
tt_line_eq("final");
s = "x";
evbuffer_validate(evb);
evbuffer_add(evb, s, 1);
evbuffer_validate(evb);
free(cp);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
tt_assert(!cp);
evbuffer_validate(evb);
s = " and a bad crlf\nand a good one\r\n\r\nMore\r";
evbuffer_add(evb, s, strlen(s));
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("x and a bad crlf\nand a good one");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_assert(!cp);
evbuffer_validate(evb);
evbuffer_add(evb, "\n", 1);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("More");
free(cp);
tt_assert(evbuffer_get_length(evb) == 0);
evbuffer_validate(evb);
s = "An internal CR\r is not an eol\r\nNor is a lack of one";
evbuffer_add(evb, s, strlen(s));
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("An internal CR\r is not an eol");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_assert(!cp);
evbuffer_validate(evb);
evbuffer_add(evb, "\r\n", 2);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("Nor is a lack of one");
free(cp);
tt_assert(evbuffer_get_length(evb) == 0);
evbuffer_validate(evb);
s = "An\rand a nl\n\nText";
evbuffer_add(evb, s, strlen(s));
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_line_eq("An\rand a nl");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_line_eq("");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_assert(!cp);
free(cp);
evbuffer_add(evb, "\n", 1);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_line_eq("Text");
free(cp);
evbuffer_validate(evb);
tt_int_op(evbuffer_get_length(evb), ==, 0);
{
char x[] =
"NUL\n\0\0"
"The all-zeros character which may serve\0"
"to accomplish time fill\0and media fill";
evbuffer_add(evb, x, sizeof(x)-1);
}
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
tt_line_eq("NUL\n");
free(cp);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
tt_line_eq("");
free(cp);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
tt_line_eq("The all-zeros character which may serve");
free(cp);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
tt_line_eq("to accomplish time fill");
free(cp);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL);
tt_ptr_op(cp, ==, NULL);
evbuffer_drain(evb, -1);
s = " and a bad crlf\nand a good one\r";
evbuffer_add(evb_tmp, s, strlen(s));
evbuffer_validate(evb);
evbuffer_add_buffer(evb, evb_tmp);
evbuffer_validate(evb);
s = "\n\r";
evbuffer_add(evb_tmp, s, strlen(s));
evbuffer_validate(evb);
evbuffer_add_buffer(evb, evb_tmp);
evbuffer_validate(evb);
s = "\nMore\r";
evbuffer_add(evb_tmp, s, strlen(s));
evbuffer_validate(evb);
evbuffer_add_buffer(evb, evb_tmp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq(" and a bad crlf\nand a good one");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("");
free(cp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_assert(!cp);
free(cp);
evbuffer_validate(evb);
evbuffer_add(evb, "\n", 1);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
tt_line_eq("More");
free(cp); cp = NULL;
evbuffer_validate(evb);
tt_assert(evbuffer_get_length(evb) == 0);
s = "one line\ntwo line\nblue line";
evbuffer_add(evb_tmp, s, strlen(s));
evbuffer_validate(evb);
evbuffer_add_buffer(evb, evb_tmp);
evbuffer_validate(evb);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_line_eq("one line");
free(cp); cp = NULL;
evbuffer_validate(evb);
#ifndef EVENT__DISABLE_MM_REPLACEMENT
event_set_mem_functions(failing_malloc, realloc, free);
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_assert(cp == NULL);
evbuffer_validate(evb);
event_set_mem_functions(malloc, realloc, free);
#endif
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
tt_line_eq("two line");
free(cp); cp = NULL;
evbuffer_validate(evb);
end:
evbuffer_free(evb);
evbuffer_free(evb_tmp);
if (cp) free(cp);
}
static void
test_evbuffer_search_eol(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
struct evbuffer_ptr ptr1, ptr2;
const char *s;
size_t eol_len;
s = "string! \r\n\r\nx\n";
evbuffer_add(buf, s, strlen(s));
eol_len = -1;
ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF);
tt_int_op(ptr1.pos, ==, 8);
tt_int_op(eol_len, ==, 2);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
tt_int_op(ptr2.pos, ==, 8);
tt_int_op(eol_len, ==, 2);
evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
tt_int_op(ptr2.pos, ==, 9);
tt_int_op(eol_len, ==, 1);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT);
tt_int_op(ptr2.pos, ==, 10);
tt_int_op(eol_len, ==, 2);
eol_len = -1;
ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF);
tt_int_op(ptr1.pos, ==, 9);
tt_int_op(eol_len, ==, 1);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
tt_int_op(ptr2.pos, ==, 9);
tt_int_op(eol_len, ==, 1);
evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
tt_int_op(ptr2.pos, ==, 11);
tt_int_op(eol_len, ==, 1);
tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
eol_len = -1;
ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
tt_int_op(ptr2.pos, ==, -1);
tt_int_op(eol_len, ==, 0);
end:
evbuffer_free(buf);
}
static void
test_evbuffer_iterative(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
unsigned i, j, sum, n;
sum = 0;
n = 0;
for (i = 0; i < 1000; ++i) {
for (j = 1; j < strlen(abc); ++j) {
char format[32];
evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j);
evbuffer_add_printf(buf, format, abc);
if ((n % 337) == 0)
evbuffer_validate(buf);
sum += j;
n++;
}
}
evbuffer_validate(buf);
tt_uint_op(sum, ==, evbuffer_get_length(buf));
{
size_t a,w,u;
a=w=u=0;
evbuffer_get_waste(buf, &a, &w, &u);
if (0)
printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
(unsigned)a, (unsigned)w, (unsigned)u);
tt_assert( ((double)w)/a < .125);
}
end:
evbuffer_free(buf);
}
static void
test_evbuffer_find(void *ptr)
{
u_char* p;
const char* test1 = "1234567890\r\n";
const char* test2 = "1234567890\r";
#define EVBUFFER_INITIAL_LENGTH 256
char test3[EVBUFFER_INITIAL_LENGTH];
unsigned int i;
struct evbuffer * buf = evbuffer_new();
tt_assert(buf);
evbuffer_add(buf, (u_char*)test1, strlen(test1));
evbuffer_validate(buf);
evbuffer_drain(buf, strlen(test1));
evbuffer_validate(buf);
evbuffer_add(buf, (u_char*)test2, strlen(test2));
evbuffer_validate(buf);
p = evbuffer_find(buf, (u_char*)"\r\n", 2);
tt_want(p == NULL);
evbuffer_drain(buf, strlen(test2));
evbuffer_validate(buf);
for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
test3[i] = 'a';
test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
evbuffer_validate(buf);
p = evbuffer_find(buf, (u_char *)"xy", 2);
tt_want(p == NULL);
p = evbuffer_find(buf, (u_char *)"ax", 2);
tt_assert(p != NULL);
tt_want(strncmp((char*)p, "ax", 2) == 0);
end:
if (buf)
evbuffer_free(buf);
}
static void
test_evbuffer_ptr_set(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
struct evbuffer_ptr pos;
struct evbuffer_iovec v[1];
tt_assert(buf);
tt_int_op(evbuffer_get_length(buf), ==, 0);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
tt_assert(pos.pos == 0);
tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1);
tt_assert(pos.pos == -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1);
tt_assert(pos.pos == -1);
evbuffer_reserve_space(buf, 5000, v, 1);
v[0].iov_len = 5000;
memset(v[0].iov_base, 1, v[0].iov_len);
evbuffer_commit_space(buf, v, 1);
evbuffer_validate(buf);
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);
evbuffer_validate(buf);
tt_int_op(evbuffer_get_length(buf), ==, 12000);
tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
tt_assert(pos.pos == -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
tt_assert(pos.pos == 0);
tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
tt_assert(pos.pos == 0);
tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0);
tt_assert(pos.pos == 10000);
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
tt_assert(pos.pos == 11000);
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
tt_assert(pos.pos == 12000);
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
tt_assert(pos.pos == -1);
end:
if (buf)
evbuffer_free(buf);
}
static void
test_evbuffer_search(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
struct evbuffer *tmp = evbuffer_new();
struct evbuffer_ptr pos, end;
tt_assert(buf);
tt_assert(tmp);
pos = evbuffer_search(buf, "x", 1, NULL);
tt_int_op(pos.pos, ==, -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search(buf, "x", 1, &pos);
tt_int_op(pos.pos, ==, -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "x", 1, &pos, &pos);
tt_int_op(pos.pos, ==, -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "x", 1, &pos, NULL);
tt_int_op(pos.pos, ==, -1);
evbuffer_add_printf(tmp, "hello");
evbuffer_add_buffer(buf, tmp);
evbuffer_add_printf(tmp, "foo");
evbuffer_add_buffer(buf, tmp);
evbuffer_add_printf(tmp, "cat");
evbuffer_add_buffer(buf, tmp);
evbuffer_add_printf(tmp, "attack");
evbuffer_add_buffer(buf, tmp);
pos = evbuffer_search(buf, "attack", 6, NULL);
tt_int_op(pos.pos, ==, 11);
pos = evbuffer_search(buf, "attacker", 8, NULL);
tt_int_op(pos.pos, ==, -1);
pos = evbuffer_search(buf, "oc", 2, NULL);
tt_int_op(pos.pos, ==, 7);
pos = evbuffer_search(buf, "cat", 3, &pos);
tt_int_op(pos.pos, ==, 8);
pos = evbuffer_search(buf, "tacking", 7, &pos);
tt_int_op(pos.pos, ==, -1);
evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET);
pos = evbuffer_search(buf, "foo", 3, &pos);
tt_int_op(pos.pos, ==, 5);
evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD);
pos = evbuffer_search(buf, "tat", 3, &pos);
tt_int_op(pos.pos, ==, 10);
evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
tt_int_op(pos.pos, ==, 5);
pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
tt_int_op(pos.pos, ==, 5);
pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
tt_int_op(pos.pos, ==, -1);
pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
tt_int_op(pos.pos, ==, -1);
tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "attack", 6, NULL, &end);
tt_int_op(pos.pos, ==, 11);
tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
tt_int_op(pos.pos, ==, 11);
tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
tt_int_op(pos.pos, ==, -1);
tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL);
tt_int_op(pos.pos, ==, -1);
end:
if (buf)
evbuffer_free(buf);
if (tmp)
evbuffer_free(tmp);
}
static void
log_change_callback(struct evbuffer *buffer,
const struct evbuffer_cb_info *cbinfo,
void *arg)
{
size_t old_len = cbinfo->orig_size;
size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
struct evbuffer *out = arg;
evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len,
(unsigned long)new_len);
}
static void
self_draining_callback(struct evbuffer *evbuffer, size_t old_len,
size_t new_len, void *arg)
{
if (new_len > old_len)
evbuffer_drain(evbuffer, new_len);
}
static void
test_evbuffer_callbacks(void *ptr)
{
struct evbuffer *buf = evbuffer_new();
struct evbuffer *buf_out1 = evbuffer_new();
struct evbuffer *buf_out2 = evbuffer_new();
struct evbuffer_cb_entry *cb1, *cb2;
tt_assert(buf);
tt_assert(buf_out1);
tt_assert(buf_out2);
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
evbuffer_validate(buf);
evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
evbuffer_drain(buf, 10);
evbuffer_validate(buf);
evbuffer_prepend(buf, "Hello", 5);
evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL);
evbuffer_remove_cb_entry(buf, cb1);
evbuffer_validate(buf);
evbuffer_drain(buf, evbuffer_get_length(buf)); ;
tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
evbuffer_add(buf, "X", 1);
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
evbuffer_validate(buf);
tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==,
"0->36; 36->26; 26->31; 31->38; ");
tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==,
"0->36; 31->38; 38->0; 0->1; ");
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
tt_assert(cb1 != NULL);
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
tt_assert(cb2 != NULL);
evbuffer_setcb(buf, self_draining_callback, NULL);
evbuffer_add_printf(buf, "This should get drained right away.");
tt_uint_op(evbuffer_get_length(buf), ==, 0);
tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
evbuffer_setcb(buf, NULL, NULL);
evbuffer_add_printf(buf, "This will not.");
tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not.");
evbuffer_validate(buf);
evbuffer_drain(buf, evbuffer_get_length(buf));
evbuffer_validate(buf);
#if 0
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
evbuffer_cb_suspend(buf,cb2);
evbuffer_prepend(buf,"Hello world",11);
evbuffer_validate(buf);
evbuffer_cb_suspend(buf,cb1);
evbuffer_add(buf,"more",4);
evbuffer_cb_unsuspend(buf,cb2);
evbuffer_drain(buf, 4);
evbuffer_cb_unsuspend(buf,cb1);
evbuffer_drain(buf, evbuffer_get_length(buf));
tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
"0->11; 11->11; 11->0; ");
tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
"0->15; 15->11; 11->0; ");
#endif
end:
if (buf)
evbuffer_free(buf);
if (buf_out1)
evbuffer_free(buf_out1);
if (buf_out2)
evbuffer_free(buf_out2);
}
static int ref_done_cb_called_count = 0;
static void *ref_done_cb_called_with = NULL;
static const void *ref_done_cb_called_with_data = NULL;
static size_t ref_done_cb_called_with_len = 0;
static void ref_done_cb(const void *data, size_t len, void *info)
{
++ref_done_cb_called_count;
ref_done_cb_called_with = info;
ref_done_cb_called_with_data = data;
ref_done_cb_called_with_len = len;
}
static void
test_evbuffer_add_reference(void *ptr)
{
const char chunk1[] = "If you have found the answer to such a problem";
const char chunk2[] = "you ought to write it up for publication";
char tmp[16];
size_t len1 = strlen(chunk1), len2=strlen(chunk2);
struct evbuffer *buf1 = NULL, *buf2 = NULL;
buf1 = evbuffer_new();
tt_assert(buf1);
evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111);
evbuffer_add(buf1, ", ", 2);
evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222);
tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
tt_int_op(memcmp(tmp, " have", 5), ==, 0);
tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
evbuffer_validate(buf1);
evbuffer_drain(buf1, 7);
evbuffer_drain(buf1, len1-11-1);
tt_int_op(ref_done_cb_called_count, ==, 0);
evbuffer_remove(buf1, tmp, 1);
tt_int_op(tmp[0], ==, 'm');
tt_assert(ref_done_cb_called_with == (void*)111);
tt_assert(ref_done_cb_called_with_data == chunk1);
tt_assert(ref_done_cb_called_with_len == len1);
tt_int_op(ref_done_cb_called_count, ==, 1);
evbuffer_validate(buf1);
evbuffer_drain(buf1, 6);
buf2 = evbuffer_new();
tt_assert(buf2);
tt_int_op(ref_done_cb_called_count, ==, 1);
evbuffer_add(buf2, "I ", 2);
evbuffer_add_buffer(buf2, buf1);
tt_int_op(ref_done_cb_called_count, ==, 1);
evbuffer_remove(buf2, tmp, 16);
tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0);
evbuffer_drain(buf2, evbuffer_get_length(buf2));
tt_int_op(ref_done_cb_called_count, ==, 2);
tt_assert(ref_done_cb_called_with == (void*)222);
evbuffer_validate(buf2);
evbuffer_add(buf1, "You shake and shake the ", 24);
evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
(void*)3333);
evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35);
evbuffer_free(buf1);
buf1 = NULL;
tt_int_op(ref_done_cb_called_count, ==, 3);
tt_assert(ref_done_cb_called_with == (void*)3333);
end:
if (buf1)
evbuffer_free(buf1);
if (buf2)
evbuffer_free(buf2);
}
static void
test_evbuffer_multicast(void *ptr)
{
const char chunk1[] = "If you have found the answer to such a problem";
const char chunk2[] = "you ought to write it up for publication";
char tmp[16];
size_t len1 = strlen(chunk1), len2=strlen(chunk2);
struct evbuffer *buf1 = NULL, *buf2 = NULL;
buf1 = evbuffer_new();
tt_assert(buf1);
evbuffer_add(buf1, chunk1, len1);
evbuffer_add(buf1, ", ", 2);
evbuffer_add(buf1, chunk2, len2);
tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
buf2 = evbuffer_new();
tt_assert(buf2);
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1);
tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1);
tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1));
tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
tt_int_op(memcmp(tmp, " have", 5), ==, 0);
tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
evbuffer_validate(buf1);
tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
tt_int_op(evbuffer_remove(buf2, tmp, 5), ==, 5);
tt_int_op(memcmp(tmp, " have", 5), ==, 0);
tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0);
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
evbuffer_validate(buf2);
evbuffer_free(buf1);
buf1 = NULL;
tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
tt_int_op(memcmp(tmp, "I have", 6), ==, 0);
tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6);
tt_int_op(memcmp(tmp, " foun", 6), ==, 0);
end:
if (buf1)
evbuffer_free(buf1);
if (buf2)
evbuffer_free(buf2);
}
static void
test_evbuffer_multicast_drain(void *ptr)
{
const char chunk1[] = "If you have found the answer to such a problem";
const char chunk2[] = "you ought to write it up for publication";
size_t len1 = strlen(chunk1), len2=strlen(chunk2);
struct evbuffer *buf1 = NULL, *buf2 = NULL;
buf1 = evbuffer_new();
tt_assert(buf1);
evbuffer_add(buf1, chunk1, len1);
evbuffer_add(buf1, ", ", 2);
evbuffer_add(buf1, chunk2, len2);
tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
buf2 = evbuffer_new();
tt_assert(buf2);
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0);
tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0);
evbuffer_validate(buf1);
evbuffer_validate(buf2);
end:
if (buf1)
evbuffer_free(buf1);
if (buf2)
evbuffer_free(buf2);
}
static void
test_evbuffer_prepend(void *ptr)
{
struct evbuffer *buf1 = NULL, *buf2 = NULL;
char tmp[128];
int n;
buf1 = evbuffer_new();
tt_assert(buf1);
evbuffer_prepend(buf1, "This string has 29 characters", 29);
evbuffer_validate(buf1);
evbuffer_prepend(buf1, "Short.", 6);
evbuffer_validate(buf1);
evbuffer_drain(buf1, 6+11);
evbuffer_prepend(buf1, "it", 2);
evbuffer_validate(buf1);
tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign,
"it has", 6));
evbuffer_prepend(buf1, "It is no longer true to say ", 28);
evbuffer_validate(buf1);
n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
tt_int_op(n, >=, 0);
tmp[n]='\0';
tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
buf2 = evbuffer_new();
tt_assert(buf2);
n = 999;
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
evbuffer_prepend_buffer(buf2, buf1);
evbuffer_validate(buf2);
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
evbuffer_prepend_buffer(buf2, buf1);
evbuffer_validate(buf2);
evbuffer_validate(buf1);
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
tt_int_op(n, >=, 0);
tmp[n]='\0';
tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
end:
if (buf1)
evbuffer_free(buf1);
if (buf2)
evbuffer_free(buf2);
}
static void
test_evbuffer_peek_first_gt(void *info)
{
struct evbuffer *buf = NULL, *tmp_buf = NULL;
struct evbuffer_ptr ptr;
struct evbuffer_iovec v[2];
buf = evbuffer_new();
tmp_buf = evbuffer_new();
evbuffer_add_printf(tmp_buf, "Contents of chunk 100\n");
evbuffer_add_buffer(buf, tmp_buf);
evbuffer_add_printf(tmp_buf, "Contents of chunk 1\n");
evbuffer_add_buffer(buf, tmp_buf);
evbuffer_ptr_set(buf, &ptr, 0, EVBUFFER_PTR_SET);
tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2);
tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2);
evbuffer_ptr_set(buf, &ptr, 20, EVBUFFER_PTR_ADD);
tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2);
tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2);
tt_int_op(evbuffer_peek(buf, 2, &ptr, NULL, 0), ==, 1);
tt_int_op(evbuffer_peek(buf, 2, &ptr, v, 2), ==, 1);
tt_int_op(evbuffer_peek(buf, 3, &ptr, NULL, 0), ==, 2);
tt_int_op(evbuffer_peek(buf, 3, &ptr, v, 2), ==, 2);
end:
if (buf)
evbuffer_free(buf);
if (tmp_buf)
evbuffer_free(tmp_buf);
}
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)))
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);
}
i = evbuffer_peek(buf, -1, NULL, NULL, 0);
tt_int_op(i, ==, 16);
i = evbuffer_peek(buf, -1, NULL, v, 20);
tt_int_op(i, ==, 16);
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");
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);
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);
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);
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);
memset(v, 0, sizeof(v));
i = evbuffer_peek(buf, 65536, NULL, v, 20);
tt_int_op(i, ==, 16);
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);
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);
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");
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");
memset(v, 0, sizeof(v));
tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
i = evbuffer_peek(buf, 44, &ptr, v, 20);
tt_int_op(i, ==, 0);
tt_assert(v[0].iov_base == NULL);
end:
if (buf)
evbuffer_free(buf);
if (tmp_buf)
evbuffer_free(tmp_buf);
}
static void
test_evbuffer_freeze(void *ptr)
{
struct evbuffer *buf = NULL, *tmp_buf=NULL;
const char string[] =
"I've known the wind by water banks to shake\n"
"The late leaves down, which frozen where they fell\n"
"And held in ice as dancers in a spell\n"
"Fluttered all winter long into a lake...";
const int start = !strcmp(ptr, "start");
char *cp;
char charbuf[128];
int r;
size_t orig_length;
struct evbuffer_iovec v[1];
if (!start)
tt_str_op(ptr, ==, "end");
buf = evbuffer_new();
tmp_buf = evbuffer_new();
tt_assert(tmp_buf);
evbuffer_add(buf, string, strlen(string));
evbuffer_freeze(buf, start);
#define FREEZE_EQ(a, startcase, endcase) \
do { \
if (start) { \
tt_int_op((a), ==, (startcase)); \
} else { \
tt_int_op((a), ==, (endcase)); \
} \
} while (0)
orig_length = evbuffer_get_length(buf);
r = evbuffer_add(buf, "abc", 0);
FREEZE_EQ(r, 0, -1);
r = evbuffer_reserve_space(buf, 10, v, 1);
FREEZE_EQ(r, 1, -1);
if (r == 1) {
memset(v[0].iov_base, 'X', 10);
v[0].iov_len = 10;
}
r = evbuffer_commit_space(buf, v, 1);
FREEZE_EQ(r, 0, -1);
r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
FREEZE_EQ(r, 0, -1);
r = evbuffer_add_printf(buf, "Hello %s", "world");
FREEZE_EQ(r, 11, -1);
if (!start)
tt_int_op(orig_length, ==, evbuffer_get_length(buf));
orig_length = evbuffer_get_length(buf);
r = evbuffer_remove(buf, charbuf, 1);
FREEZE_EQ(r, -1, 1);
r = evbuffer_drain(buf, 3);
FREEZE_EQ(r, -1, 0);
r = evbuffer_prepend(buf, "dummy", 5);
FREEZE_EQ(r, -1, 0);
cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF);
FREEZE_EQ(cp==NULL, 1, 0);
if (cp)
free(cp);
if (start)
tt_int_op(orig_length, ==, evbuffer_get_length(buf));
end:
if (buf)
evbuffer_free(buf);
if (tmp_buf)
evbuffer_free(tmp_buf);
}
static void
test_evbuffer_add_iovec(void * ptr)
{
struct evbuffer * buf = NULL;
struct evbuffer_iovec vec[4];
const char * data[] = {
"Guilt resembles a sword with two edges.",
"On the one hand, it cuts for Justice, imposing practical morality upon those who fear it.",
"Conscience does not always adhere to rational judgment.",
"Guilt is always a self-imposed burden, but it is not always rightly imposed."
};
size_t expected_length = 0;
size_t returned_length = 0;
int i;
buf = evbuffer_new();
tt_assert(buf);
for (i = 0; i < 4; i++) {
vec[i].iov_len = strlen(data[i]);
vec[i].iov_base = (char*) data[i];
expected_length += vec[i].iov_len;
}
returned_length = evbuffer_add_iovec(buf, vec, 4);
tt_int_op(returned_length, ==, evbuffer_get_length(buf));
tt_int_op(evbuffer_get_length(buf), ==, expected_length);
for (i = 0; i < 4; i++) {
char charbuf[1024];
memset(charbuf, 0, 1024);
evbuffer_remove(buf, charbuf, strlen(data[i]));
tt_assert(strcmp(charbuf, data[i]) == 0);
}
tt_assert(evbuffer_get_length(buf) == 0);
end:
if (buf) {
evbuffer_free(buf);
}
}
static void
test_evbuffer_copyout(void *dummy)
{
const char string[] =
"Still they skirmish to and fro, men my messmates on the snow "
"When we headed off the aurochs turn for turn; "
"When the rich Allobrogenses never kept amanuenses, "
"And our only plots were piled in lakes at Berne.";
char tmp[1024];
struct evbuffer_ptr ptr;
struct evbuffer *buf;
(void)dummy;
buf = evbuffer_new();
tt_assert(buf);
tt_int_op(strlen(string), ==, 206);
evbuffer_add_reference(buf, string, 80, no_cleanup, NULL);
evbuffer_add_reference(buf, string+80, 80, no_cleanup, NULL);
evbuffer_add(buf, string+160, strlen(string)-160);
tt_int_op(206, ==, evbuffer_get_length(buf));
tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10));
tt_int_op(0, ==, memcmp(tmp, "Still they", 10));
memset(tmp, 0, sizeof(tmp));
tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100));
tt_int_op(0, ==, memcmp(tmp, string, 100));
memset(tmp, 0, sizeof(tmp));
tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230));
tt_int_op(0, ==, memcmp(tmp, string, 206));
tt_int_op(206, ==, evbuffer_get_length(buf));
evbuffer_ptr_set(buf, &ptr, 15, EVBUFFER_PTR_SET);
memset(tmp, 0, sizeof(tmp));
tt_int_op(10, ==, evbuffer_copyout_from(buf, &ptr, tmp, 10));
tt_int_op(0, ==, memcmp(tmp, "mish to an", 10));
memset(tmp, 0, sizeof(tmp));
tt_int_op(65, ==, evbuffer_copyout_from(buf, &ptr, tmp, 65));
tt_int_op(0, ==, memcmp(tmp, string+15, 65));
memset(tmp, 0, sizeof(tmp));
tt_int_op(90, ==, evbuffer_copyout_from(buf, &ptr, tmp, 90));
tt_int_op(0, ==, memcmp(tmp, string+15, 90));
memset(tmp, 0, sizeof(tmp));
tt_int_op(160, ==, evbuffer_copyout_from(buf, &ptr, tmp, 160));
tt_int_op(0, ==, memcmp(tmp, string+15, 160));
memset(tmp, 0, sizeof(tmp));
tt_int_op(206-15, ==, evbuffer_copyout_from(buf, &ptr, tmp, 999));
tt_int_op(0, ==, memcmp(tmp, string+15, 206-15));
tt_int_op(206, ==, evbuffer_get_length(buf));
end:
if (buf)
evbuffer_free(buf);
}
static void *
setup_passthrough(const struct testcase_t *testcase)
{
return testcase->setup_data;
}
static int
cleanup_passthrough(const struct testcase_t *testcase, void *ptr)
{
(void) ptr;
return 1;
}
static const struct testcase_setup_t nil_setup = {
setup_passthrough,
cleanup_passthrough
};
struct testcase_t evbuffer_testcases[] = {
{ "evbuffer", test_evbuffer, 0, NULL, NULL },
{ "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
{ "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
{ "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
{ "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" },
{ "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" },
{ "expand", test_evbuffer_expand, 0, NULL, NULL },
{ "reference", test_evbuffer_reference, 0, NULL, NULL },
{ "iterative", test_evbuffer_iterative, 0, NULL, NULL },
{ "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
{ "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
{ "find", test_evbuffer_find, 0, NULL, NULL },
{ "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
{ "search", test_evbuffer_search, 0, NULL, NULL },
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
{ "multicast", test_evbuffer_multicast, 0, NULL, NULL },
{ "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
{ "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL },
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
{ "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL},
{ "copyout", test_evbuffer_copyout, 0, NULL, NULL},
{ "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL },
#define ADDFILE_TEST(name, parameters) \
{ name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \
&basic_setup, (void*)(parameters) }
#define ADDFILE_TEST_GROUP(name, parameters) \
ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \
ADDFILE_TEST(name "_mmap", "mmap " parameters), \
ADDFILE_TEST(name "_linear", "linear " parameters)
ADDFILE_TEST_GROUP("add_file", ""),
ADDFILE_TEST("add_file_nosegment", "default nosegment"),
ADDFILE_TEST_GROUP("add_big_file", "bigfile"),
ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"),
ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"),
ADDFILE_TEST("add_file_offset_nosegment",
"default nosegment bigfile map_offset"),
ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"),
ADDFILE_TEST_GROUP("add_file_offset3",
"bigfile offset_in_segment map_offset"),
END_OF_TESTCASES
};