2009-02-01 01:07:12 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
|
2012-02-10 17:29:53 -05:00
|
|
|
* Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
|
2009-02-01 01:07:12 +00:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2012-01-24 16:08:00 -05:00
|
|
|
#include "util-internal.h"
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifdef _WIN32
|
2009-02-01 01:07:12 +00:00
|
|
|
#include <winsock2.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2010-07-07 16:45:03 -04:00
|
|
|
#include "event2/event-config.h"
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifdef EVENT__HAVE_SYS_TIME_H
|
2009-02-01 01:07:12 +00:00
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
#include <sys/queue.h>
|
2011-05-25 19:50:56 -04:00
|
|
|
#ifndef _WIN32
|
2009-02-01 01:07:12 +00:00
|
|
|
#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 "evbuffer-internal.h"
|
|
|
|
#include "log-internal.h"
|
|
|
|
|
|
|
|
#include "regress.h"
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
/* Validates that an evbuffer is good. Returns false if it isn't, true if it
|
|
|
|
* is*/
|
|
|
|
static int
|
2012-02-29 15:07:32 -05:00
|
|
|
evbuffer_validate_(struct evbuffer *buf)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
2010-03-10 23:28:51 -05:00
|
|
|
struct evbuffer_chain *chain;
|
2009-02-01 01:07:12 +00:00
|
|
|
size_t sum = 0;
|
2010-03-26 23:18:40 -04:00
|
|
|
int found_last_with_datap = 0;
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
if (buf->first == NULL) {
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(buf->last == NULL);
|
|
|
|
tt_assert(buf->total_len == 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
chain = buf->first;
|
2010-03-26 23:18:40 -04:00
|
|
|
|
|
|
|
tt_assert(buf->last_with_datap);
|
|
|
|
if (buf->last_with_datap == &buf->first)
|
|
|
|
found_last_with_datap = 1;
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
while (chain != NULL) {
|
2010-03-26 23:18:40 -04:00
|
|
|
if (&chain->next == buf->last_with_datap)
|
|
|
|
found_last_with_datap = 1;
|
2009-02-01 01:07:12 +00:00
|
|
|
sum += chain->off;
|
|
|
|
if (chain->next == NULL) {
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(buf->last == chain);
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(chain->buffer_len >= chain->misalign + chain->off);
|
2009-02-01 01:07:12 +00:00
|
|
|
chain = chain->next;
|
|
|
|
}
|
|
|
|
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
if (buf->first)
|
2010-03-26 23:18:40 -04:00
|
|
|
tt_assert(*buf->last_with_datap);
|
|
|
|
|
|
|
|
if (*buf->last_with_datap) {
|
|
|
|
chain = *buf->last_with_datap;
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
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;
|
|
|
|
}
|
2010-03-26 23:18:40 -04:00
|
|
|
} else {
|
|
|
|
tt_assert(buf->last_with_datap == &buf->first);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
}
|
2010-03-26 23:18:40 -04:00
|
|
|
tt_assert(found_last_with_datap);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(sum == buf->total_len);
|
|
|
|
return 1;
|
|
|
|
end:
|
|
|
|
return 0;
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
|
|
|
|
2010-03-30 16:47:37 -04:00
|
|
|
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;
|
|
|
|
/* skip empty at start */
|
|
|
|
while (chain && chain->off==0) {
|
|
|
|
++n;
|
|
|
|
a += chain->buffer_len;
|
|
|
|
chain = chain->next;
|
|
|
|
}
|
|
|
|
/* first nonempty chain: stuff at the end only is wasted. */
|
|
|
|
if (chain) {
|
|
|
|
++n;
|
|
|
|
a += chain->buffer_len;
|
|
|
|
u += chain->off;
|
|
|
|
if (chain->next && chain->next->off)
|
2010-11-01 13:43:43 -04:00
|
|
|
w += (size_t)(chain->buffer_len - (chain->misalign + chain->off));
|
2010-03-30 16:47:37 -04:00
|
|
|
chain = chain->next;
|
|
|
|
}
|
|
|
|
/* subsequent nonempty chains */
|
|
|
|
while (chain && chain->off) {
|
|
|
|
++n;
|
|
|
|
a += chain->buffer_len;
|
2010-11-01 13:43:43 -04:00
|
|
|
w += (size_t)chain->misalign;
|
2010-03-30 16:47:37 -04:00
|
|
|
u += chain->off;
|
|
|
|
if (chain->next && chain->next->off)
|
2010-11-01 13:43:43 -04:00
|
|
|
w += (size_t) (chain->buffer_len - (chain->misalign + chain->off));
|
2010-03-30 16:47:37 -04:00
|
|
|
chain = chain->next;
|
|
|
|
}
|
|
|
|
/* subsequent empty chains */
|
|
|
|
while (chain) {
|
|
|
|
++n;
|
|
|
|
a += chain->buffer_len;
|
|
|
|
}
|
|
|
|
*allocatedp = a;
|
|
|
|
*wastedp = w;
|
|
|
|
*usedp = u;
|
|
|
|
}
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
#define evbuffer_validate(buf) \
|
2012-02-29 15:07:32 -05:00
|
|
|
TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
|
2009-02-01 01:07:22 +00:00
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
static void
|
2009-02-01 01:07:22 +00:00
|
|
|
test_evbuffer(void *ptr)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) == 7);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
evbuffer_add_buffer(evb, evb_two);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
evbuffer_drain(evb, strlen("hello/"));
|
|
|
|
evbuffer_validate(evb);
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) == 1);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
evbuffer_add_printf(evb_two, "%s", "/hello");
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
evbuffer_add_buffer(evb, evb_two);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb_two) == 0);
|
|
|
|
tt_assert(evbuffer_get_length(evb) == 7);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
evbuffer_add(evb, buffer, sizeof(buffer));
|
|
|
|
evbuffer_validate(evb);
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) == 7 + 512);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
tmp = (char *)evbuffer_pullup(evb, 7 + 512);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(tmp);
|
|
|
|
tt_assert(!strncmp(tmp, "1/hello", 7));
|
|
|
|
tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
|
2009-02-01 01:07:12 +00:00
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
|
2009-02-01 01:07:12 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb_two) == 0);
|
|
|
|
tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
/* test remove buffer */
|
2009-11-05 21:22:23 +00:00
|
|
|
sz_tmp = (size_t)(sizeof(buffer)*2.5);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_remove_buffer(evb, evb_two, sz_tmp);
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
|
|
|
|
tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
if (memcmp(evbuffer_pullup(
|
|
|
|
evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
|
|
|
|
memcmp(evbuffer_pullup(
|
|
|
|
evb_two, -1), buffer, sizeof(buffer) != 0))
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_abort_msg("Pullup did not preserve content");
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
/* testing one-vector reserve and commit */
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
2009-05-19 21:39:35 +00:00
|
|
|
struct evbuffer_iovec v[1];
|
|
|
|
char *buf;
|
|
|
|
int i, j, r;
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 3; ++i) {
|
2009-05-19 21:39:35 +00:00
|
|
|
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);
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
2009-05-19 21:39:35 +00:00
|
|
|
buf = v[0].iov_base;
|
2009-02-01 01:07:12 +00:00
|
|
|
for (j = 0; j < 10000; ++j) {
|
|
|
|
buf[j] = j;
|
|
|
|
}
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) >= 10000);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
evbuffer_drain(evb, j * 5000);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
end:
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_free(evb);
|
|
|
|
evbuffer_free(evb_two);
|
|
|
|
}
|
|
|
|
|
2011-11-01 13:44:40 -07:00
|
|
|
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);
|
|
|
|
|
|
|
|
/* setup the buffers */
|
|
|
|
/* we need more data in src than we will move later */
|
2011-11-02 15:19:05 -07:00
|
|
|
evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
|
|
|
|
evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
|
2011-11-01 13:44:40 -07:00
|
|
|
/* we need one buffer in dst and one empty buffer at the end */
|
|
|
|
evbuffer_add(dst, buf, sizeof(buf));
|
|
|
|
evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
|
|
|
|
|
|
|
|
evbuffer_validate(src);
|
|
|
|
evbuffer_validate(dst);
|
|
|
|
|
2011-11-02 15:19:05 -07:00
|
|
|
/* move three bytes over */
|
|
|
|
evbuffer_remove_buffer(src, dst, 3);
|
2011-11-01 13:44:40 -07:00
|
|
|
|
|
|
|
evbuffer_validate(src);
|
|
|
|
evbuffer_validate(dst);
|
|
|
|
|
|
|
|
end:
|
|
|
|
evbuffer_free(src);
|
|
|
|
evbuffer_free(dst);
|
|
|
|
}
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
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;
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
|
|
|
|
tt_int_op(evbuffer_get_length(buf), ==, 512);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
/* 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;
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
/* 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;
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
/* 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);
|
2010-03-10 23:24:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
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);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2010-03-11 15:39:44 -05:00
|
|
|
static void
|
|
|
|
test_evbuffer_reserve_many(void *ptr)
|
|
|
|
{
|
|
|
|
/* This is a glass-box test to handle expanding a buffer with more
|
|
|
|
* chunks and reallocating chunks as needed */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* When reserving the the first chunk, we just allocate it */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make another chunk get added. */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* And a third chunk. */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Now force a reallocation by asking for more space in only 2
|
|
|
|
* buffers. */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-04-09 16:40:53 -04:00
|
|
|
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));
|
|
|
|
|
|
|
|
/* Make sure that expand() works on an empty buffer */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure that expand() works as a no-op when there's enough
|
|
|
|
* contiguous space already. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure that expand() can work by moving misaligned data
|
|
|
|
* when it makes sense to do so. */
|
|
|
|
buf = evbuffer_new();
|
|
|
|
evbuffer_add(buf, data, 400);
|
|
|
|
{
|
2010-11-03 14:38:45 -07:00
|
|
|
int n = (int)(buf->first->buffer_len - buf->first->off - 1);
|
2010-10-14 13:16:41 -04:00
|
|
|
tt_assert(n < (int)sizeof(data));
|
2010-04-09 16:40:53 -04:00
|
|
|
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);
|
|
|
|
|
|
|
|
/* add, expand, pull-up: This used to crash libevent. */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-03-11 15:39:44 -05:00
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
static int reference_cb_called;
|
2009-02-01 01:07:12 +00:00
|
|
|
static void
|
2009-05-15 22:44:18 +00:00
|
|
|
reference_cb(const void *data, size_t len, void *extra)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
2009-05-15 22:44:18 +00:00
|
|
|
tt_str_op(data, ==, "this is what we add as read-only memory.");
|
|
|
|
tt_int_op(len, ==, strlen(data));
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_want(extra == (void *)0xdeadaffe);
|
|
|
|
++reference_cb_called;
|
2009-05-15 22:44:18 +00:00
|
|
|
end:
|
|
|
|
;
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-02-01 01:07:22 +00:00
|
|
|
test_evbuffer_reference(void *ptr)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
|
|
|
struct evbuffer *src = evbuffer_new();
|
|
|
|
struct evbuffer *dst = evbuffer_new();
|
2009-05-19 21:39:35 +00:00
|
|
|
struct evbuffer_iovec v[1];
|
2009-02-01 01:07:12 +00:00
|
|
|
const char *data = "this is what we add as read-only memory.";
|
2009-02-01 01:07:22 +00:00
|
|
|
reference_cb_called = 0;
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(evbuffer_add_reference(src, data, strlen(data),
|
|
|
|
reference_cb, (void *)0xdeadaffe) != -1);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
evbuffer_reserve_space(dst, strlen(data), v, 1);
|
|
|
|
tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
evbuffer_validate(src);
|
|
|
|
evbuffer_validate(dst);
|
|
|
|
|
|
|
|
/* make sure that we don't write data at the beginning */
|
|
|
|
evbuffer_prepend(src, "aaaaa", 5);
|
|
|
|
evbuffer_validate(src);
|
|
|
|
evbuffer_drain(src, 5);
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
|
|
|
|
strlen(data) - 10) != -1);
|
|
|
|
|
|
|
|
v[0].iov_len = strlen(data);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
evbuffer_commit_space(dst, v, 1);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(src);
|
|
|
|
evbuffer_validate(dst);
|
|
|
|
|
2009-02-01 01:07:42 +00:00
|
|
|
tt_int_op(reference_cb_called, ==, 1);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)),
|
|
|
|
data, strlen(data)));
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(dst);
|
2009-02-01 01:07:22 +00:00
|
|
|
|
|
|
|
end:
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_free(dst);
|
|
|
|
evbuffer_free(src);
|
|
|
|
}
|
|
|
|
|
2010-12-20 18:40:03 -05:00
|
|
|
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 {
|
|
|
|
int 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-13 01:42:59 +00:00
|
|
|
static void
|
|
|
|
test_evbuffer_add_file(void *ptr)
|
|
|
|
{
|
2010-12-20 18:40:03 -05:00
|
|
|
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;
|
2009-02-13 01:42:59 +00:00
|
|
|
const char *compare;
|
2010-11-03 14:38:45 -07:00
|
|
|
int fd = -1;
|
2011-10-06 18:02:22 -04:00
|
|
|
int want_ismapping = -1, want_cansendfile = -1;
|
2010-10-21 19:45:49 -04:00
|
|
|
unsigned flags = 0;
|
2010-12-20 18:40:03 -05:00
|
|
|
int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
|
|
|
|
view_from_offset = 0;
|
2010-10-21 19:45:49 -04:00
|
|
|
struct evbuffer_file_segment *seg = NULL;
|
2010-12-20 18:40:03 -05:00
|
|
|
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};
|
2012-04-09 10:46:32 -04:00
|
|
|
static ev_uint32_t seed = 123456789U;
|
2009-02-13 01:42:59 +00:00
|
|
|
|
2010-12-20 18:40:03 -05:00
|
|
|
/* This test is highly parameterized based on substrings of its
|
|
|
|
* argument. The strings are: */
|
2010-04-09 15:28:26 -04:00
|
|
|
tt_assert(impl);
|
2010-12-20 18:40:03 -05:00
|
|
|
if (strstr(impl, "nosegment")) {
|
|
|
|
/* If nosegment is set, use the older evbuffer_add_file
|
|
|
|
* interface */
|
2010-10-21 19:45:49 -04:00
|
|
|
use_segment = 0;
|
2010-12-20 18:40:03 -05:00
|
|
|
}
|
|
|
|
if (strstr(impl, "bigfile")) {
|
|
|
|
/* If bigfile is set, use a 512K file. Else use a smaller
|
|
|
|
* one. */
|
|
|
|
use_bigfile = 1;
|
|
|
|
}
|
|
|
|
if (strstr(impl, "map_offset")) {
|
|
|
|
/* If map_offset is set, we build the file segment starting
|
|
|
|
* from a point other than byte 0 and ending somewhere other
|
|
|
|
* than the last byte. Otherwise we map the whole thing */
|
|
|
|
map_from_offset = 1;
|
|
|
|
}
|
|
|
|
if (strstr(impl, "offset_in_segment")) {
|
|
|
|
/* If offset_in_segment is set, we add a subsection of the
|
|
|
|
* file semgment starting from a point other than byte 0 of
|
|
|
|
* the segment. */
|
|
|
|
view_from_offset = 1;
|
|
|
|
}
|
|
|
|
if (strstr(impl, "sendfile")) {
|
|
|
|
/* If sendfile is set, we try to use a sendfile/splice style
|
|
|
|
* backend. */
|
2010-10-21 19:45:49 -04:00
|
|
|
flags = EVBUF_FS_DISABLE_MMAP;
|
2011-10-06 18:02:22 -04:00
|
|
|
want_cansendfile = 1;
|
|
|
|
want_ismapping = 0;
|
2010-12-20 18:40:03 -05:00
|
|
|
} else if (strstr(impl, "mmap")) {
|
|
|
|
/* If sendfile is set, we try to use a mmap/CreateFileMapping
|
|
|
|
* style backend. */
|
2010-10-21 19:45:49 -04:00
|
|
|
flags = EVBUF_FS_DISABLE_SENDFILE;
|
2011-10-06 18:02:22 -04:00
|
|
|
want_ismapping = 1;
|
|
|
|
want_cansendfile = 0;
|
2010-12-20 18:40:03 -05:00
|
|
|
} else if (strstr(impl, "linear")) {
|
|
|
|
/* If linear is set, we try to use a read-the-whole-thing
|
|
|
|
* backend. */
|
2010-10-21 19:45:49 -04:00
|
|
|
flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
|
2011-10-06 18:02:22 -04:00
|
|
|
want_ismapping = 0;
|
|
|
|
want_cansendfile = 0;
|
2010-12-20 18:40:03 -05:00
|
|
|
} else if (strstr(impl, "default")) {
|
|
|
|
/* The caller doesn't care which backend we use. */
|
|
|
|
;
|
2010-04-09 15:28:26 -04:00
|
|
|
} else {
|
2010-12-20 18:40:03 -05:00
|
|
|
/* The caller must choose a backend. */
|
2010-04-09 15:28:26 -04:00
|
|
|
TT_DIE(("Didn't recognize the implementation"));
|
|
|
|
}
|
|
|
|
|
2010-12-20 18:40:03 -05:00
|
|
|
if (use_bigfile) {
|
|
|
|
unsigned int i;
|
|
|
|
datalen = 1024*512;
|
|
|
|
data = malloc(1024*512);
|
|
|
|
tt_assert(data);
|
|
|
|
for (i = 0; i < datalen; ++i)
|
2012-04-09 10:46:32 -04:00
|
|
|
data[i] = (char)evutil_weakrand_(&seed);
|
2010-12-20 18:40:03 -05:00
|
|
|
} 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); /* Can't do this with add_file*/
|
|
|
|
segment_offset = expect_len / 3;
|
|
|
|
segment_len = expect_len / 2;
|
|
|
|
expect_data = expect_data + segment_offset;
|
|
|
|
expect_len = segment_len;
|
|
|
|
}
|
2010-10-21 19:45:49 -04:00
|
|
|
|
|
|
|
if (use_segment) {
|
2010-12-20 18:40:03 -05:00
|
|
|
seg = evbuffer_file_segment_new(fd, starting_offset,
|
|
|
|
mapping_len, flags);
|
2010-10-21 19:45:49 -04:00
|
|
|
tt_assert(seg);
|
2011-10-06 18:02:22 -04:00
|
|
|
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();
|
|
|
|
}
|
2010-10-21 19:45:49 -04:00
|
|
|
}
|
|
|
|
|
Prefer mmap to sendfile unless a DRAINS_TO_FD flag is set. Allows add_file to work with SSL.
The sendfile() implementation for evbuffer_add_file is potentially more
efficient, but it has a problem: you can only use it to send bytes over
a socket using sendfile(). If you are writing bytes via SSL_send() or
via a filter, or if you need to be able to inspect your buffer, it
doesn't work.
As an easy fix, this patch disables the sendfile-based implementation of
evbuffer_add_file on an evbuffer unless the user sets a new
EVBUFFER_FLAG_DRAINS_TO_FD flag on that evbuffer, indicating that the
evbuffer will not be inspected, but only written out via
evbuffer_write(), evbuffer_write_atmost(), or drained with stuff like
evbuffer_drain() or evbuffer_add_buffer(). This flag is off by
default, except for evbuffers used for output on bufferevent_socket.
In the future, it could be interesting to make a best-effort file
segment implementation that tries to send via sendfile, but mmaps on
demand. That's too much complexity for a stable release series, though.
2011-09-29 09:30:04 -04:00
|
|
|
/* Say that it drains to a fd so that we can use sendfile. */
|
|
|
|
evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
|
|
|
|
|
2012-02-29 15:07:31 -05:00
|
|
|
#if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
|
2010-08-06 13:03:17 -04:00
|
|
|
/* We need to use a pair of AF_INET sockets, since Solaris
|
|
|
|
doesn't support sendfile() over AF_UNIX. */
|
2012-02-29 15:07:33 -05:00
|
|
|
if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1)
|
2010-08-06 13:03:17 -04:00
|
|
|
tt_abort_msg("ersatz_socketpair failed");
|
|
|
|
#else
|
2009-02-13 01:42:59 +00:00
|
|
|
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
|
|
|
|
tt_abort_msg("socketpair failed");
|
2010-08-06 13:03:17 -04:00
|
|
|
#endif
|
2010-12-20 18:40:03 -05:00
|
|
|
evutil_make_socket_nonblocking(pair[0]);
|
|
|
|
evutil_make_socket_nonblocking(pair[1]);
|
2009-02-13 01:42:59 +00:00
|
|
|
|
|
|
|
tt_assert(fd != -1);
|
|
|
|
|
2010-10-21 19:45:49 -04:00
|
|
|
if (use_segment) {
|
2010-12-20 18:40:03 -05:00
|
|
|
tt_assert(evbuffer_add_file_segment(src, seg,
|
|
|
|
segment_offset, segment_len)!=-1);
|
2010-10-21 19:45:49 -04:00
|
|
|
} else {
|
2010-12-20 18:40:03 -05:00
|
|
|
tt_assert(evbuffer_add_file(src, fd, starting_offset,
|
|
|
|
mapping_len) != -1);
|
2010-10-21 19:45:49 -04:00
|
|
|
}
|
2009-02-13 01:42:59 +00:00
|
|
|
|
|
|
|
evbuffer_validate(src);
|
|
|
|
|
2010-12-20 18:40:03 -05:00
|
|
|
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);
|
2009-02-13 01:42:59 +00:00
|
|
|
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(src);
|
2010-12-20 18:40:03 -05:00
|
|
|
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);
|
2009-02-13 01:42:59 +00:00
|
|
|
tt_assert(compare != NULL);
|
2010-12-20 18:40:03 -05:00
|
|
|
if (memcmp(compare, expect_data, expect_len)) {
|
2009-02-13 01:42:59 +00:00
|
|
|
tt_abort_msg("Data from add_file differs.");
|
2010-10-21 19:45:49 -04:00
|
|
|
}
|
2009-02-13 01:42:59 +00:00
|
|
|
|
2010-12-20 18:40:03 -05:00
|
|
|
evbuffer_validate(dest);
|
2009-02-13 01:42:59 +00:00
|
|
|
end:
|
2010-12-20 18:40:03 -05:00
|
|
|
if (data)
|
|
|
|
free(data);
|
|
|
|
if (seg)
|
|
|
|
evbuffer_file_segment_free(seg);
|
|
|
|
if (src)
|
|
|
|
evbuffer_free(src);
|
|
|
|
if (dest)
|
|
|
|
evbuffer_free(dest);
|
2010-05-17 11:58:07 -04:00
|
|
|
if (pair[0] >= 0)
|
|
|
|
evutil_closesocket(pair[0]);
|
|
|
|
if (pair[1] >= 0)
|
|
|
|
evutil_closesocket(pair[1]);
|
2010-12-20 18:40:03 -05:00
|
|
|
if (tmpfilename) {
|
|
|
|
unlink(tmpfilename);
|
|
|
|
free(tmpfilename);
|
|
|
|
}
|
2009-02-13 01:42:59 +00:00
|
|
|
}
|
|
|
|
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifndef EVENT__DISABLE_MM_REPLACEMENT
|
2009-09-24 22:18:19 +00:00
|
|
|
static void *
|
|
|
|
failing_malloc(size_t how_much)
|
|
|
|
{
|
2009-10-27 04:03:50 +00:00
|
|
|
errno = ENOMEM;
|
2009-09-24 22:18:19 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-11-18 21:16:47 +00:00
|
|
|
#endif
|
2009-09-24 22:18:19 +00:00
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
static void
|
2009-02-01 01:07:22 +00:00
|
|
|
test_evbuffer_readln(void *ptr)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
|
|
|
struct evbuffer *evb = evbuffer_new();
|
|
|
|
struct evbuffer *evb_tmp = evbuffer_new();
|
|
|
|
const char *s;
|
|
|
|
char *cp = NULL;
|
|
|
|
size_t sz;
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
#define tt_line_eq(content) \
|
|
|
|
TT_STMT_BEGIN \
|
2009-02-10 19:38:54 +00:00
|
|
|
if (!cp || sz != strlen(content) || strcmp(cp, content)) { \
|
2009-02-01 01:07:22 +00:00
|
|
|
TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
|
|
|
|
} \
|
|
|
|
TT_STMT_END
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
/* Test EOL_ANY. */
|
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("complex silly newline");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
|
|
|
|
if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6))
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_abort_msg("Not as expected");
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_uint_op(evbuffer_get_length(evb), ==, 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!cp);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
2009-04-17 06:56:09 +00:00
|
|
|
evbuffer_drain(evb, evbuffer_get_length(evb));
|
|
|
|
tt_assert(evbuffer_get_length(evb) == 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
/* Test EOL_CRLF */
|
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("Line with\rin the middle");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("Line with good crlf");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("final");
|
2009-02-01 01:07:12 +00:00
|
|
|
s = "x";
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
evbuffer_add(evb, s, 1);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
free(cp);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!cp);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
/* Test CRLF_STRICT */
|
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("x and a bad crlf\nand a good one");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!cp);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
evbuffer_add(evb, "\n", 1);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("More");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) == 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2009-07-31 17:34:18 +00:00
|
|
|
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);
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
/* Test LF */
|
|
|
|
s = "An\rand a nl\n\nText";
|
|
|
|
evbuffer_add(evb, s, strlen(s));
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("An\rand a nl");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!cp);
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_add(evb, "\n", 1);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("Text");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2011-11-14 11:43:31 -05:00
|
|
|
/* Test NUL */
|
|
|
|
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";
|
|
|
|
/* Add all but the final NUL of x. */
|
|
|
|
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);
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
/* Test CRLF_STRICT - across boundaries*/
|
|
|
|
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);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq(" and a bad crlf\nand a good one");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_assert(!cp);
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
evbuffer_add(evb, "\n", 1);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
|
2009-02-01 01:07:22 +00:00
|
|
|
tt_line_eq("More");
|
2009-02-01 01:07:12 +00:00
|
|
|
free(cp); cp = NULL;
|
|
|
|
evbuffer_validate(evb);
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_assert(evbuffer_get_length(evb) == 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-09-24 22:18:19 +00:00
|
|
|
/* Test memory problem*/
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* the next call to readline should fail */
|
2012-02-29 15:07:31 -05:00
|
|
|
#ifndef EVENT__DISABLE_MM_REPLACEMENT
|
2009-09-24 22:18:19 +00:00
|
|
|
event_set_mem_functions(failing_malloc, realloc, free);
|
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
|
|
|
tt_assert(cp == NULL);
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
|
|
|
/* now we should get the next line back */
|
|
|
|
event_set_mem_functions(malloc, realloc, free);
|
2009-11-18 21:16:47 +00:00
|
|
|
#endif
|
2009-09-24 22:18:19 +00:00
|
|
|
cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
|
|
|
|
tt_line_eq("two line");
|
|
|
|
free(cp); cp = NULL;
|
|
|
|
evbuffer_validate(evb);
|
|
|
|
|
2009-02-01 01:07:22 +00:00
|
|
|
end:
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_free(evb);
|
|
|
|
evbuffer_free(evb_tmp);
|
|
|
|
if (cp) free(cp);
|
|
|
|
}
|
|
|
|
|
2011-06-06 15:11:28 -04:00
|
|
|
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);
|
|
|
|
|
2011-06-13 16:35:28 -04:00
|
|
|
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);
|
|
|
|
|
2011-06-06 15:11:28 -04:00
|
|
|
end:
|
|
|
|
evbuffer_free(buf);
|
|
|
|
}
|
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
static void
|
2009-02-01 01:07:22 +00:00
|
|
|
test_evbuffer_iterative(void *ptr)
|
2009-02-01 01:07:12 +00:00
|
|
|
{
|
|
|
|
struct evbuffer *buf = evbuffer_new();
|
|
|
|
const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
|
2010-03-30 16:47:37 -04:00
|
|
|
unsigned i, j, sum, n;
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
sum = 0;
|
2010-03-30 16:47:37 -04:00
|
|
|
n = 0;
|
2009-02-01 01:07:12 +00:00
|
|
|
for (i = 0; i < 1000; ++i) {
|
|
|
|
for (j = 1; j < strlen(abc); ++j) {
|
|
|
|
char format[32];
|
2009-11-05 21:22:23 +00:00
|
|
|
evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j);
|
2009-02-01 01:07:12 +00:00
|
|
|
evbuffer_add_printf(buf, format, abc);
|
2010-03-30 16:47:37 -04:00
|
|
|
|
|
|
|
/* Only check for rep violations every so often.
|
|
|
|
Walking over the whole list of chains can get
|
|
|
|
pretty expensive as it gets long.
|
|
|
|
*/
|
|
|
|
if ((n % 337) == 0)
|
|
|
|
evbuffer_validate(buf);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
sum += j;
|
2010-03-30 16:47:37 -04:00
|
|
|
n++;
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-30 16:47:37 -04:00
|
|
|
evbuffer_validate(buf);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2009-04-17 06:56:09 +00:00
|
|
|
tt_uint_op(sum, ==, evbuffer_get_length(buf));
|
2009-02-01 01:07:12 +00:00
|
|
|
|
2010-03-30 16:47:37 -04:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2009-02-01 01:07:22 +00:00
|
|
|
end:
|
2009-02-01 01:07:12 +00:00
|
|
|
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();
|
|
|
|
|
|
|
|
/* make sure evbuffer_find doesn't match past the end of the buffer */
|
|
|
|
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);
|
2009-02-10 19:38:54 +00:00
|
|
|
tt_want(p == NULL);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* drain the buffer and do another find; in r309 this would
|
|
|
|
* read past the allocated buffer causing a valgrind error.
|
|
|
|
*/
|
|
|
|
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);
|
2009-02-10 19:38:54 +00:00
|
|
|
tt_want(p == NULL);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
/* simple test for match at end of allocated buffer */
|
|
|
|
p = evbuffer_find(buf, (u_char *)"ax", 2);
|
2009-02-10 19:38:54 +00:00
|
|
|
tt_assert(p != NULL);
|
|
|
|
tt_want(strncmp((char*)p, "ax", 2) == 0);
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
end:
|
2009-02-10 19:38:54 +00:00
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
2009-02-01 01:07:12 +00:00
|
|
|
}
|
|
|
|
|
2009-04-03 01:21:36 +00:00
|
|
|
static void
|
|
|
|
test_evbuffer_ptr_set(void *ptr)
|
|
|
|
{
|
|
|
|
struct evbuffer *buf = evbuffer_new();
|
|
|
|
struct evbuffer_ptr pos;
|
2009-05-19 21:39:35 +00:00
|
|
|
struct evbuffer_iovec v[1];
|
2009-04-03 01:21:36 +00:00
|
|
|
|
2011-06-13 16:35:28 -04:00
|
|
|
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);
|
|
|
|
|
2009-04-03 01:21:36 +00:00
|
|
|
/* create some chains */
|
2009-05-19 21:39:35 +00:00
|
|
|
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);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
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);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-05-19 21:39:35 +00:00
|
|
|
|
|
|
|
tt_int_op(evbuffer_get_length(buf), ==, 12000);
|
2009-04-03 01:21:36 +00:00
|
|
|
|
|
|
|
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);
|
2011-06-06 21:03:35 -04:00
|
|
|
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
|
|
|
|
tt_assert(pos.pos == 12000);
|
2009-04-03 01:21:36 +00:00
|
|
|
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();
|
2009-08-07 17:16:52 +00:00
|
|
|
struct evbuffer_ptr pos, end;
|
2009-04-03 01:21:36 +00:00
|
|
|
|
2011-06-13 16:35:28 -04:00
|
|
|
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);
|
|
|
|
|
2009-04-03 01:21:36 +00:00
|
|
|
/* set up our chains */
|
|
|
|
evbuffer_add_printf(tmp, "hello"); /* 5 chars */
|
|
|
|
evbuffer_add_buffer(buf, tmp);
|
|
|
|
evbuffer_add_printf(tmp, "foo"); /* 3 chars */
|
|
|
|
evbuffer_add_buffer(buf, tmp);
|
|
|
|
evbuffer_add_printf(tmp, "cat"); /* 3 chars */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* test continuing search */
|
|
|
|
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);
|
|
|
|
|
2009-08-07 17:16:52 +00:00
|
|
|
/* test bounded search. */
|
|
|
|
/* Set "end" to the first t in "attack". */
|
|
|
|
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);
|
|
|
|
|
2011-06-13 16:35:28 -04:00
|
|
|
/* Set "end" after the last byte in the buffer. */
|
|
|
|
tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0);
|
|
|
|
|
2011-06-07 03:15:51 +03:00
|
|
|
pos = evbuffer_search_range(buf, "attack", 6, NULL, &end);
|
|
|
|
tt_int_op(pos.pos, ==, 11);
|
2011-06-13 16:35:28 -04:00
|
|
|
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);
|
2011-06-06 15:11:28 -04:00
|
|
|
|
2009-04-03 01:21:36 +00:00
|
|
|
end:
|
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
|
|
|
if (tmp)
|
|
|
|
evbuffer_free(tmp);
|
|
|
|
}
|
|
|
|
|
2009-02-01 01:07:42 +00:00
|
|
|
static void
|
2009-04-03 14:27:03 +00:00
|
|
|
log_change_callback(struct evbuffer *buffer,
|
|
|
|
const struct evbuffer_cb_info *cbinfo,
|
|
|
|
void *arg)
|
2009-02-01 01:07:42 +00:00
|
|
|
{
|
2009-04-03 14:27:03 +00:00
|
|
|
|
2010-02-18 17:41:15 -05:00
|
|
|
size_t old_len = cbinfo->orig_size;
|
|
|
|
size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
|
2009-02-01 01:07:42 +00:00
|
|
|
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,
|
2010-02-18 17:41:15 -05:00
|
|
|
size_t new_len, void *arg)
|
2009-02-01 01:07:42 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
|
|
|
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
|
|
|
|
|
|
|
|
/* Let's run through adding and deleting some stuff from the buffer
|
|
|
|
* and turning the callbacks on and off and removing them. The callback
|
|
|
|
* adds a summary of length changes to buf_out1/buf_out2 when called. */
|
|
|
|
/* size: 0-> 36. */
|
|
|
|
evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(buf);
|
2009-05-15 20:23:59 +00:00
|
|
|
evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
2009-02-01 01:07:42 +00:00
|
|
|
evbuffer_drain(buf, 10); /*36->26*/
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(buf);
|
2009-02-01 01:07:42 +00:00
|
|
|
evbuffer_prepend(buf, "Hello", 5);/*26->31*/
|
|
|
|
evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
|
|
|
evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
|
|
|
|
evbuffer_remove_cb_entry(buf, cb1);
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(buf);
|
2009-04-17 06:56:09 +00:00
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
|
2009-02-01 01:07:42 +00:00
|
|
|
tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
|
|
|
|
evbuffer_add(buf, "X", 1); /* 0->1 */
|
|
|
|
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(buf);
|
2009-02-01 01:07:42 +00:00
|
|
|
|
|
|
|
tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
|
|
|
|
"0->36; 36->26; 26->31; 31->38; ");
|
|
|
|
tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
|
|
|
|
"0->36; 31->38; 38->0; 0->1; ");
|
2009-04-17 06:56:09 +00:00
|
|
|
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
|
|
|
|
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
|
2009-02-01 01:07:42 +00:00
|
|
|
/* Let's test the obsolete buffer_setcb function too. */
|
|
|
|
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
2011-04-11 18:26:48 +02:00
|
|
|
tt_assert(cb1 != NULL);
|
2009-02-01 01:07:42 +00:00
|
|
|
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
|
2011-04-11 18:26:48 +02:00
|
|
|
tt_assert(cb2 != NULL);
|
2009-02-01 01:07:42 +00:00
|
|
|
evbuffer_setcb(buf, self_draining_callback, NULL);
|
|
|
|
evbuffer_add_printf(buf, "This should get drained right away.");
|
2009-04-17 06:56:09 +00:00
|
|
|
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);
|
2009-02-01 01:07:42 +00:00
|
|
|
evbuffer_setcb(buf, NULL, NULL);
|
|
|
|
evbuffer_add_printf(buf, "This will not.");
|
|
|
|
tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-04-17 06:56:09 +00:00
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf));
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf);
|
2009-04-03 14:27:03 +00:00
|
|
|
#if 0
|
2009-02-01 01:43:58 +00:00
|
|
|
/* Now let's try a suspended callback. */
|
|
|
|
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); /*0->11*/
|
|
|
|
evbuffer_validate(buf);
|
|
|
|
evbuffer_cb_suspend(buf,cb1);
|
|
|
|
evbuffer_add(buf,"more",4); /* 11->15 */
|
|
|
|
evbuffer_cb_unsuspend(buf,cb2);
|
|
|
|
evbuffer_drain(buf, 4); /* 15->11 */
|
|
|
|
evbuffer_cb_unsuspend(buf,cb1);
|
2009-04-17 06:56:09 +00:00
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */
|
2009-02-01 01:43:58 +00:00
|
|
|
|
|
|
|
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; ");
|
2009-04-03 14:27:03 +00:00
|
|
|
#endif
|
2009-02-01 01:43:58 +00:00
|
|
|
|
2009-02-01 01:07:42 +00:00
|
|
|
end:
|
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
|
|
|
if (buf_out1)
|
|
|
|
evbuffer_free(buf_out1);
|
|
|
|
if (buf_out2)
|
|
|
|
evbuffer_free(buf_out2);
|
|
|
|
}
|
|
|
|
|
2009-02-10 19:38:54 +00:00
|
|
|
static int ref_done_cb_called_count = 0;
|
|
|
|
static void *ref_done_cb_called_with = NULL;
|
2009-05-15 22:44:18 +00:00
|
|
|
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)
|
2009-02-10 19:38:54 +00:00
|
|
|
{
|
|
|
|
++ref_done_cb_called_count;
|
2009-05-15 22:44:18 +00:00
|
|
|
ref_done_cb_called_with = info;
|
|
|
|
ref_done_cb_called_with_data = data;
|
|
|
|
ref_done_cb_called_with_len = len;
|
2009-02-10 19:38:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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";
|
|
|
|
/* -- Knuth's "Notes on the Exercises" from TAOCP */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure we can drain a little from a reference. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure that prepending does not meddle with immutable data */
|
|
|
|
tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
|
|
|
|
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf1);
|
2009-02-10 19:38:54 +00:00
|
|
|
|
|
|
|
/* Make sure that when the chunk is over, the callback is invoked. */
|
|
|
|
evbuffer_drain(buf1, 7); /* Remove prepended stuff. */
|
|
|
|
evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */
|
|
|
|
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);
|
2009-05-15 22:44:18 +00:00
|
|
|
tt_assert(ref_done_cb_called_with_data == chunk1);
|
|
|
|
tt_assert(ref_done_cb_called_with_len == len1);
|
2009-02-10 19:38:54 +00:00
|
|
|
tt_int_op(ref_done_cb_called_count, ==, 1);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf1);
|
2009-02-10 19:38:54 +00:00
|
|
|
|
|
|
|
/* Drain some of the remaining chunk, then add it to another buffer */
|
|
|
|
evbuffer_drain(buf1, 6); /* Remove the ", you ". */
|
|
|
|
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);
|
Revise evbuffer to add last_with_data
This is the first patch in a series to replace previous_to_last with
last_with_data. Currently, we can only use two partially empty chains
at the end of an evbuffer, so if we have one with 511 bytes free, and
another with 512 bytes free, and we try to do a 1024 byte read, we
can't just stick another chain on the end: we need to reallocate the
last one. That's stupid and inefficient.
Instead, this patch adds a last_with_data pointer to eventually
replace previous_to_last. Instead of pointing to the penultimated
chain (if any) as previous_to_last does, last_with_data points to the
last chain that has any data in it, if any. If all chains are empty,
last_with_data points to the first chain. If there are no chains,
last_with_data is NULL.
The next step is to start using last_with_data everywhere that we
currently use previous_to_last. When that's done, we can remove
previous_to_last and the code that maintains it.
2010-03-10 22:16:14 -05:00
|
|
|
evbuffer_validate(buf2);
|
2009-02-10 19:38:54 +00:00
|
|
|
|
|
|
|
/* Now add more stuff to buf1 and make sure that it gets removed on
|
|
|
|
* free. */
|
|
|
|
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.", 42);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-06-09 23:33:58 +02:00
|
|
|
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";
|
|
|
|
/* -- Knuth's "Notes on the Exercises" from TAOCP */
|
|
|
|
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);
|
|
|
|
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
|
2012-02-02 11:45:23 -05:00
|
|
|
/* nested references are not allowed */
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1);
|
|
|
|
tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1);
|
2011-06-09 23:33:58 +02:00
|
|
|
|
2012-02-02 11:45:23 -05:00
|
|
|
/* both buffers contain the same amount of data */
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1));
|
2011-06-09 23:33:58 +02:00
|
|
|
|
|
|
|
/* Make sure we can drain a little from the first buffer. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure that prepending does not meddle with immutable data */
|
|
|
|
tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
|
|
|
|
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
|
|
|
|
evbuffer_validate(buf1);
|
|
|
|
|
|
|
|
/* Make sure we can drain a little from the second buffer. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Make sure that prepending does not meddle with immutable data */
|
|
|
|
tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0);
|
|
|
|
tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
|
|
|
|
evbuffer_validate(buf2);
|
|
|
|
|
2011-12-08 14:05:47 -05:00
|
|
|
/* Make sure the data can be read from the second buffer when the first is freed */
|
2011-06-09 23:33:58 +02:00
|
|
|
evbuffer_free(buf1);
|
|
|
|
buf1 = NULL;
|
2011-12-08 14:05:47 -05:00
|
|
|
|
2011-06-09 23:33:58 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-12-07 21:06:10 +01:00
|
|
|
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";
|
|
|
|
/* -- Knuth's "Notes on the Exercises" from TAOCP */
|
|
|
|
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);
|
|
|
|
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
|
2011-12-07 21:06:10 +01:00
|
|
|
tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0);
|
2011-12-07 21:06:10 +01:00
|
|
|
tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2);
|
2011-12-08 14:05:47 -05:00
|
|
|
tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0);
|
2011-12-07 21:06:10 +01:00
|
|
|
evbuffer_validate(buf1);
|
|
|
|
evbuffer_validate(buf2);
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (buf1)
|
|
|
|
evbuffer_free(buf1);
|
|
|
|
if (buf2)
|
|
|
|
evbuffer_free(buf2);
|
|
|
|
}
|
|
|
|
|
2009-02-10 19:39:03 +00:00
|
|
|
/* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
|
|
|
|
static void
|
|
|
|
test_evbuffer_prepend(void *ptr)
|
|
|
|
{
|
|
|
|
struct evbuffer *buf1 = NULL, *buf2 = NULL;
|
|
|
|
char tmp[128];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
buf1 = evbuffer_new();
|
|
|
|
tt_assert(buf1);
|
|
|
|
|
2010-04-09 17:19:39 -04:00
|
|
|
/* Case 0: The evbuffer is entirely empty. */
|
|
|
|
evbuffer_prepend(buf1, "This string has 29 characters", 29);
|
|
|
|
evbuffer_validate(buf1);
|
2009-02-10 19:39:03 +00:00
|
|
|
|
|
|
|
/* Case 1: Prepend goes entirely in new chunk. */
|
|
|
|
evbuffer_prepend(buf1, "Short.", 6);
|
|
|
|
evbuffer_validate(buf1);
|
|
|
|
|
|
|
|
/* Case 2: prepend goes entirely in first chunk. */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* Case 3: prepend is split over multiple chunks. */
|
|
|
|
evbuffer_prepend(buf1, "It is no longer true to say ", 28);
|
|
|
|
evbuffer_validate(buf1);
|
|
|
|
n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
|
|
|
|
tmp[n]='\0';
|
|
|
|
tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
|
|
|
|
|
|
|
|
buf2 = evbuffer_new();
|
|
|
|
tt_assert(buf2);
|
|
|
|
|
|
|
|
/* Case 4: prepend a buffer to an empty buffer. */
|
|
|
|
n = 999;
|
|
|
|
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
|
|
|
|
evbuffer_prepend_buffer(buf2, buf1);
|
|
|
|
evbuffer_validate(buf2);
|
|
|
|
|
|
|
|
/* Case 5: prepend a buffer to a nonempty buffer. */
|
|
|
|
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
|
|
|
|
evbuffer_prepend_buffer(buf2, buf1);
|
|
|
|
evbuffer_validate(buf2);
|
2010-03-26 23:18:40 -04:00
|
|
|
evbuffer_validate(buf1);
|
2009-02-10 19:39:03 +00:00
|
|
|
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
|
|
|
|
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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-12-08 14:30:20 -05:00
|
|
|
/* How many chunks do we need for everything? */
|
|
|
|
i = evbuffer_peek(buf, -1, NULL, NULL, 0);
|
|
|
|
tt_int_op(i, ==, 16);
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
/* 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*/
|
|
|
|
|
2011-06-13 16:35:28 -04:00
|
|
|
/* peek at the end of the buffer */
|
|
|
|
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);
|
|
|
|
|
2009-05-19 21:39:35 +00:00
|
|
|
end:
|
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
|
|
|
if (tmp_buf)
|
|
|
|
evbuffer_free(tmp_buf);
|
|
|
|
}
|
|
|
|
|
2009-04-08 03:04:39 +00:00
|
|
|
/* Check whether evbuffer freezing works right. This is called twice,
|
|
|
|
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
|
|
|
|
that modifying the start of the buffer doesn't work. When we test
|
|
|
|
"end", we freeze the end of an evbuffer and make sure that modifying
|
|
|
|
the end of the buffer doesn't work.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
test_evbuffer_freeze(void *ptr)
|
|
|
|
{
|
|
|
|
struct evbuffer *buf = NULL, *tmp_buf=NULL;
|
|
|
|
const char string[] = /* Year's End, Richard Wilbur */
|
|
|
|
"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;
|
2009-05-19 21:39:35 +00:00
|
|
|
struct evbuffer_iovec v[1];
|
2009-04-08 03:04:39 +00:00
|
|
|
|
|
|
|
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); /* Freeze the start or the end.*/
|
|
|
|
|
|
|
|
#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);
|
|
|
|
|
|
|
|
/* These functions all manipulate the end of buf. */
|
|
|
|
r = evbuffer_add(buf, "abc", 0);
|
|
|
|
FREEZE_EQ(r, 0, -1);
|
2009-05-19 21:39:35 +00:00
|
|
|
r = evbuffer_reserve_space(buf, 10, v, 1);
|
|
|
|
FREEZE_EQ(r, 1, -1);
|
|
|
|
if (r == 0) {
|
|
|
|
memset(v[0].iov_base, 'X', 10);
|
|
|
|
v[0].iov_len = 10;
|
|
|
|
}
|
|
|
|
r = evbuffer_commit_space(buf, v, 1);
|
2009-04-08 03:04:39 +00:00
|
|
|
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);
|
2009-07-14 18:50:06 +00:00
|
|
|
/* TODO: test add_buffer, add_file, read */
|
2009-04-08 03:04:39 +00:00
|
|
|
|
|
|
|
if (!start)
|
|
|
|
tt_int_op(orig_length, ==, evbuffer_get_length(buf));
|
|
|
|
|
|
|
|
orig_length = evbuffer_get_length(buf);
|
|
|
|
|
|
|
|
/* These functions all manipulate the start of 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);
|
2009-07-14 18:50:06 +00:00
|
|
|
/* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
|
2009-04-08 03:04:39 +00:00
|
|
|
|
|
|
|
if (start)
|
|
|
|
tt_int_op(orig_length, ==, evbuffer_get_length(buf));
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
|
|
|
|
|
|
|
if (tmp_buf)
|
|
|
|
evbuffer_free(tmp_buf);
|
|
|
|
}
|
|
|
|
|
2011-10-25 09:13:15 -04:00
|
|
|
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."
|
2011-11-11 17:56:08 -05:00
|
|
|
/* -- R.A. Salvatore, _Sojurn_ */
|
2011-10-25 09:13:15 -04:00
|
|
|
};
|
|
|
|
size_t expected_length = 0;
|
|
|
|
size_t returned_length = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
buf = evbuffer_new();
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
vec[i].iov_len = strlen(data[i]);
|
2011-11-11 17:56:08 -05:00
|
|
|
vec[i].iov_base = (char*) data[i];
|
2011-10-25 09:13:15 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-07 13:04:35 -05:00
|
|
|
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.";
|
|
|
|
/* -- Kipling, "In The Neolithic Age" */
|
|
|
|
char tmp[256];
|
|
|
|
struct evbuffer_ptr ptr;
|
|
|
|
struct evbuffer *buf;
|
|
|
|
|
|
|
|
(void)dummy;
|
|
|
|
|
|
|
|
buf = evbuffer_new();
|
|
|
|
tt_assert(buf);
|
|
|
|
|
|
|
|
tt_int_op(strlen(string), ==, 206);
|
|
|
|
|
|
|
|
/* Ensure separate chains */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* First, let's test plain old copyout. */
|
|
|
|
|
|
|
|
/* Copy a little from the beginning. */
|
|
|
|
tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10));
|
|
|
|
tt_int_op(0, ==, memcmp(tmp, "Still they", 10));
|
|
|
|
|
|
|
|
/* Now copy more than a little from the beginning */
|
|
|
|
memset(tmp, 0, sizeof(tmp));
|
|
|
|
tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100));
|
|
|
|
tt_int_op(0, ==, memcmp(tmp, string, 100));
|
|
|
|
|
|
|
|
/* Copy too much; ensure truncation. */
|
|
|
|
memset(tmp, 0, sizeof(tmp));
|
|
|
|
tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230));
|
|
|
|
tt_int_op(0, ==, memcmp(tmp, string, 206));
|
|
|
|
|
|
|
|
/* That was supposed to be nondestructive, btw */
|
|
|
|
tt_int_op(206, ==, evbuffer_get_length(buf));
|
|
|
|
|
|
|
|
/* Now it's time to test copyout_from! First, let's start in the
|
|
|
|
* first chain. */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* Right up to the end of the first chain */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* Span into the second chain */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* Span into the third chain */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* Overrun */
|
|
|
|
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));
|
|
|
|
|
|
|
|
/* That was supposed to be nondestructive, too */
|
|
|
|
tt_int_op(206, ==, evbuffer_get_length(buf));
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (buf)
|
|
|
|
evbuffer_free(buf);
|
|
|
|
}
|
|
|
|
|
2009-04-08 03:04:39 +00:00
|
|
|
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
|
|
|
|
};
|
2009-02-10 19:39:03 +00:00
|
|
|
|
2009-02-01 01:07:12 +00:00
|
|
|
struct testcase_t evbuffer_testcases[] = {
|
2009-02-01 01:07:22 +00:00
|
|
|
{ "evbuffer", test_evbuffer, 0, NULL, NULL },
|
2011-11-01 13:44:40 -07:00
|
|
|
{ "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
|
2009-05-19 21:39:35 +00:00
|
|
|
{ "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
|
2010-03-11 15:39:44 -05:00
|
|
|
{ "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" },
|
2010-04-09 16:40:53 -04:00
|
|
|
{ "expand", test_evbuffer_expand, 0, NULL, NULL },
|
2009-02-01 01:07:22 +00:00
|
|
|
{ "reference", test_evbuffer_reference, 0, NULL, NULL },
|
|
|
|
{ "iterative", test_evbuffer_iterative, 0, NULL, NULL },
|
2009-10-27 04:03:50 +00:00
|
|
|
{ "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
|
2011-06-06 15:11:28 -04:00
|
|
|
{ "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
|
2009-02-01 01:07:22 +00:00
|
|
|
{ "find", test_evbuffer_find, 0, NULL, NULL },
|
2009-04-03 01:21:36 +00:00
|
|
|
{ "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
|
|
|
|
{ "search", test_evbuffer_search, 0, NULL, NULL },
|
2009-02-01 01:07:42 +00:00
|
|
|
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
|
2009-02-10 19:38:54 +00:00
|
|
|
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
|
2011-06-09 23:33:58 +02:00
|
|
|
{ "multicast", test_evbuffer_multicast, 0, NULL, NULL },
|
2011-12-07 21:06:10 +01:00
|
|
|
{ "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
|
2010-03-26 23:18:40 -04:00
|
|
|
{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
|
2009-05-19 21:39:35 +00:00
|
|
|
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
|
2009-04-08 03:04:39 +00:00
|
|
|
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
|
|
|
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
2011-10-25 09:13:15 -04:00
|
|
|
{ "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL},
|
2011-12-07 13:04:35 -05:00
|
|
|
{ "copyout", test_evbuffer_copyout, 0, NULL, NULL},
|
2010-12-20 18:40:03 -05:00
|
|
|
|
|
|
|
#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"),
|
2009-02-01 01:07:12 +00:00
|
|
|
|
|
|
|
END_OF_TESTCASES
|
|
|
|
};
|