xref: /minix3/external/bsd/libevent/dist/test/regress_buffer.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: regress_buffer.c,v 1.5 2015/08/28 13:04:48 joerg Exp $	*/
2e985b929SDavid van Moolenbroek /*
3e985b929SDavid van Moolenbroek  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
4e985b929SDavid van Moolenbroek  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5e985b929SDavid van Moolenbroek  *
6e985b929SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
7e985b929SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
8e985b929SDavid van Moolenbroek  * are met:
9e985b929SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
10e985b929SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
11e985b929SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
12e985b929SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
13e985b929SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
14e985b929SDavid van Moolenbroek  * 3. The name of the author may not be used to endorse or promote products
15e985b929SDavid van Moolenbroek  *    derived from this software without specific prior written permission.
16e985b929SDavid van Moolenbroek  *
17e985b929SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18e985b929SDavid van Moolenbroek  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19e985b929SDavid van Moolenbroek  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20e985b929SDavid van Moolenbroek  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21e985b929SDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22e985b929SDavid van Moolenbroek  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23e985b929SDavid van Moolenbroek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24e985b929SDavid van Moolenbroek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25e985b929SDavid van Moolenbroek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26e985b929SDavid van Moolenbroek  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27e985b929SDavid van Moolenbroek  */
28e985b929SDavid van Moolenbroek 
29e985b929SDavid van Moolenbroek #ifdef WIN32
30e985b929SDavid van Moolenbroek #include <winsock2.h>
31e985b929SDavid van Moolenbroek #include <windows.h>
32e985b929SDavid van Moolenbroek #endif
33e985b929SDavid van Moolenbroek 
34e985b929SDavid van Moolenbroek #include "event2/event-config.h"
35e985b929SDavid van Moolenbroek #include <sys/cdefs.h>
36*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: regress_buffer.c,v 1.5 2015/08/28 13:04:48 joerg Exp $");
37e985b929SDavid van Moolenbroek 
38e985b929SDavid van Moolenbroek #include <sys/types.h>
39e985b929SDavid van Moolenbroek #include <sys/stat.h>
40e985b929SDavid van Moolenbroek #ifdef _EVENT_HAVE_SYS_TIME_H
41e985b929SDavid van Moolenbroek #include <sys/time.h>
42e985b929SDavid van Moolenbroek #endif
43e985b929SDavid van Moolenbroek #include <sys/queue.h>
44e985b929SDavid van Moolenbroek #ifndef WIN32
45e985b929SDavid van Moolenbroek #include <sys/socket.h>
46e985b929SDavid van Moolenbroek #include <sys/wait.h>
47e985b929SDavid van Moolenbroek #include <signal.h>
48e985b929SDavid van Moolenbroek #include <unistd.h>
49e985b929SDavid van Moolenbroek #include <netdb.h>
50e985b929SDavid van Moolenbroek #endif
51e985b929SDavid van Moolenbroek #include <stdlib.h>
52e985b929SDavid van Moolenbroek #include <stdio.h>
53e985b929SDavid van Moolenbroek #include <string.h>
54e985b929SDavid van Moolenbroek #include <errno.h>
55e985b929SDavid van Moolenbroek #include <assert.h>
56e985b929SDavid van Moolenbroek 
57e985b929SDavid van Moolenbroek #include "event2/event.h"
58e985b929SDavid van Moolenbroek #include "event2/buffer.h"
59e985b929SDavid van Moolenbroek #include "event2/buffer_compat.h"
60e985b929SDavid van Moolenbroek #include "event2/util.h"
61e985b929SDavid van Moolenbroek 
62e985b929SDavid van Moolenbroek #include "evbuffer-internal.h"
63e985b929SDavid van Moolenbroek #include "log-internal.h"
64e985b929SDavid van Moolenbroek 
65e985b929SDavid van Moolenbroek #include "regress.h"
66e985b929SDavid van Moolenbroek 
67e985b929SDavid van Moolenbroek /* Validates that an evbuffer is good. Returns false if it isn't, true if it
68e985b929SDavid van Moolenbroek  * is*/
69e985b929SDavid van Moolenbroek static int
_evbuffer_validate(struct evbuffer * buf)70e985b929SDavid van Moolenbroek _evbuffer_validate(struct evbuffer *buf)
71e985b929SDavid van Moolenbroek {
72e985b929SDavid van Moolenbroek 	struct evbuffer_chain *chain;
73e985b929SDavid van Moolenbroek 	size_t sum = 0;
74e985b929SDavid van Moolenbroek 	int found_last_with_datap = 0;
75e985b929SDavid van Moolenbroek 
76e985b929SDavid van Moolenbroek 	if (buf->first == NULL) {
77e985b929SDavid van Moolenbroek 		tt_assert(buf->last == NULL);
78e985b929SDavid van Moolenbroek 		tt_assert(buf->total_len == 0);
79e985b929SDavid van Moolenbroek 	}
80e985b929SDavid van Moolenbroek 
81e985b929SDavid van Moolenbroek 	chain = buf->first;
82e985b929SDavid van Moolenbroek 
83e985b929SDavid van Moolenbroek 	tt_assert(buf->last_with_datap);
84e985b929SDavid van Moolenbroek 	if (buf->last_with_datap == &buf->first)
85e985b929SDavid van Moolenbroek 		found_last_with_datap = 1;
86e985b929SDavid van Moolenbroek 
87e985b929SDavid van Moolenbroek 	while (chain != NULL) {
88e985b929SDavid van Moolenbroek 		if (&chain->next == buf->last_with_datap)
89e985b929SDavid van Moolenbroek 			found_last_with_datap = 1;
90e985b929SDavid van Moolenbroek 		sum += chain->off;
91e985b929SDavid van Moolenbroek 		if (chain->next == NULL) {
92e985b929SDavid van Moolenbroek 			tt_assert(buf->last == chain);
93e985b929SDavid van Moolenbroek 		}
94e985b929SDavid van Moolenbroek 		tt_assert(chain->buffer_len >= chain->misalign + chain->off);
95e985b929SDavid van Moolenbroek 		chain = chain->next;
96e985b929SDavid van Moolenbroek 	}
97e985b929SDavid van Moolenbroek 
98e985b929SDavid van Moolenbroek 	if (buf->first)
99e985b929SDavid van Moolenbroek 		tt_assert(*buf->last_with_datap);
100e985b929SDavid van Moolenbroek 
101e985b929SDavid van Moolenbroek 	if (*buf->last_with_datap) {
102e985b929SDavid van Moolenbroek 		chain = *buf->last_with_datap;
103e985b929SDavid van Moolenbroek 		if (chain->off == 0 || buf->total_len == 0) {
104e985b929SDavid van Moolenbroek 			tt_assert(chain->off == 0)
105e985b929SDavid van Moolenbroek 			tt_assert(chain == buf->first);
106e985b929SDavid van Moolenbroek 			tt_assert(buf->total_len == 0);
107e985b929SDavid van Moolenbroek 		}
108e985b929SDavid van Moolenbroek 		chain = chain->next;
109e985b929SDavid van Moolenbroek 		while (chain != NULL) {
110e985b929SDavid van Moolenbroek 			tt_assert(chain->off == 0);
111e985b929SDavid van Moolenbroek 			chain = chain->next;
112e985b929SDavid van Moolenbroek 		}
113e985b929SDavid van Moolenbroek 	} else {
114e985b929SDavid van Moolenbroek 		tt_assert(buf->last_with_datap == &buf->first);
115e985b929SDavid van Moolenbroek 	}
116e985b929SDavid van Moolenbroek 	tt_assert(found_last_with_datap);
117e985b929SDavid van Moolenbroek 
118e985b929SDavid van Moolenbroek 	tt_assert(sum == buf->total_len);
119e985b929SDavid van Moolenbroek 	return 1;
120e985b929SDavid van Moolenbroek  end:
121e985b929SDavid van Moolenbroek 	return 0;
122e985b929SDavid van Moolenbroek }
123e985b929SDavid van Moolenbroek 
124e985b929SDavid van Moolenbroek static void
evbuffer_get_waste(struct evbuffer * buf,size_t * allocatedp,size_t * wastedp,size_t * usedp)125e985b929SDavid van Moolenbroek evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp)
126e985b929SDavid van Moolenbroek {
127e985b929SDavid van Moolenbroek 	struct evbuffer_chain *chain;
128e985b929SDavid van Moolenbroek 	size_t a, w, u;
129e985b929SDavid van Moolenbroek 	int n = 0;
130e985b929SDavid van Moolenbroek 	u = a = w = 0;
131e985b929SDavid van Moolenbroek 
132e985b929SDavid van Moolenbroek 	chain = buf->first;
133e985b929SDavid van Moolenbroek 	/* skip empty at start */
134e985b929SDavid van Moolenbroek 	while (chain && chain->off==0) {
135e985b929SDavid van Moolenbroek 		++n;
136e985b929SDavid van Moolenbroek 		a += chain->buffer_len;
137e985b929SDavid van Moolenbroek 		chain = chain->next;
138e985b929SDavid van Moolenbroek 	}
139e985b929SDavid van Moolenbroek 	/* first nonempty chain: stuff at the end only is wasted. */
140e985b929SDavid van Moolenbroek 	if (chain) {
141e985b929SDavid van Moolenbroek 		++n;
142e985b929SDavid van Moolenbroek 		a += chain->buffer_len;
143e985b929SDavid van Moolenbroek 		u += chain->off;
144e985b929SDavid van Moolenbroek 		if (chain->next && chain->next->off)
145e985b929SDavid van Moolenbroek 			w += (size_t)(chain->buffer_len - (chain->misalign + chain->off));
146e985b929SDavid van Moolenbroek 		chain = chain->next;
147e985b929SDavid van Moolenbroek 	}
148e985b929SDavid van Moolenbroek 	/* subsequent nonempty chains */
149e985b929SDavid van Moolenbroek 	while (chain && chain->off) {
150e985b929SDavid van Moolenbroek 		++n;
151e985b929SDavid van Moolenbroek 		a += chain->buffer_len;
152e985b929SDavid van Moolenbroek 		w += (size_t)chain->misalign;
153e985b929SDavid van Moolenbroek 		u += chain->off;
154e985b929SDavid van Moolenbroek 		if (chain->next && chain->next->off)
155e985b929SDavid van Moolenbroek 			w += (size_t) (chain->buffer_len - (chain->misalign + chain->off));
156e985b929SDavid van Moolenbroek 		chain = chain->next;
157e985b929SDavid van Moolenbroek 	}
158e985b929SDavid van Moolenbroek 	/* subsequent empty chains */
159e985b929SDavid van Moolenbroek 	while (chain) {
160e985b929SDavid van Moolenbroek 		++n;
161e985b929SDavid van Moolenbroek 		a += chain->buffer_len;
162e985b929SDavid van Moolenbroek 	}
163e985b929SDavid van Moolenbroek 	*allocatedp = a;
164e985b929SDavid van Moolenbroek 	*wastedp = w;
165e985b929SDavid van Moolenbroek 	*usedp = u;
166e985b929SDavid van Moolenbroek }
167e985b929SDavid van Moolenbroek 
168e985b929SDavid van Moolenbroek #define evbuffer_validate(buf)			\
169e985b929SDavid van Moolenbroek 	TT_STMT_BEGIN if (!_evbuffer_validate(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
170e985b929SDavid van Moolenbroek 
171e985b929SDavid van Moolenbroek static void
test_evbuffer(void * ptr)172e985b929SDavid van Moolenbroek test_evbuffer(void *ptr)
173e985b929SDavid van Moolenbroek {
174e985b929SDavid van Moolenbroek 	static char buffer[512], *tmp;
175e985b929SDavid van Moolenbroek 	struct evbuffer *evb = evbuffer_new();
176e985b929SDavid van Moolenbroek 	struct evbuffer *evb_two = evbuffer_new();
177e985b929SDavid van Moolenbroek 	size_t sz_tmp;
178e985b929SDavid van Moolenbroek 	int i;
179e985b929SDavid van Moolenbroek 
180e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
181e985b929SDavid van Moolenbroek 	evbuffer_add_printf(evb, "%s/%d", "hello", 1);
182e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
183e985b929SDavid van Moolenbroek 
184e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 7);
185e985b929SDavid van Moolenbroek 	tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1));
186e985b929SDavid van Moolenbroek 
187e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_two);
188e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
189e985b929SDavid van Moolenbroek 
190e985b929SDavid van Moolenbroek 	evbuffer_drain(evb, strlen("hello/"));
191e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
192e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 1);
193e985b929SDavid van Moolenbroek 	tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1));
194e985b929SDavid van Moolenbroek 
195e985b929SDavid van Moolenbroek 	evbuffer_add_printf(evb_two, "%s", "/hello");
196e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
197e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_two);
198e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
199e985b929SDavid van Moolenbroek 
200e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb_two) == 0);
201e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 7);
202*0a6a1f1dSLionel Sambuc 	tt_assert(memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) == 0);
203e985b929SDavid van Moolenbroek 
204e985b929SDavid van Moolenbroek 	memset(buffer, 0, sizeof(buffer));
205e985b929SDavid van Moolenbroek 	evbuffer_add(evb, buffer, sizeof(buffer));
206e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
207e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 7 + 512);
208e985b929SDavid van Moolenbroek 
209e985b929SDavid van Moolenbroek 	tmp = (char *)evbuffer_pullup(evb, 7 + 512);
210e985b929SDavid van Moolenbroek 	tt_assert(tmp);
211e985b929SDavid van Moolenbroek 	tt_assert(!strncmp(tmp, "1/hello", 7));
212e985b929SDavid van Moolenbroek 	tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer)));
213e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
214e985b929SDavid van Moolenbroek 
215e985b929SDavid van Moolenbroek 	evbuffer_prepend(evb, "something", 9);
216e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
217e985b929SDavid van Moolenbroek 	evbuffer_prepend(evb, "else", 4);
218e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
219e985b929SDavid van Moolenbroek 
220e985b929SDavid van Moolenbroek 	tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7);
221e985b929SDavid van Moolenbroek 	tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7));
222e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
223e985b929SDavid van Moolenbroek 
224e985b929SDavid van Moolenbroek 	evbuffer_drain(evb, -1);
225e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
226e985b929SDavid van Moolenbroek 	evbuffer_drain(evb_two, -1);
227e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
228e985b929SDavid van Moolenbroek 
229e985b929SDavid van Moolenbroek 	for (i = 0; i < 3; ++i) {
230e985b929SDavid van Moolenbroek 		evbuffer_add(evb_two, buffer, sizeof(buffer));
231e985b929SDavid van Moolenbroek 		evbuffer_validate(evb_two);
232e985b929SDavid van Moolenbroek 		evbuffer_add_buffer(evb, evb_two);
233e985b929SDavid van Moolenbroek 		evbuffer_validate(evb);
234e985b929SDavid van Moolenbroek 		evbuffer_validate(evb_two);
235e985b929SDavid van Moolenbroek 	}
236e985b929SDavid van Moolenbroek 
237e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb_two) == 0);
238e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer));
239e985b929SDavid van Moolenbroek 
240e985b929SDavid van Moolenbroek 	/* test remove buffer */
241e985b929SDavid van Moolenbroek 	sz_tmp = (size_t)(sizeof(buffer)*2.5);
242e985b929SDavid van Moolenbroek 	evbuffer_remove_buffer(evb, evb_two, sz_tmp);
243e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb_two) == sz_tmp);
244e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2);
245e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
246e985b929SDavid van Moolenbroek 
247e985b929SDavid van Moolenbroek 	if (memcmp(evbuffer_pullup(
248e985b929SDavid van Moolenbroek 			   evb, -1), buffer, sizeof(buffer) / 2) != 0 ||
249e985b929SDavid van Moolenbroek 	    memcmp(evbuffer_pullup(
250*0a6a1f1dSLionel Sambuc 			   evb_two, -1), buffer, sizeof(buffer)) != 0)
251e985b929SDavid van Moolenbroek 		tt_abort_msg("Pullup did not preserve content");
252e985b929SDavid van Moolenbroek 
253e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
254e985b929SDavid van Moolenbroek 
255e985b929SDavid van Moolenbroek 
256e985b929SDavid van Moolenbroek 	/* testing one-vector reserve and commit */
257e985b929SDavid van Moolenbroek 	{
258e985b929SDavid van Moolenbroek 		struct evbuffer_iovec v[1];
259e985b929SDavid van Moolenbroek 		char *buf;
260e985b929SDavid van Moolenbroek 		int ii, j, r;
261e985b929SDavid van Moolenbroek 
262e985b929SDavid van Moolenbroek 		for (ii = 0; ii < 3; ++ii) {
263e985b929SDavid van Moolenbroek 			r = evbuffer_reserve_space(evb, 10000, v, 1);
264e985b929SDavid van Moolenbroek 			tt_int_op(r, ==, 1);
265e985b929SDavid van Moolenbroek 			tt_assert(v[0].iov_len >= 10000);
266e985b929SDavid van Moolenbroek 			tt_assert(v[0].iov_base != NULL);
267e985b929SDavid van Moolenbroek 
268e985b929SDavid van Moolenbroek 			evbuffer_validate(evb);
269e985b929SDavid van Moolenbroek 			buf = v[0].iov_base;
270e985b929SDavid van Moolenbroek 			for (j = 0; j < 10000; ++j) {
271e985b929SDavid van Moolenbroek 				buf[j] = j;
272e985b929SDavid van Moolenbroek 			}
273e985b929SDavid van Moolenbroek 			evbuffer_validate(evb);
274e985b929SDavid van Moolenbroek 
275e985b929SDavid van Moolenbroek 			tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0);
276e985b929SDavid van Moolenbroek 			evbuffer_validate(evb);
277e985b929SDavid van Moolenbroek 
278e985b929SDavid van Moolenbroek 			tt_assert(evbuffer_get_length(evb) >= 10000);
279e985b929SDavid van Moolenbroek 
280e985b929SDavid van Moolenbroek 			evbuffer_drain(evb, j * 5000);
281e985b929SDavid van Moolenbroek 			evbuffer_validate(evb);
282e985b929SDavid van Moolenbroek 		}
283e985b929SDavid van Moolenbroek 	}
284e985b929SDavid van Moolenbroek 
285e985b929SDavid van Moolenbroek  end:
286e985b929SDavid van Moolenbroek 	evbuffer_free(evb);
287e985b929SDavid van Moolenbroek 	evbuffer_free(evb_two);
288e985b929SDavid van Moolenbroek }
289e985b929SDavid van Moolenbroek 
290e985b929SDavid van Moolenbroek static void
no_cleanup(const void * data,size_t datalen,void * extra)291e985b929SDavid van Moolenbroek no_cleanup(const void *data, size_t datalen, void *extra)
292e985b929SDavid van Moolenbroek {
293e985b929SDavid van Moolenbroek }
294e985b929SDavid van Moolenbroek 
295e985b929SDavid van Moolenbroek static void
test_evbuffer_remove_buffer_with_empty(void * ptr)296e985b929SDavid van Moolenbroek test_evbuffer_remove_buffer_with_empty(void *ptr)
297e985b929SDavid van Moolenbroek {
298e985b929SDavid van Moolenbroek     struct evbuffer *src = evbuffer_new();
299e985b929SDavid van Moolenbroek     struct evbuffer *dst = evbuffer_new();
300e985b929SDavid van Moolenbroek     char buf[2];
301e985b929SDavid van Moolenbroek 
302e985b929SDavid van Moolenbroek     evbuffer_validate(src);
303e985b929SDavid van Moolenbroek     evbuffer_validate(dst);
304e985b929SDavid van Moolenbroek 
305e985b929SDavid van Moolenbroek     /* setup the buffers */
306e985b929SDavid van Moolenbroek     /* we need more data in src than we will move later */
307e985b929SDavid van Moolenbroek     evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
308e985b929SDavid van Moolenbroek     evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL);
309e985b929SDavid van Moolenbroek     /* we need one buffer in dst and one empty buffer at the end */
310e985b929SDavid van Moolenbroek     evbuffer_add(dst, buf, sizeof(buf));
311e985b929SDavid van Moolenbroek     evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL);
312e985b929SDavid van Moolenbroek 
313e985b929SDavid van Moolenbroek     evbuffer_validate(src);
314e985b929SDavid van Moolenbroek     evbuffer_validate(dst);
315e985b929SDavid van Moolenbroek 
316e985b929SDavid van Moolenbroek     /* move three bytes over */
317e985b929SDavid van Moolenbroek     evbuffer_remove_buffer(src, dst, 3);
318e985b929SDavid van Moolenbroek 
319e985b929SDavid van Moolenbroek     evbuffer_validate(src);
320e985b929SDavid van Moolenbroek     evbuffer_validate(dst);
321e985b929SDavid van Moolenbroek 
322e985b929SDavid van Moolenbroek end:
323e985b929SDavid van Moolenbroek     evbuffer_free(src);
324e985b929SDavid van Moolenbroek     evbuffer_free(dst);
325e985b929SDavid van Moolenbroek }
326e985b929SDavid van Moolenbroek 
327e985b929SDavid van Moolenbroek static void
test_evbuffer_reserve2(void * ptr)328e985b929SDavid van Moolenbroek test_evbuffer_reserve2(void *ptr)
329e985b929SDavid van Moolenbroek {
330e985b929SDavid van Moolenbroek 	/* Test the two-vector cases of reserve/commit. */
331e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
332e985b929SDavid van Moolenbroek 	int n, i;
333e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[2];
334e985b929SDavid van Moolenbroek 	size_t remaining;
335e985b929SDavid van Moolenbroek 	char *cp, *cp2;
336e985b929SDavid van Moolenbroek 
337e985b929SDavid van Moolenbroek 	/* First chunk will necessarily be one chunk. Use 512 bytes of it.*/
338e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, 1024, v, 2);
339e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 1);
340e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 0);
341e985b929SDavid van Moolenbroek 	tt_assert(v[0].iov_base != NULL);
342e985b929SDavid van Moolenbroek 	tt_int_op(v[0].iov_len, >=, 1024);
343e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 'X', 512);
344e985b929SDavid van Moolenbroek 	cp = v[0].iov_base;
345e985b929SDavid van Moolenbroek 	remaining = v[0].iov_len - 512;
346e985b929SDavid van Moolenbroek 	v[0].iov_len = 512;
347e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
348e985b929SDavid van Moolenbroek 	tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
349e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 512);
350e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
351e985b929SDavid van Moolenbroek 
352e985b929SDavid van Moolenbroek 	/* Ask for another same-chunk request, in an existing chunk. Use 8
353e985b929SDavid van Moolenbroek 	 * bytes of it. */
354e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, 32, v, 2);
355e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 1);
356e985b929SDavid van Moolenbroek 	tt_assert(cp + 512 == v[0].iov_base);
357e985b929SDavid van Moolenbroek 	tt_int_op(remaining, ==, v[0].iov_len);
358e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 'Y', 8);
359e985b929SDavid van Moolenbroek 	v[0].iov_len = 8;
360e985b929SDavid van Moolenbroek 	tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
361e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 520);
362e985b929SDavid van Moolenbroek 	remaining -= 8;
363e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
364e985b929SDavid van Moolenbroek 
365e985b929SDavid van Moolenbroek 	/* Now ask for a request that will be split. Use only one byte of it,
366e985b929SDavid van Moolenbroek 	   though. */
367e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, remaining+64, v, 2);
368e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 2);
369e985b929SDavid van Moolenbroek 	tt_assert(cp + 520 == v[0].iov_base);
370e985b929SDavid van Moolenbroek 	tt_int_op(remaining, ==, v[0].iov_len);
371e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_base);
372e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_len >= 64);
373e985b929SDavid van Moolenbroek 	cp2 = v[1].iov_base;
374e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 'Z', 1);
375e985b929SDavid van Moolenbroek 	v[0].iov_len = 1;
376e985b929SDavid van Moolenbroek 	tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1));
377e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 521);
378e985b929SDavid van Moolenbroek 	remaining -= 1;
379e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
380e985b929SDavid van Moolenbroek 
381e985b929SDavid van Moolenbroek 	/* Now ask for a request that will be split. Use some of the first
382e985b929SDavid van Moolenbroek 	 * part and some of the second. */
383e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, remaining+64, v, 2);
384e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
385e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 2);
386e985b929SDavid van Moolenbroek 	tt_assert(cp + 521 == v[0].iov_base);
387e985b929SDavid van Moolenbroek 	tt_int_op(remaining, ==, v[0].iov_len);
388e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_base == cp2);
389e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_len >= 64);
390e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 'W', 400);
391e985b929SDavid van Moolenbroek 	v[0].iov_len = 400;
392e985b929SDavid van Moolenbroek 	memset(v[1].iov_base, 'x', 60);
393e985b929SDavid van Moolenbroek 	v[1].iov_len = 60;
394e985b929SDavid van Moolenbroek 	tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2));
395e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 981);
396e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
397e985b929SDavid van Moolenbroek 
398e985b929SDavid van Moolenbroek 	/* Now peek to make sure stuff got made how we like. */
399e985b929SDavid van Moolenbroek 	memset(v,0,sizeof(v));
400e985b929SDavid van Moolenbroek 	n = evbuffer_peek(buf, -1, NULL, v, 2);
401e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 2);
402e985b929SDavid van Moolenbroek 	tt_int_op(v[0].iov_len, ==, 921);
403e985b929SDavid van Moolenbroek 	tt_int_op(v[1].iov_len, ==, 60);
404e985b929SDavid van Moolenbroek 
405e985b929SDavid van Moolenbroek 	cp = v[0].iov_base;
406e985b929SDavid van Moolenbroek 	for (i=0; i<512; ++i)
407e985b929SDavid van Moolenbroek 		tt_int_op(cp[i], ==, 'X');
408e985b929SDavid van Moolenbroek 	for (i=512; i<520; ++i)
409e985b929SDavid van Moolenbroek 		tt_int_op(cp[i], ==, 'Y');
410e985b929SDavid van Moolenbroek 	for (i=520; i<521; ++i)
411e985b929SDavid van Moolenbroek 		tt_int_op(cp[i], ==, 'Z');
412e985b929SDavid van Moolenbroek 	for (i=521; i<921; ++i)
413e985b929SDavid van Moolenbroek 		tt_int_op(cp[i], ==, 'W');
414e985b929SDavid van Moolenbroek 
415e985b929SDavid van Moolenbroek 	cp = v[1].iov_base;
416e985b929SDavid van Moolenbroek 	for (i=0; i<60; ++i)
417e985b929SDavid van Moolenbroek 		tt_int_op(cp[i], ==, 'x');
418e985b929SDavid van Moolenbroek 
419e985b929SDavid van Moolenbroek end:
420e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
421e985b929SDavid van Moolenbroek }
422e985b929SDavid van Moolenbroek 
423e985b929SDavid van Moolenbroek static void
test_evbuffer_reserve_many(void * ptr)424e985b929SDavid van Moolenbroek test_evbuffer_reserve_many(void *ptr)
425e985b929SDavid van Moolenbroek {
426e985b929SDavid van Moolenbroek 	/* This is a glass-box test to handle expanding a buffer with more
427e985b929SDavid van Moolenbroek 	 * chunks and reallocating chunks as needed */
428e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
429e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[8];
430e985b929SDavid van Moolenbroek 	int n;
431e985b929SDavid van Moolenbroek 	size_t sz;
432e985b929SDavid van Moolenbroek 	int add_data = ptr && !strcmp(ptr, "add");
433e985b929SDavid van Moolenbroek 	int fill_first = ptr && !strcmp(ptr, "fill");
434e985b929SDavid van Moolenbroek 	char *cp1, *cp2;
435e985b929SDavid van Moolenbroek 
436e985b929SDavid van Moolenbroek 	/* When reserving the the first chunk, we just allocate it */
437e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, 128, v, 2);
438e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
439e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 1);
440e985b929SDavid van Moolenbroek 	tt_assert(v[0].iov_len >= 128);
441e985b929SDavid van Moolenbroek 	sz = v[0].iov_len;
442e985b929SDavid van Moolenbroek 	cp1 = v[0].iov_base;
443e985b929SDavid van Moolenbroek 	if (add_data) {
444e985b929SDavid van Moolenbroek 		*(char*)v[0].iov_base = 'X';
445e985b929SDavid van Moolenbroek 		v[0].iov_len = 1;
446e985b929SDavid van Moolenbroek 		n = evbuffer_commit_space(buf, v, 1);
447e985b929SDavid van Moolenbroek 		tt_int_op(n, ==, 0);
448e985b929SDavid van Moolenbroek 	} else if (fill_first) {
449e985b929SDavid van Moolenbroek 		memset(v[0].iov_base, 'X', v[0].iov_len);
450e985b929SDavid van Moolenbroek 		n = evbuffer_commit_space(buf, v, 1);
451e985b929SDavid van Moolenbroek 		tt_int_op(n, ==, 0);
452e985b929SDavid van Moolenbroek 		n = evbuffer_reserve_space(buf, 128, v, 2);
453e985b929SDavid van Moolenbroek 		tt_int_op(n, ==, 1);
454e985b929SDavid van Moolenbroek 		sz = v[0].iov_len;
455e985b929SDavid van Moolenbroek 		tt_assert(v[0].iov_base != cp1);
456e985b929SDavid van Moolenbroek 		cp1 = v[0].iov_base;
457e985b929SDavid van Moolenbroek 	}
458e985b929SDavid van Moolenbroek 
459e985b929SDavid van Moolenbroek 	/* Make another chunk get added. */
460e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, sz+128, v, 2);
461e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
462e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 2);
463e985b929SDavid van Moolenbroek 	sz = v[0].iov_len + v[1].iov_len;
464e985b929SDavid van Moolenbroek 	tt_int_op(sz, >=, v[0].iov_len+128);
465e985b929SDavid van Moolenbroek 	if (add_data) {
466e985b929SDavid van Moolenbroek 		tt_assert(v[0].iov_base == cp1 + 1);
467e985b929SDavid van Moolenbroek 	} else {
468e985b929SDavid van Moolenbroek 		tt_assert(v[0].iov_base == cp1);
469e985b929SDavid van Moolenbroek 	}
470e985b929SDavid van Moolenbroek 	cp1 = v[0].iov_base;
471e985b929SDavid van Moolenbroek 	cp2 = v[1].iov_base;
472e985b929SDavid van Moolenbroek 
473e985b929SDavid van Moolenbroek 	/* And a third chunk. */
474e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, sz+128, v, 3);
475e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
476e985b929SDavid van Moolenbroek 	tt_int_op(n, ==, 3);
477e985b929SDavid van Moolenbroek 	tt_assert(cp1 == v[0].iov_base);
478e985b929SDavid van Moolenbroek 	tt_assert(cp2 == v[1].iov_base);
479e985b929SDavid van Moolenbroek 	sz = v[0].iov_len + v[1].iov_len + v[2].iov_len;
480e985b929SDavid van Moolenbroek 
481e985b929SDavid van Moolenbroek 	/* Now force a reallocation by asking for more space in only 2
482e985b929SDavid van Moolenbroek 	 * buffers. */
483e985b929SDavid van Moolenbroek 	n = evbuffer_reserve_space(buf, sz+128, v, 2);
484e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
485e985b929SDavid van Moolenbroek 	if (add_data) {
486e985b929SDavid van Moolenbroek 		tt_int_op(n, ==, 2);
487e985b929SDavid van Moolenbroek 		tt_assert(cp1 == v[0].iov_base);
488e985b929SDavid van Moolenbroek 	} else {
489e985b929SDavid van Moolenbroek 		tt_int_op(n, ==, 1);
490e985b929SDavid van Moolenbroek 	}
491e985b929SDavid van Moolenbroek 
492e985b929SDavid van Moolenbroek end:
493e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
494e985b929SDavid van Moolenbroek }
495e985b929SDavid van Moolenbroek 
496e985b929SDavid van Moolenbroek static void
test_evbuffer_expand(void * ptr)497e985b929SDavid van Moolenbroek test_evbuffer_expand(void *ptr)
498e985b929SDavid van Moolenbroek {
499e985b929SDavid van Moolenbroek 	char data[4096];
500e985b929SDavid van Moolenbroek 	struct evbuffer *buf;
501e985b929SDavid van Moolenbroek 	size_t a,w,u;
502e985b929SDavid van Moolenbroek 	void *buffer;
503e985b929SDavid van Moolenbroek 
504e985b929SDavid van Moolenbroek 	memset(data, 'X', sizeof(data));
505e985b929SDavid van Moolenbroek 
506e985b929SDavid van Moolenbroek 	/* Make sure that expand() works on an empty buffer */
507e985b929SDavid van Moolenbroek 	buf = evbuffer_new();
508e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_expand(buf, 20000), ==, 0);
509e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
510e985b929SDavid van Moolenbroek 	a=w=u=0;
511e985b929SDavid van Moolenbroek 	evbuffer_get_waste(buf, &a,&w,&u);
512e985b929SDavid van Moolenbroek 	tt_assert(w == 0);
513e985b929SDavid van Moolenbroek 	tt_assert(u == 0);
514e985b929SDavid van Moolenbroek 	tt_assert(a >= 20000);
515e985b929SDavid van Moolenbroek 	tt_assert(buf->first);
516e985b929SDavid van Moolenbroek 	tt_assert(buf->first == buf->last);
517e985b929SDavid van Moolenbroek 	tt_assert(buf->first->off == 0);
518e985b929SDavid van Moolenbroek 	tt_assert(buf->first->buffer_len >= 20000);
519e985b929SDavid van Moolenbroek 
520e985b929SDavid van Moolenbroek 	/* Make sure that expand() works as a no-op when there's enough
521e985b929SDavid van Moolenbroek 	 * contiguous space already. */
522e985b929SDavid van Moolenbroek 	buffer = buf->first->buffer;
523e985b929SDavid van Moolenbroek 	evbuffer_add(buf, data, 1024);
524e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_expand(buf, 1024), ==, 0);
525e985b929SDavid van Moolenbroek 	tt_assert(buf->first->buffer == buffer);
526e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
527e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
528e985b929SDavid van Moolenbroek 
529e985b929SDavid van Moolenbroek 	/* Make sure that expand() can work by moving misaligned data
530e985b929SDavid van Moolenbroek 	 * when it makes sense to do so. */
531e985b929SDavid van Moolenbroek 	buf = evbuffer_new();
532e985b929SDavid van Moolenbroek 	evbuffer_add(buf, data, 400);
533e985b929SDavid van Moolenbroek 	{
534e985b929SDavid van Moolenbroek 		int n = (int)(buf->first->buffer_len - buf->first->off - 1);
535e985b929SDavid van Moolenbroek 		tt_assert(n < (int)sizeof(data));
536e985b929SDavid van Moolenbroek 		evbuffer_add(buf, data, n);
537e985b929SDavid van Moolenbroek 	}
538e985b929SDavid van Moolenbroek 	tt_assert(buf->first == buf->last);
539e985b929SDavid van Moolenbroek 	tt_assert(buf->first->off == buf->first->buffer_len - 1);
540e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, buf->first->off - 1);
541e985b929SDavid van Moolenbroek 	tt_assert(1 == evbuffer_get_length(buf));
542e985b929SDavid van Moolenbroek 	tt_assert(buf->first->misalign > 0);
543e985b929SDavid van Moolenbroek 	tt_assert(buf->first->off == 1);
544e985b929SDavid van Moolenbroek 	buffer = buf->first->buffer;
545e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_expand(buf, 40) == 0);
546e985b929SDavid van Moolenbroek 	tt_assert(buf->first == buf->last);
547e985b929SDavid van Moolenbroek 	tt_assert(buf->first->off == 1);
548e985b929SDavid van Moolenbroek 	tt_assert(buf->first->buffer == buffer);
549e985b929SDavid van Moolenbroek 	tt_assert(buf->first->misalign == 0);
550e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
551e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
552e985b929SDavid van Moolenbroek 
553e985b929SDavid van Moolenbroek 	/* add, expand, pull-up: This used to crash libevent. */
554e985b929SDavid van Moolenbroek 	buf = evbuffer_new();
555e985b929SDavid van Moolenbroek 
556e985b929SDavid van Moolenbroek 	evbuffer_add(buf, data, sizeof(data));
557e985b929SDavid van Moolenbroek 	evbuffer_add(buf, data, sizeof(data));
558e985b929SDavid van Moolenbroek 	evbuffer_add(buf, data, sizeof(data));
559e985b929SDavid van Moolenbroek 
560e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
561e985b929SDavid van Moolenbroek 	evbuffer_expand(buf, 1024);
562e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
563e985b929SDavid van Moolenbroek 	evbuffer_pullup(buf, -1);
564e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
565e985b929SDavid van Moolenbroek 
566e985b929SDavid van Moolenbroek end:
567e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
568e985b929SDavid van Moolenbroek }
569e985b929SDavid van Moolenbroek 
570e985b929SDavid van Moolenbroek 
571e985b929SDavid van Moolenbroek static int reference_cb_called;
572e985b929SDavid van Moolenbroek static void
reference_cb(const void * data,size_t len,void * extra)573e985b929SDavid van Moolenbroek reference_cb(const void *data, size_t len, void *extra)
574e985b929SDavid van Moolenbroek {
575e985b929SDavid van Moolenbroek 	tt_str_op(data, ==, "this is what we add as read-only memory.");
576e985b929SDavid van Moolenbroek 	tt_int_op(len, ==, strlen(data));
577e985b929SDavid van Moolenbroek 	tt_want(extra == (void *)0xdeadaffe);
578e985b929SDavid van Moolenbroek 	++reference_cb_called;
579e985b929SDavid van Moolenbroek end:
580e985b929SDavid van Moolenbroek 	;
581e985b929SDavid van Moolenbroek }
582e985b929SDavid van Moolenbroek 
583e985b929SDavid van Moolenbroek static void
test_evbuffer_reference(void * ptr)584e985b929SDavid van Moolenbroek test_evbuffer_reference(void *ptr)
585e985b929SDavid van Moolenbroek {
586e985b929SDavid van Moolenbroek 	struct evbuffer *src = evbuffer_new();
587e985b929SDavid van Moolenbroek 	struct evbuffer *dst = evbuffer_new();
588e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[1];
589e985b929SDavid van Moolenbroek 	const char *data = "this is what we add as read-only memory.";
590e985b929SDavid van Moolenbroek 	reference_cb_called = 0;
591e985b929SDavid van Moolenbroek 
592e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_add_reference(src, data, strlen(data),
593e985b929SDavid van Moolenbroek 		 reference_cb, (void *)0xdeadaffe) != -1);
594e985b929SDavid van Moolenbroek 
595e985b929SDavid van Moolenbroek 	evbuffer_reserve_space(dst, strlen(data), v, 1);
596e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1);
597e985b929SDavid van Moolenbroek 
598e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
599e985b929SDavid van Moolenbroek 	evbuffer_validate(dst);
600e985b929SDavid van Moolenbroek 
601e985b929SDavid van Moolenbroek 	/* make sure that we don't write data at the beginning */
602e985b929SDavid van Moolenbroek 	evbuffer_prepend(src, "aaaaa", 5);
603e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
604e985b929SDavid van Moolenbroek 	evbuffer_drain(src, 5);
605e985b929SDavid van Moolenbroek 
606e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10,
607e985b929SDavid van Moolenbroek 		strlen(data) - 10) != -1);
608e985b929SDavid van Moolenbroek 
609e985b929SDavid van Moolenbroek 	v[0].iov_len = strlen(data);
610e985b929SDavid van Moolenbroek 
611e985b929SDavid van Moolenbroek 	evbuffer_commit_space(dst, v, 1);
612e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
613e985b929SDavid van Moolenbroek 	evbuffer_validate(dst);
614e985b929SDavid van Moolenbroek 
615e985b929SDavid van Moolenbroek 	tt_int_op(reference_cb_called, ==, 1);
616e985b929SDavid van Moolenbroek 
617e985b929SDavid van Moolenbroek 	tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)),
618e985b929SDavid van Moolenbroek 			  data, strlen(data)));
619e985b929SDavid van Moolenbroek 	evbuffer_validate(dst);
620e985b929SDavid van Moolenbroek 
621e985b929SDavid van Moolenbroek  end:
622e985b929SDavid van Moolenbroek 	evbuffer_free(dst);
623e985b929SDavid van Moolenbroek 	evbuffer_free(src);
624e985b929SDavid van Moolenbroek }
625e985b929SDavid van Moolenbroek 
626e985b929SDavid van Moolenbroek int _evbuffer_testing_use_sendfile(void);
627e985b929SDavid van Moolenbroek int _evbuffer_testing_use_mmap(void);
628e985b929SDavid van Moolenbroek int _evbuffer_testing_use_linear_file_access(void);
629e985b929SDavid van Moolenbroek 
630e985b929SDavid van Moolenbroek static void
test_evbuffer_add_file(void * ptr)631e985b929SDavid van Moolenbroek test_evbuffer_add_file(void *ptr)
632e985b929SDavid van Moolenbroek {
633e985b929SDavid van Moolenbroek 	const char *impl = ptr;
634e985b929SDavid van Moolenbroek 	struct evbuffer *src = evbuffer_new();
635e985b929SDavid van Moolenbroek 	const char *data = "this is what we add as file system data.";
636e985b929SDavid van Moolenbroek 	size_t datalen;
637e985b929SDavid van Moolenbroek 	const char *compare;
638e985b929SDavid van Moolenbroek 	int fd = -1;
639e985b929SDavid van Moolenbroek 	evutil_socket_t xpair[2] = {-1, -1};
640e985b929SDavid van Moolenbroek 	int r=0, n_written=0;
641e985b929SDavid van Moolenbroek 
642e985b929SDavid van Moolenbroek 	/* Add a test for a big file. XXXX */
643e985b929SDavid van Moolenbroek 
644e985b929SDavid van Moolenbroek 	tt_assert(impl);
645e985b929SDavid van Moolenbroek 	if (!strcmp(impl, "sendfile")) {
646e985b929SDavid van Moolenbroek 		if (!_evbuffer_testing_use_sendfile())
647e985b929SDavid van Moolenbroek 			tt_skip();
648e985b929SDavid van Moolenbroek 		TT_BLATHER(("Using sendfile-based implementaion"));
649e985b929SDavid van Moolenbroek 	} else if (!strcmp(impl, "mmap")) {
650e985b929SDavid van Moolenbroek 		if (!_evbuffer_testing_use_mmap())
651e985b929SDavid van Moolenbroek 			tt_skip();
652e985b929SDavid van Moolenbroek 		TT_BLATHER(("Using mmap-based implementaion"));
653e985b929SDavid van Moolenbroek 	} else if (!strcmp(impl, "linear")) {
654e985b929SDavid van Moolenbroek 		if (!_evbuffer_testing_use_linear_file_access())
655e985b929SDavid van Moolenbroek 			tt_skip();
656e985b929SDavid van Moolenbroek 		TT_BLATHER(("Using read-based implementaion"));
657e985b929SDavid van Moolenbroek 	} else {
658e985b929SDavid van Moolenbroek 		TT_DIE(("Didn't recognize the implementation"));
659e985b929SDavid van Moolenbroek 	}
660e985b929SDavid van Moolenbroek 
661e985b929SDavid van Moolenbroek 	/* Say that it drains to a fd so that we can use sendfile. */
662e985b929SDavid van Moolenbroek 	evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
663e985b929SDavid van Moolenbroek 
664e985b929SDavid van Moolenbroek #if defined(_EVENT_HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
665e985b929SDavid van Moolenbroek 	/* We need to use a pair of AF_INET sockets, since Solaris
666e985b929SDavid van Moolenbroek 	   doesn't support sendfile() over AF_UNIX. */
667e985b929SDavid van Moolenbroek 	if (evutil_ersatz_socketpair(AF_INET, SOCK_STREAM, 0, xpair) == -1)
668e985b929SDavid van Moolenbroek 		tt_abort_msg("ersatz_socketpair failed");
669e985b929SDavid van Moolenbroek #else
670e985b929SDavid van Moolenbroek 	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, xpair) == -1)
671e985b929SDavid van Moolenbroek 		tt_abort_msg("socketpair failed");
672e985b929SDavid van Moolenbroek #endif
673e985b929SDavid van Moolenbroek 
674e985b929SDavid van Moolenbroek 	datalen = strlen(data);
675e985b929SDavid van Moolenbroek 	fd = regress_make_tmpfile(data, datalen);
676e985b929SDavid van Moolenbroek 
677e985b929SDavid van Moolenbroek 	tt_assert(fd != -1);
678e985b929SDavid van Moolenbroek 
679e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_add_file(src, fd, 0, datalen) != -1);
680e985b929SDavid van Moolenbroek 
681e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
682e985b929SDavid van Moolenbroek 
683e985b929SDavid van Moolenbroek 	while (evbuffer_get_length(src) &&
684e985b929SDavid van Moolenbroek 	    (r = evbuffer_write(src, xpair[0])) > 0) {
685e985b929SDavid van Moolenbroek 		evbuffer_validate(src);
686e985b929SDavid van Moolenbroek 		n_written += r;
687e985b929SDavid van Moolenbroek 	}
688e985b929SDavid van Moolenbroek 	tt_int_op(r, !=, -1);
689e985b929SDavid van Moolenbroek 	tt_int_op(n_written, ==, datalen);
690e985b929SDavid van Moolenbroek 
691e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
692e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_read(src, xpair[1], (int)strlen(data)), ==, datalen);
693e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
694e985b929SDavid van Moolenbroek 	compare = (char *)evbuffer_pullup(src, datalen);
695e985b929SDavid van Moolenbroek 	tt_assert(compare != NULL);
696e985b929SDavid van Moolenbroek 	if (memcmp(compare, data, datalen))
697e985b929SDavid van Moolenbroek 		tt_abort_msg("Data from add_file differs.");
698e985b929SDavid van Moolenbroek 
699e985b929SDavid van Moolenbroek 	evbuffer_validate(src);
700e985b929SDavid van Moolenbroek  end:
701e985b929SDavid van Moolenbroek 	if (xpair[0] >= 0)
702e985b929SDavid van Moolenbroek 		evutil_closesocket(xpair[0]);
703e985b929SDavid van Moolenbroek 	if (xpair[1] >= 0)
704e985b929SDavid van Moolenbroek 		evutil_closesocket(xpair[1]);
705e985b929SDavid van Moolenbroek 	evbuffer_free(src);
706e985b929SDavid van Moolenbroek }
707e985b929SDavid van Moolenbroek 
708e985b929SDavid van Moolenbroek #ifndef _EVENT_DISABLE_MM_REPLACEMENT
709e985b929SDavid van Moolenbroek static void *
failing_malloc(size_t how_much)710e985b929SDavid van Moolenbroek failing_malloc(size_t how_much)
711e985b929SDavid van Moolenbroek {
712e985b929SDavid van Moolenbroek 	errno = ENOMEM;
713e985b929SDavid van Moolenbroek 	return NULL;
714e985b929SDavid van Moolenbroek }
715e985b929SDavid van Moolenbroek #endif
716e985b929SDavid van Moolenbroek 
717e985b929SDavid van Moolenbroek static void
test_evbuffer_readln(void * ptr)718e985b929SDavid van Moolenbroek test_evbuffer_readln(void *ptr)
719e985b929SDavid van Moolenbroek {
720e985b929SDavid van Moolenbroek 	struct evbuffer *evb = evbuffer_new();
721e985b929SDavid van Moolenbroek 	struct evbuffer *evb_tmp = evbuffer_new();
722e985b929SDavid van Moolenbroek 	const char *s;
723e985b929SDavid van Moolenbroek 	char *cp = NULL;
724e985b929SDavid van Moolenbroek 	size_t sz;
725e985b929SDavid van Moolenbroek 
726e985b929SDavid van Moolenbroek #define tt_line_eq(content)						\
727e985b929SDavid van Moolenbroek 	TT_STMT_BEGIN							\
728e985b929SDavid van Moolenbroek 	if (!cp || sz != strlen(content) || strcmp(cp, content)) {	\
729e985b929SDavid van Moolenbroek 		TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
730e985b929SDavid van Moolenbroek 	}								\
731e985b929SDavid van Moolenbroek 	TT_STMT_END
732e985b929SDavid van Moolenbroek 
733e985b929SDavid van Moolenbroek 	/* Test EOL_ANY. */
734e985b929SDavid van Moolenbroek 	s = "complex silly newline\r\n\n\r\n\n\rmore\0\n";
735e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s)+2);
736e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
737e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
738e985b929SDavid van Moolenbroek 	tt_line_eq("complex silly newline");
739e985b929SDavid van Moolenbroek 	free(cp);
740e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
741e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
742e985b929SDavid van Moolenbroek 	if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6))
743e985b929SDavid van Moolenbroek 		tt_abort_msg("Not as expected");
744e985b929SDavid van Moolenbroek 	tt_uint_op(evbuffer_get_length(evb), ==, 0);
745e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
746e985b929SDavid van Moolenbroek 	s = "\nno newline";
747e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s));
748e985b929SDavid van Moolenbroek 	free(cp);
749e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
750e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
751e985b929SDavid van Moolenbroek 	tt_line_eq("");
752e985b929SDavid van Moolenbroek 	free(cp);
753e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
754e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY);
755e985b929SDavid van Moolenbroek 	tt_assert(!cp);
756e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
757e985b929SDavid van Moolenbroek 	evbuffer_drain(evb, evbuffer_get_length(evb));
758e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 0);
759e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
760e985b929SDavid van Moolenbroek 
761e985b929SDavid van Moolenbroek 	/* Test EOL_CRLF */
762e985b929SDavid van Moolenbroek 	s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n";
763e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s));
764e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
765e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
766e985b929SDavid van Moolenbroek 	tt_line_eq("Line with\rin the middle");
767e985b929SDavid van Moolenbroek 	free(cp);
768e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
769e985b929SDavid van Moolenbroek 
770e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
771e985b929SDavid van Moolenbroek 	tt_line_eq("Line with good crlf");
772e985b929SDavid van Moolenbroek 	free(cp);
773e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
774e985b929SDavid van Moolenbroek 
775e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
776e985b929SDavid van Moolenbroek 	tt_line_eq("");
777e985b929SDavid van Moolenbroek 	free(cp);
778e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
779e985b929SDavid van Moolenbroek 
780e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
781e985b929SDavid van Moolenbroek 	tt_line_eq("final");
782e985b929SDavid van Moolenbroek 	s = "x";
783e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
784e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, 1);
785e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
786e985b929SDavid van Moolenbroek 	free(cp);
787e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF);
788e985b929SDavid van Moolenbroek 	tt_assert(!cp);
789e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
790e985b929SDavid van Moolenbroek 
791e985b929SDavid van Moolenbroek 	/* Test CRLF_STRICT */
792e985b929SDavid van Moolenbroek 	s = " and a bad crlf\nand a good one\r\n\r\nMore\r";
793e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s));
794e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
795e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
796e985b929SDavid van Moolenbroek 	tt_line_eq("x and a bad crlf\nand a good one");
797e985b929SDavid van Moolenbroek 	free(cp);
798e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
799e985b929SDavid van Moolenbroek 
800e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
801e985b929SDavid van Moolenbroek 	tt_line_eq("");
802e985b929SDavid van Moolenbroek 	free(cp);
803e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
804e985b929SDavid van Moolenbroek 
805e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
806e985b929SDavid van Moolenbroek 	tt_assert(!cp);
807e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
808e985b929SDavid van Moolenbroek 	evbuffer_add(evb, "\n", 1);
809e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
810e985b929SDavid van Moolenbroek 
811e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
812e985b929SDavid van Moolenbroek 	tt_line_eq("More");
813e985b929SDavid van Moolenbroek 	free(cp);
814e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 0);
815e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
816e985b929SDavid van Moolenbroek 
817e985b929SDavid van Moolenbroek 	s = "An internal CR\r is not an eol\r\nNor is a lack of one";
818e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s));
819e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
820e985b929SDavid van Moolenbroek 	tt_line_eq("An internal CR\r is not an eol");
821e985b929SDavid van Moolenbroek 	free(cp);
822e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
823e985b929SDavid van Moolenbroek 
824e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
825e985b929SDavid van Moolenbroek 	tt_assert(!cp);
826e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
827e985b929SDavid van Moolenbroek 
828e985b929SDavid van Moolenbroek 	evbuffer_add(evb, "\r\n", 2);
829e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
830e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
831e985b929SDavid van Moolenbroek 	tt_line_eq("Nor is a lack of one");
832e985b929SDavid van Moolenbroek 	free(cp);
833e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 0);
834e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
835e985b929SDavid van Moolenbroek 
836e985b929SDavid van Moolenbroek 	/* Test LF */
837e985b929SDavid van Moolenbroek 	s = "An\rand a nl\n\nText";
838e985b929SDavid van Moolenbroek 	evbuffer_add(evb, s, strlen(s));
839e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
840e985b929SDavid van Moolenbroek 
841e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
842e985b929SDavid van Moolenbroek 	tt_line_eq("An\rand a nl");
843e985b929SDavid van Moolenbroek 	free(cp);
844e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
845e985b929SDavid van Moolenbroek 
846e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
847e985b929SDavid van Moolenbroek 	tt_line_eq("");
848e985b929SDavid van Moolenbroek 	free(cp);
849e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
850e985b929SDavid van Moolenbroek 
851e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
852e985b929SDavid van Moolenbroek 	tt_assert(!cp);
853e985b929SDavid van Moolenbroek 	free(cp);
854e985b929SDavid van Moolenbroek 	evbuffer_add(evb, "\n", 1);
855e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
856e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
857e985b929SDavid van Moolenbroek 	tt_line_eq("Text");
858e985b929SDavid van Moolenbroek 	free(cp);
859e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
860e985b929SDavid van Moolenbroek 
861e985b929SDavid van Moolenbroek 	/* Test CRLF_STRICT - across boundaries*/
862e985b929SDavid van Moolenbroek 	s = " and a bad crlf\nand a good one\r";
863e985b929SDavid van Moolenbroek 	evbuffer_add(evb_tmp, s, strlen(s));
864e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
865e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_tmp);
866e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
867e985b929SDavid van Moolenbroek 	s = "\n\r";
868e985b929SDavid van Moolenbroek 	evbuffer_add(evb_tmp, s, strlen(s));
869e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
870e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_tmp);
871e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
872e985b929SDavid van Moolenbroek 	s = "\nMore\r";
873e985b929SDavid van Moolenbroek 	evbuffer_add(evb_tmp, s, strlen(s));
874e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
875e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_tmp);
876e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
877e985b929SDavid van Moolenbroek 
878e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
879e985b929SDavid van Moolenbroek 	tt_line_eq(" and a bad crlf\nand a good one");
880e985b929SDavid van Moolenbroek 	free(cp);
881e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
882e985b929SDavid van Moolenbroek 
883e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
884e985b929SDavid van Moolenbroek 	tt_line_eq("");
885e985b929SDavid van Moolenbroek 	free(cp);
886e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
887e985b929SDavid van Moolenbroek 
888e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
889e985b929SDavid van Moolenbroek 	tt_assert(!cp);
890e985b929SDavid van Moolenbroek 	free(cp);
891e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
892e985b929SDavid van Moolenbroek 	evbuffer_add(evb, "\n", 1);
893e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
894e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT);
895e985b929SDavid van Moolenbroek 	tt_line_eq("More");
896e985b929SDavid van Moolenbroek 	free(cp); cp = NULL;
897e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
898e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_get_length(evb) == 0);
899e985b929SDavid van Moolenbroek 
900e985b929SDavid van Moolenbroek 	/* Test memory problem*/
901e985b929SDavid van Moolenbroek 	s = "one line\ntwo line\nblue line";
902e985b929SDavid van Moolenbroek 	evbuffer_add(evb_tmp, s, strlen(s));
903e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
904e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(evb, evb_tmp);
905e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
906e985b929SDavid van Moolenbroek 
907e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
908e985b929SDavid van Moolenbroek 	tt_line_eq("one line");
909e985b929SDavid van Moolenbroek 	free(cp); cp = NULL;
910e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
911e985b929SDavid van Moolenbroek 
912e985b929SDavid van Moolenbroek 	/* the next call to readline should fail */
913e985b929SDavid van Moolenbroek #ifndef _EVENT_DISABLE_MM_REPLACEMENT
914e985b929SDavid van Moolenbroek 	event_set_mem_functions(failing_malloc, realloc, free);
915e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
916e985b929SDavid van Moolenbroek 	tt_assert(cp == NULL);
917e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
918e985b929SDavid van Moolenbroek 
919e985b929SDavid van Moolenbroek 	/* now we should get the next line back */
920e985b929SDavid van Moolenbroek 	event_set_mem_functions(malloc, realloc, free);
921e985b929SDavid van Moolenbroek #endif
922e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF);
923e985b929SDavid van Moolenbroek 	tt_line_eq("two line");
924e985b929SDavid van Moolenbroek 	free(cp); cp = NULL;
925e985b929SDavid van Moolenbroek 	evbuffer_validate(evb);
926e985b929SDavid van Moolenbroek 
927e985b929SDavid van Moolenbroek  end:
928e985b929SDavid van Moolenbroek 	evbuffer_free(evb);
929e985b929SDavid van Moolenbroek 	evbuffer_free(evb_tmp);
930e985b929SDavid van Moolenbroek 	if (cp) free(cp);
931e985b929SDavid van Moolenbroek }
932e985b929SDavid van Moolenbroek 
933e985b929SDavid van Moolenbroek static void
test_evbuffer_search_eol(void * ptr)934e985b929SDavid van Moolenbroek test_evbuffer_search_eol(void *ptr)
935e985b929SDavid van Moolenbroek {
936e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
937e985b929SDavid van Moolenbroek 	struct evbuffer_ptr ptr1, ptr2;
938e985b929SDavid van Moolenbroek 	const char *s;
939e985b929SDavid van Moolenbroek 	size_t eol_len;
940e985b929SDavid van Moolenbroek 
941e985b929SDavid van Moolenbroek 	s = "string! \r\n\r\nx\n";
942e985b929SDavid van Moolenbroek 	evbuffer_add(buf, s, strlen(s));
943e985b929SDavid van Moolenbroek 	eol_len = -1;
944e985b929SDavid van Moolenbroek 	ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF);
945e985b929SDavid van Moolenbroek 	tt_int_op(ptr1.pos, ==, 8);
946e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 2);
947e985b929SDavid van Moolenbroek 
948e985b929SDavid van Moolenbroek 	eol_len = -1;
949e985b929SDavid van Moolenbroek 	ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
950e985b929SDavid van Moolenbroek 	tt_int_op(ptr2.pos, ==, 8);
951e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 2);
952e985b929SDavid van Moolenbroek 
953e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
954e985b929SDavid van Moolenbroek 	eol_len = -1;
955e985b929SDavid van Moolenbroek 	ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF);
956e985b929SDavid van Moolenbroek 	tt_int_op(ptr2.pos, ==, 9);
957e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 1);
958e985b929SDavid van Moolenbroek 
959e985b929SDavid van Moolenbroek 	eol_len = -1;
960e985b929SDavid van Moolenbroek 	ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT);
961e985b929SDavid van Moolenbroek 	tt_int_op(ptr2.pos, ==, 10);
962e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 2);
963e985b929SDavid van Moolenbroek 
964e985b929SDavid van Moolenbroek 	eol_len = -1;
965e985b929SDavid van Moolenbroek 	ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF);
966e985b929SDavid van Moolenbroek 	tt_int_op(ptr1.pos, ==, 9);
967e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 1);
968e985b929SDavid van Moolenbroek 
969e985b929SDavid van Moolenbroek 	eol_len = -1;
970e985b929SDavid van Moolenbroek 	ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
971e985b929SDavid van Moolenbroek 	tt_int_op(ptr2.pos, ==, 9);
972e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 1);
973e985b929SDavid van Moolenbroek 
974e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD);
975e985b929SDavid van Moolenbroek 	eol_len = -1;
976e985b929SDavid van Moolenbroek 	ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
977e985b929SDavid van Moolenbroek 	tt_int_op(ptr2.pos, ==, 11);
978e985b929SDavid van Moolenbroek 	tt_int_op(eol_len, ==, 1);
979e985b929SDavid van Moolenbroek 
980e985b929SDavid van Moolenbroek end:
981e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
982e985b929SDavid van Moolenbroek }
983e985b929SDavid van Moolenbroek 
984e985b929SDavid van Moolenbroek static void
test_evbuffer_iterative(void * ptr)985e985b929SDavid van Moolenbroek test_evbuffer_iterative(void *ptr)
986e985b929SDavid van Moolenbroek {
987e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
988e985b929SDavid van Moolenbroek 	const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
989e985b929SDavid van Moolenbroek 	unsigned i, j, sum, n;
990e985b929SDavid van Moolenbroek 
991e985b929SDavid van Moolenbroek 	sum = 0;
992e985b929SDavid van Moolenbroek 	n = 0;
993e985b929SDavid van Moolenbroek 	for (i = 0; i < 1000; ++i) {
994e985b929SDavid van Moolenbroek 		for (j = 1; j < strlen(abc); ++j) {
995*0a6a1f1dSLionel Sambuc 			char format[32];
996*0a6a1f1dSLionel Sambuc 			evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j);
997*0a6a1f1dSLionel Sambuc 			evbuffer_add_printf(buf, fmtcheck(format, "%s"), abc);
998e985b929SDavid van Moolenbroek 
999e985b929SDavid van Moolenbroek 			/* Only check for rep violations every so often.
1000e985b929SDavid van Moolenbroek 			   Walking over the whole list of chains can get
1001e985b929SDavid van Moolenbroek 			   pretty expensive as it gets long.
1002e985b929SDavid van Moolenbroek 			 */
1003e985b929SDavid van Moolenbroek 			if ((n % 337) == 0)
1004e985b929SDavid van Moolenbroek 				evbuffer_validate(buf);
1005e985b929SDavid van Moolenbroek 
1006e985b929SDavid van Moolenbroek 			sum += j;
1007e985b929SDavid van Moolenbroek 			n++;
1008e985b929SDavid van Moolenbroek 		}
1009e985b929SDavid van Moolenbroek 	}
1010e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1011e985b929SDavid van Moolenbroek 
1012e985b929SDavid van Moolenbroek 	tt_uint_op(sum, ==, evbuffer_get_length(buf));
1013e985b929SDavid van Moolenbroek 
1014e985b929SDavid van Moolenbroek 	{
1015e985b929SDavid van Moolenbroek 		size_t a,w,u;
1016e985b929SDavid van Moolenbroek 		a=w=u=0;
1017e985b929SDavid van Moolenbroek 		evbuffer_get_waste(buf, &a, &w, &u);
1018e985b929SDavid van Moolenbroek 		if (0)
1019e985b929SDavid van Moolenbroek 			printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
1020e985b929SDavid van Moolenbroek 			    (unsigned)a, (unsigned)w, (unsigned)u);
1021e985b929SDavid van Moolenbroek 		tt_assert( ((double)w)/a < .125);
1022e985b929SDavid van Moolenbroek 	}
1023e985b929SDavid van Moolenbroek  end:
1024e985b929SDavid van Moolenbroek 	evbuffer_free(buf);
1025e985b929SDavid van Moolenbroek 
1026e985b929SDavid van Moolenbroek }
1027e985b929SDavid van Moolenbroek 
1028e985b929SDavid van Moolenbroek static void
test_evbuffer_find(void * ptr)1029e985b929SDavid van Moolenbroek test_evbuffer_find(void *ptr)
1030e985b929SDavid van Moolenbroek {
1031e985b929SDavid van Moolenbroek 	u_char* p;
1032e985b929SDavid van Moolenbroek 	const char* test1 = "1234567890\r\n";
1033e985b929SDavid van Moolenbroek 	const char* test2 = "1234567890\r";
1034e985b929SDavid van Moolenbroek #define EVBUFFER_INITIAL_LENGTH 256
1035e985b929SDavid van Moolenbroek 	char test3[EVBUFFER_INITIAL_LENGTH];
1036e985b929SDavid van Moolenbroek 	unsigned int i;
1037e985b929SDavid van Moolenbroek 	struct evbuffer * buf = evbuffer_new();
1038e985b929SDavid van Moolenbroek 
1039e985b929SDavid van Moolenbroek 	tt_assert(buf);
1040e985b929SDavid van Moolenbroek 
1041e985b929SDavid van Moolenbroek 	/* make sure evbuffer_find doesn't match past the end of the buffer */
1042e985b929SDavid van Moolenbroek 	evbuffer_add(buf, __UNCONST(test1), strlen(test1));
1043e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1044e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, strlen(test1));
1045e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1046e985b929SDavid van Moolenbroek 	evbuffer_add(buf, __UNCONST(test2), strlen(test2));
1047e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1048e985b929SDavid van Moolenbroek 	p = evbuffer_find(buf, __UNCONST("\r\n"), 2);
1049e985b929SDavid van Moolenbroek 	tt_want(p == NULL);
1050e985b929SDavid van Moolenbroek 
1051e985b929SDavid van Moolenbroek 	/*
1052e985b929SDavid van Moolenbroek 	 * drain the buffer and do another find; in r309 this would
1053e985b929SDavid van Moolenbroek 	 * read past the allocated buffer causing a valgrind error.
1054e985b929SDavid van Moolenbroek 	 */
1055e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, strlen(test2));
1056e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1057e985b929SDavid van Moolenbroek 	for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
1058e985b929SDavid van Moolenbroek 		test3[i] = 'a';
1059e985b929SDavid van Moolenbroek 	test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
1060e985b929SDavid van Moolenbroek 	evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
1061e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1062e985b929SDavid van Moolenbroek 	p = evbuffer_find(buf, __UNCONST("xy"), 2);
1063e985b929SDavid van Moolenbroek 	tt_want(p == NULL);
1064e985b929SDavid van Moolenbroek 
1065e985b929SDavid van Moolenbroek 	/* simple test for match at end of allocated buffer */
1066e985b929SDavid van Moolenbroek 	p = evbuffer_find(buf, __UNCONST("ax"), 2);
1067e985b929SDavid van Moolenbroek 	tt_assert(p != NULL);
1068e985b929SDavid van Moolenbroek 	tt_want(strncmp((char*)p, "ax", 2) == 0);
1069e985b929SDavid van Moolenbroek 
1070e985b929SDavid van Moolenbroek end:
1071e985b929SDavid van Moolenbroek 	if (buf)
1072e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1073e985b929SDavid van Moolenbroek }
1074e985b929SDavid van Moolenbroek 
1075e985b929SDavid van Moolenbroek static void
test_evbuffer_ptr_set(void * ptr)1076e985b929SDavid van Moolenbroek test_evbuffer_ptr_set(void *ptr)
1077e985b929SDavid van Moolenbroek {
1078e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
1079e985b929SDavid van Moolenbroek 	struct evbuffer_ptr pos;
1080e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[1];
1081e985b929SDavid van Moolenbroek 
1082e985b929SDavid van Moolenbroek 	tt_assert(buf);
1083e985b929SDavid van Moolenbroek 
1084e985b929SDavid van Moolenbroek 	/* create some chains */
1085e985b929SDavid van Moolenbroek 	evbuffer_reserve_space(buf, 5000, v, 1);
1086e985b929SDavid van Moolenbroek 	v[0].iov_len = 5000;
1087e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 1, v[0].iov_len);
1088e985b929SDavid van Moolenbroek 	evbuffer_commit_space(buf, v, 1);
1089e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1090e985b929SDavid van Moolenbroek 
1091e985b929SDavid van Moolenbroek 	evbuffer_reserve_space(buf, 4000, v, 1);
1092e985b929SDavid van Moolenbroek 	v[0].iov_len = 4000;
1093e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 2, v[0].iov_len);
1094e985b929SDavid van Moolenbroek 	evbuffer_commit_space(buf, v, 1);
1095e985b929SDavid van Moolenbroek 
1096e985b929SDavid van Moolenbroek 	evbuffer_reserve_space(buf, 3000, v, 1);
1097e985b929SDavid van Moolenbroek 	v[0].iov_len = 3000;
1098e985b929SDavid van Moolenbroek 	memset(v[0].iov_base, 3, v[0].iov_len);
1099e985b929SDavid van Moolenbroek 	evbuffer_commit_space(buf, v, 1);
1100e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1101e985b929SDavid van Moolenbroek 
1102e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf), ==, 12000);
1103e985b929SDavid van Moolenbroek 
1104e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
1105e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == -1);
1106e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
1107e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == 0);
1108e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1);
1109e985b929SDavid van Moolenbroek 
1110e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
1111e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == 0);
1112e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0);
1113e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == 10000);
1114e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
1115e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == 11000);
1116e985b929SDavid van Moolenbroek 	tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
1117e985b929SDavid van Moolenbroek 	tt_assert(pos.pos == -1);
1118e985b929SDavid van Moolenbroek 
1119e985b929SDavid van Moolenbroek end:
1120e985b929SDavid van Moolenbroek 	if (buf)
1121e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1122e985b929SDavid van Moolenbroek }
1123e985b929SDavid van Moolenbroek 
1124e985b929SDavid van Moolenbroek static void
test_evbuffer_search(void * ptr)1125e985b929SDavid van Moolenbroek test_evbuffer_search(void *ptr)
1126e985b929SDavid van Moolenbroek {
1127e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
1128e985b929SDavid van Moolenbroek 	struct evbuffer *tmp = evbuffer_new();
1129e985b929SDavid van Moolenbroek 	struct evbuffer_ptr pos, end;
1130e985b929SDavid van Moolenbroek 
1131e985b929SDavid van Moolenbroek 	tt_assert(buf);
1132e985b929SDavid van Moolenbroek 	tt_assert(tmp);
1133e985b929SDavid van Moolenbroek 
1134e985b929SDavid van Moolenbroek 	/* set up our chains */
1135e985b929SDavid van Moolenbroek 	evbuffer_add_printf(tmp, "hello");  /* 5 chars */
1136e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(buf, tmp);
1137e985b929SDavid van Moolenbroek 	evbuffer_add_printf(tmp, "foo");    /* 3 chars */
1138e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(buf, tmp);
1139e985b929SDavid van Moolenbroek 	evbuffer_add_printf(tmp, "cat");    /* 3 chars */
1140e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(buf, tmp);
1141e985b929SDavid van Moolenbroek 	evbuffer_add_printf(tmp, "attack");
1142e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(buf, tmp);
1143e985b929SDavid van Moolenbroek 
1144e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "attack", 6, NULL);
1145e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 11);
1146e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "attacker", 8, NULL);
1147e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, -1);
1148e985b929SDavid van Moolenbroek 
1149e985b929SDavid van Moolenbroek 	/* test continuing search */
1150e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "oc", 2, NULL);
1151e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 7);
1152e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "cat", 3, &pos);
1153e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 8);
1154e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "tacking", 7, &pos);
1155e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, -1);
1156e985b929SDavid van Moolenbroek 
1157e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET);
1158e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "foo", 3, &pos);
1159e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 5);
1160e985b929SDavid van Moolenbroek 
1161e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD);
1162e985b929SDavid van Moolenbroek 	pos = evbuffer_search(buf, "tat", 3, &pos);
1163e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 10);
1164e985b929SDavid van Moolenbroek 
1165e985b929SDavid van Moolenbroek 	/* test bounded search. */
1166e985b929SDavid van Moolenbroek 	/* Set "end" to the first t in "attack". */
1167e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
1168e985b929SDavid van Moolenbroek 	pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
1169e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 5);
1170e985b929SDavid van Moolenbroek 	pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
1171e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, 5);
1172e985b929SDavid van Moolenbroek 	pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
1173e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, -1);
1174e985b929SDavid van Moolenbroek 	pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
1175e985b929SDavid van Moolenbroek 	tt_int_op(pos.pos, ==, -1);
1176e985b929SDavid van Moolenbroek 
1177e985b929SDavid van Moolenbroek 
1178e985b929SDavid van Moolenbroek end:
1179e985b929SDavid van Moolenbroek 	if (buf)
1180e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1181e985b929SDavid van Moolenbroek 	if (tmp)
1182e985b929SDavid van Moolenbroek 		evbuffer_free(tmp);
1183e985b929SDavid van Moolenbroek }
1184e985b929SDavid van Moolenbroek 
1185e985b929SDavid van Moolenbroek static void
log_change_callback(struct evbuffer * buffer,const struct evbuffer_cb_info * cbinfo,void * arg)1186e985b929SDavid van Moolenbroek log_change_callback(struct evbuffer *buffer,
1187e985b929SDavid van Moolenbroek     const struct evbuffer_cb_info *cbinfo,
1188e985b929SDavid van Moolenbroek     void *arg)
1189e985b929SDavid van Moolenbroek {
1190e985b929SDavid van Moolenbroek 
1191e985b929SDavid van Moolenbroek 	size_t old_len = cbinfo->orig_size;
1192e985b929SDavid van Moolenbroek 	size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
1193e985b929SDavid van Moolenbroek 	struct evbuffer *out = arg;
1194e985b929SDavid van Moolenbroek 	evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len,
1195e985b929SDavid van Moolenbroek 			    (unsigned long)new_len);
1196e985b929SDavid van Moolenbroek }
1197e985b929SDavid van Moolenbroek static void
self_draining_callback(struct evbuffer * evbuffer,size_t old_len,size_t new_len,void * arg)1198e985b929SDavid van Moolenbroek self_draining_callback(struct evbuffer *evbuffer, size_t old_len,
1199e985b929SDavid van Moolenbroek 		size_t new_len, void *arg)
1200e985b929SDavid van Moolenbroek {
1201e985b929SDavid van Moolenbroek 	if (new_len > old_len)
1202e985b929SDavid van Moolenbroek 		evbuffer_drain(evbuffer, new_len);
1203e985b929SDavid van Moolenbroek }
1204e985b929SDavid van Moolenbroek 
1205e985b929SDavid van Moolenbroek static void
test_evbuffer_callbacks(void * ptr)1206e985b929SDavid van Moolenbroek test_evbuffer_callbacks(void *ptr)
1207e985b929SDavid van Moolenbroek {
1208e985b929SDavid van Moolenbroek 	struct evbuffer *buf = evbuffer_new();
1209e985b929SDavid van Moolenbroek 	struct evbuffer *buf_out1 = evbuffer_new();
1210e985b929SDavid van Moolenbroek 	struct evbuffer *buf_out2 = evbuffer_new();
1211e985b929SDavid van Moolenbroek 	struct evbuffer_cb_entry *cb1, *cb2;
1212e985b929SDavid van Moolenbroek 
1213e985b929SDavid van Moolenbroek 	tt_assert(buf);
1214e985b929SDavid van Moolenbroek 	tt_assert(buf_out1);
1215e985b929SDavid van Moolenbroek 	tt_assert(buf_out2);
1216e985b929SDavid van Moolenbroek 
1217e985b929SDavid van Moolenbroek 	cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1218e985b929SDavid van Moolenbroek 	cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1219e985b929SDavid van Moolenbroek 
1220e985b929SDavid van Moolenbroek 	/* Let's run through adding and deleting some stuff from the buffer
1221e985b929SDavid van Moolenbroek 	 * and turning the callbacks on and off and removing them.  The callback
1222e985b929SDavid van Moolenbroek 	 * adds a summary of length changes to buf_out1/buf_out2 when called. */
1223e985b929SDavid van Moolenbroek 	/* size: 0-> 36. */
1224e985b929SDavid van Moolenbroek 	evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
1225e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1226e985b929SDavid van Moolenbroek 	evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
1227e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, 10); /*36->26*/
1228e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1229e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf, "Hello", 5);/*26->31*/
1230e985b929SDavid van Moolenbroek 	evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
1231e985b929SDavid van Moolenbroek 	evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
1232e985b929SDavid van Moolenbroek 	evbuffer_remove_cb_entry(buf, cb1);
1233e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1234e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
1235e985b929SDavid van Moolenbroek 	tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
1236e985b929SDavid van Moolenbroek 	evbuffer_add(buf, "X", 1); /* 0->1 */
1237e985b929SDavid van Moolenbroek 	tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
1238e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1239e985b929SDavid van Moolenbroek 
1240e985b929SDavid van Moolenbroek 	tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
1241e985b929SDavid van Moolenbroek 		  "0->36; 36->26; 26->31; 31->38; ");
1242e985b929SDavid van Moolenbroek 	tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
1243e985b929SDavid van Moolenbroek 		  "0->36; 31->38; 38->0; 0->1; ");
1244e985b929SDavid van Moolenbroek 	evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
1245e985b929SDavid van Moolenbroek 	evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
1246e985b929SDavid van Moolenbroek 	/* Let's test the obsolete buffer_setcb function too. */
1247e985b929SDavid van Moolenbroek 	cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1248e985b929SDavid van Moolenbroek 	tt_assert(cb1 != NULL);
1249e985b929SDavid van Moolenbroek 	cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1250e985b929SDavid van Moolenbroek 	tt_assert(cb2 != NULL);
1251e985b929SDavid van Moolenbroek 	evbuffer_setcb(buf, self_draining_callback, NULL);
1252e985b929SDavid van Moolenbroek 	evbuffer_add_printf(buf, "This should get drained right away.");
1253e985b929SDavid van Moolenbroek 	tt_uint_op(evbuffer_get_length(buf), ==, 0);
1254e985b929SDavid van Moolenbroek 	tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
1255e985b929SDavid van Moolenbroek 	tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
1256e985b929SDavid van Moolenbroek 	evbuffer_setcb(buf, NULL, NULL);
1257e985b929SDavid van Moolenbroek 	evbuffer_add_printf(buf, "This will not.");
1258e985b929SDavid van Moolenbroek 	tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
1259e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1260e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, evbuffer_get_length(buf));
1261e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1262e985b929SDavid van Moolenbroek #if 0
1263e985b929SDavid van Moolenbroek 	/* Now let's try a suspended callback. */
1264e985b929SDavid van Moolenbroek 	cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1265e985b929SDavid van Moolenbroek 	cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1266e985b929SDavid van Moolenbroek 	evbuffer_cb_suspend(buf,cb2);
1267e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf,"Hello world",11); /*0->11*/
1268e985b929SDavid van Moolenbroek 	evbuffer_validate(buf);
1269e985b929SDavid van Moolenbroek 	evbuffer_cb_suspend(buf,cb1);
1270e985b929SDavid van Moolenbroek 	evbuffer_add(buf,"more",4); /* 11->15 */
1271e985b929SDavid van Moolenbroek 	evbuffer_cb_unsuspend(buf,cb2);
1272e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, 4); /* 15->11 */
1273e985b929SDavid van Moolenbroek 	evbuffer_cb_unsuspend(buf,cb1);
1274e985b929SDavid van Moolenbroek 	evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */
1275e985b929SDavid van Moolenbroek 
1276e985b929SDavid van Moolenbroek 	tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
1277e985b929SDavid van Moolenbroek 		  "0->11; 11->11; 11->0; ");
1278e985b929SDavid van Moolenbroek 	tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
1279e985b929SDavid van Moolenbroek 		  "0->15; 15->11; 11->0; ");
1280e985b929SDavid van Moolenbroek #endif
1281e985b929SDavid van Moolenbroek 
1282e985b929SDavid van Moolenbroek  end:
1283e985b929SDavid van Moolenbroek 	if (buf)
1284e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1285e985b929SDavid van Moolenbroek 	if (buf_out1)
1286e985b929SDavid van Moolenbroek 		evbuffer_free(buf_out1);
1287e985b929SDavid van Moolenbroek 	if (buf_out2)
1288e985b929SDavid van Moolenbroek 		evbuffer_free(buf_out2);
1289e985b929SDavid van Moolenbroek }
1290e985b929SDavid van Moolenbroek 
1291e985b929SDavid van Moolenbroek static int ref_done_cb_called_count = 0;
1292e985b929SDavid van Moolenbroek static void *ref_done_cb_called_with = NULL;
1293e985b929SDavid van Moolenbroek static const void *ref_done_cb_called_with_data = NULL;
1294e985b929SDavid van Moolenbroek static size_t ref_done_cb_called_with_len = 0;
ref_done_cb(const void * data,size_t len,void * info)1295e985b929SDavid van Moolenbroek static void ref_done_cb(const void *data, size_t len, void *info)
1296e985b929SDavid van Moolenbroek {
1297e985b929SDavid van Moolenbroek 	++ref_done_cb_called_count;
1298e985b929SDavid van Moolenbroek 	ref_done_cb_called_with = info;
1299e985b929SDavid van Moolenbroek 	ref_done_cb_called_with_data = data;
1300e985b929SDavid van Moolenbroek 	ref_done_cb_called_with_len = len;
1301e985b929SDavid van Moolenbroek }
1302e985b929SDavid van Moolenbroek 
1303e985b929SDavid van Moolenbroek static void
test_evbuffer_add_reference(void * ptr)1304e985b929SDavid van Moolenbroek test_evbuffer_add_reference(void *ptr)
1305e985b929SDavid van Moolenbroek {
1306e985b929SDavid van Moolenbroek 	const char chunk1[] = "If you have found the answer to such a problem";
1307e985b929SDavid van Moolenbroek 	const char chunk2[] = "you ought to write it up for publication";
1308e985b929SDavid van Moolenbroek 			  /* -- Knuth's "Notes on the Exercises" from TAOCP */
1309e985b929SDavid van Moolenbroek 	char tmp[16];
1310e985b929SDavid van Moolenbroek 	size_t len1 = strlen(chunk1), len2=strlen(chunk2);
1311e985b929SDavid van Moolenbroek 
1312e985b929SDavid van Moolenbroek 	struct evbuffer *buf1 = NULL, *buf2 = NULL;
1313e985b929SDavid van Moolenbroek 
1314e985b929SDavid van Moolenbroek 	buf1 = evbuffer_new();
1315e985b929SDavid van Moolenbroek 	tt_assert(buf1);
1316e985b929SDavid van Moolenbroek 
1317e985b929SDavid van Moolenbroek 	evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111);
1318e985b929SDavid van Moolenbroek 	evbuffer_add(buf1, ", ", 2);
1319e985b929SDavid van Moolenbroek 	evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222);
1320e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
1321e985b929SDavid van Moolenbroek 
1322e985b929SDavid van Moolenbroek 	/* Make sure we can drain a little from a reference. */
1323e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
1324e985b929SDavid van Moolenbroek 	tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
1325e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
1326e985b929SDavid van Moolenbroek 	tt_int_op(memcmp(tmp, " have", 5), ==, 0);
1327e985b929SDavid van Moolenbroek 
1328e985b929SDavid van Moolenbroek 	/* Make sure that prepending does not meddle with immutable data */
1329e985b929SDavid van Moolenbroek 	tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
1330e985b929SDavid van Moolenbroek 	tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
1331e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1332e985b929SDavid van Moolenbroek 
1333e985b929SDavid van Moolenbroek 	/* Make sure that when the chunk is over, the callback is invoked. */
1334e985b929SDavid van Moolenbroek 	evbuffer_drain(buf1, 7); /* Remove prepended stuff. */
1335e985b929SDavid van Moolenbroek 	evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */
1336e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 0);
1337e985b929SDavid van Moolenbroek 	evbuffer_remove(buf1, tmp, 1);
1338e985b929SDavid van Moolenbroek 	tt_int_op(tmp[0], ==, 'm');
1339e985b929SDavid van Moolenbroek 	tt_assert(ref_done_cb_called_with == (void*)111);
1340e985b929SDavid van Moolenbroek 	tt_assert(ref_done_cb_called_with_data == chunk1);
1341e985b929SDavid van Moolenbroek 	tt_assert(ref_done_cb_called_with_len == len1);
1342e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 1);
1343e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1344e985b929SDavid van Moolenbroek 
1345e985b929SDavid van Moolenbroek 	/* Drain some of the remaining chunk, then add it to another buffer */
1346e985b929SDavid van Moolenbroek 	evbuffer_drain(buf1, 6); /* Remove the ", you ". */
1347e985b929SDavid van Moolenbroek 	buf2 = evbuffer_new();
1348e985b929SDavid van Moolenbroek 	tt_assert(buf2);
1349e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 1);
1350e985b929SDavid van Moolenbroek 	evbuffer_add(buf2, "I ", 2);
1351e985b929SDavid van Moolenbroek 
1352e985b929SDavid van Moolenbroek 	evbuffer_add_buffer(buf2, buf1);
1353e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 1);
1354e985b929SDavid van Moolenbroek 	evbuffer_remove(buf2, tmp, 16);
1355e985b929SDavid van Moolenbroek 	tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0);
1356e985b929SDavid van Moolenbroek 	evbuffer_drain(buf2, evbuffer_get_length(buf2));
1357e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 2);
1358e985b929SDavid van Moolenbroek 	tt_assert(ref_done_cb_called_with == (void*)222);
1359e985b929SDavid van Moolenbroek 	evbuffer_validate(buf2);
1360e985b929SDavid van Moolenbroek 
1361e985b929SDavid van Moolenbroek 	/* Now add more stuff to buf1 and make sure that it gets removed on
1362e985b929SDavid van Moolenbroek 	 * free. */
1363e985b929SDavid van Moolenbroek 	evbuffer_add(buf1, "You shake and shake the ", 24);
1364e985b929SDavid van Moolenbroek 	evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
1365e985b929SDavid van Moolenbroek 	    (void*)3333);
1366e985b929SDavid van Moolenbroek 	evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 42);
1367e985b929SDavid van Moolenbroek 	evbuffer_free(buf1);
1368e985b929SDavid van Moolenbroek 	buf1 = NULL;
1369e985b929SDavid van Moolenbroek 	tt_int_op(ref_done_cb_called_count, ==, 3);
1370e985b929SDavid van Moolenbroek 	tt_assert(ref_done_cb_called_with == (void*)3333);
1371e985b929SDavid van Moolenbroek 
1372e985b929SDavid van Moolenbroek end:
1373e985b929SDavid van Moolenbroek 	if (buf1)
1374e985b929SDavid van Moolenbroek 		evbuffer_free(buf1);
1375e985b929SDavid van Moolenbroek 	if (buf2)
1376e985b929SDavid van Moolenbroek 		evbuffer_free(buf2);
1377e985b929SDavid van Moolenbroek }
1378e985b929SDavid van Moolenbroek 
1379e985b929SDavid van Moolenbroek /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
1380e985b929SDavid van Moolenbroek static void
test_evbuffer_prepend(void * ptr)1381e985b929SDavid van Moolenbroek test_evbuffer_prepend(void *ptr)
1382e985b929SDavid van Moolenbroek {
1383e985b929SDavid van Moolenbroek 	struct evbuffer *buf1 = NULL, *buf2 = NULL;
1384e985b929SDavid van Moolenbroek 	char tmp[128];
1385e985b929SDavid van Moolenbroek 	int n;
1386e985b929SDavid van Moolenbroek 
1387e985b929SDavid van Moolenbroek 	buf1 = evbuffer_new();
1388e985b929SDavid van Moolenbroek 	tt_assert(buf1);
1389e985b929SDavid van Moolenbroek 
1390e985b929SDavid van Moolenbroek 	/* Case 0: The evbuffer is entirely empty. */
1391e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf1, "This string has 29 characters", 29);
1392e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1393e985b929SDavid van Moolenbroek 
1394e985b929SDavid van Moolenbroek 	/* Case 1: Prepend goes entirely in new chunk. */
1395e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf1, "Short.", 6);
1396e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1397e985b929SDavid van Moolenbroek 
1398e985b929SDavid van Moolenbroek 	/* Case 2: prepend goes entirely in first chunk. */
1399e985b929SDavid van Moolenbroek 	evbuffer_drain(buf1, 6+11);
1400e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf1, "it", 2);
1401e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1402e985b929SDavid van Moolenbroek 	tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign,
1403e985b929SDavid van Moolenbroek 		"it has", 6));
1404e985b929SDavid van Moolenbroek 
1405e985b929SDavid van Moolenbroek 	/* Case 3: prepend is split over multiple chunks. */
1406e985b929SDavid van Moolenbroek 	evbuffer_prepend(buf1, "It is no longer true to say ", 28);
1407e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1408e985b929SDavid van Moolenbroek 	n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
1409e985b929SDavid van Moolenbroek 	tmp[n]='\0';
1410e985b929SDavid van Moolenbroek 	tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
1411e985b929SDavid van Moolenbroek 
1412e985b929SDavid van Moolenbroek 	buf2 = evbuffer_new();
1413e985b929SDavid van Moolenbroek 	tt_assert(buf2);
1414e985b929SDavid van Moolenbroek 
1415e985b929SDavid van Moolenbroek 	/* Case 4: prepend a buffer to an empty buffer. */
1416e985b929SDavid van Moolenbroek 	n = 999;
1417e985b929SDavid van Moolenbroek 	evbuffer_add_printf(buf1, "Here is string %d. ", n++);
1418e985b929SDavid van Moolenbroek 	evbuffer_prepend_buffer(buf2, buf1);
1419e985b929SDavid van Moolenbroek 	evbuffer_validate(buf2);
1420e985b929SDavid van Moolenbroek 
1421e985b929SDavid van Moolenbroek 	/* Case 5: prepend a buffer to a nonempty buffer. */
1422e985b929SDavid van Moolenbroek 	evbuffer_add_printf(buf1, "Here is string %d. ", n++);
1423e985b929SDavid van Moolenbroek 	evbuffer_prepend_buffer(buf2, buf1);
1424e985b929SDavid van Moolenbroek 	evbuffer_validate(buf2);
1425e985b929SDavid van Moolenbroek 	evbuffer_validate(buf1);
1426e985b929SDavid van Moolenbroek 	n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
1427e985b929SDavid van Moolenbroek 	tmp[n]='\0';
1428e985b929SDavid van Moolenbroek 	tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
1429e985b929SDavid van Moolenbroek 
1430e985b929SDavid van Moolenbroek end:
1431e985b929SDavid van Moolenbroek 	if (buf1)
1432e985b929SDavid van Moolenbroek 		evbuffer_free(buf1);
1433e985b929SDavid van Moolenbroek 	if (buf2)
1434e985b929SDavid van Moolenbroek 		evbuffer_free(buf2);
1435e985b929SDavid van Moolenbroek 
1436e985b929SDavid van Moolenbroek }
1437e985b929SDavid van Moolenbroek 
1438e985b929SDavid van Moolenbroek static void
test_evbuffer_peek(void * info)1439e985b929SDavid van Moolenbroek test_evbuffer_peek(void *info)
1440e985b929SDavid van Moolenbroek {
1441e985b929SDavid van Moolenbroek 	struct evbuffer *buf = NULL, *tmp_buf = NULL;
1442e985b929SDavid van Moolenbroek 	int i;
1443e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[20];
1444e985b929SDavid van Moolenbroek 	struct evbuffer_ptr ptr;
1445e985b929SDavid van Moolenbroek 
1446e985b929SDavid van Moolenbroek #define tt_iov_eq(v, s)						\
1447e985b929SDavid van Moolenbroek 	tt_int_op((v)->iov_len, ==, strlen(s));			\
1448e985b929SDavid van Moolenbroek 	tt_assert(!memcmp((v)->iov_base, (s), strlen(s)))
1449e985b929SDavid van Moolenbroek 
1450e985b929SDavid van Moolenbroek 	/* Let's make a very fragmented buffer. */
1451e985b929SDavid van Moolenbroek 	buf = evbuffer_new();
1452e985b929SDavid van Moolenbroek 	tmp_buf = evbuffer_new();
1453e985b929SDavid van Moolenbroek 	for (i = 0; i < 16; ++i) {
1454e985b929SDavid van Moolenbroek 		evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i);
1455e985b929SDavid van Moolenbroek 		evbuffer_add_buffer(buf, tmp_buf);
1456e985b929SDavid van Moolenbroek 	}
1457e985b929SDavid van Moolenbroek 
1458e985b929SDavid van Moolenbroek 	/* How many chunks do we need for everything? */
1459e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, -1, NULL, NULL, 0);
1460e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 16);
1461e985b929SDavid van Moolenbroek 
1462e985b929SDavid van Moolenbroek 	/* Simple peek: get everything. */
1463e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, -1, NULL, v, 20);
1464e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 16); /* we used only 16 chunks. */
1465e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1466e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[3], "Contents of chunk [3]\n");
1467e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[12], "Contents of chunk [12]\n");
1468e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[15], "Contents of chunk [15]\n");
1469e985b929SDavid van Moolenbroek 
1470e985b929SDavid van Moolenbroek 	/* Just get one chunk worth. */
1471e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1472e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, -1, NULL, v, 1);
1473e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 1);
1474e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1475e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_base == NULL);
1476e985b929SDavid van Moolenbroek 
1477e985b929SDavid van Moolenbroek 	/* Suppose we want at least the first 40 bytes. */
1478e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1479e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 40, NULL, v, 16);
1480e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 2);
1481e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1482e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[1], "Contents of chunk [1]\n");
1483e985b929SDavid van Moolenbroek 	tt_assert(v[2].iov_base == NULL);
1484e985b929SDavid van Moolenbroek 
1485e985b929SDavid van Moolenbroek 	/* How many chunks do we need for 100 bytes? */
1486e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1487e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 100, NULL, NULL, 0);
1488e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 5);
1489e985b929SDavid van Moolenbroek 	tt_assert(v[0].iov_base == NULL);
1490e985b929SDavid van Moolenbroek 
1491e985b929SDavid van Moolenbroek 	/* Now we ask for more bytes than we provide chunks for */
1492e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1493e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 60, NULL, v, 1);
1494e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 3);
1495e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1496e985b929SDavid van Moolenbroek 	tt_assert(v[1].iov_base == NULL);
1497e985b929SDavid van Moolenbroek 
1498e985b929SDavid van Moolenbroek 	/* Now we ask for more bytes than the buffer has. */
1499e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1500e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 65536, NULL, v, 20);
1501e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 16); /* we used only 16 chunks. */
1502e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1503e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[3], "Contents of chunk [3]\n");
1504e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[12], "Contents of chunk [12]\n");
1505e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[15], "Contents of chunk [15]\n");
1506e985b929SDavid van Moolenbroek 	tt_assert(v[16].iov_base == NULL);
1507e985b929SDavid van Moolenbroek 
1508e985b929SDavid van Moolenbroek 	/* What happens if we try an empty buffer? */
1509e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1510e985b929SDavid van Moolenbroek 	i = evbuffer_peek(tmp_buf, -1, NULL, v, 20);
1511e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 0);
1512e985b929SDavid van Moolenbroek 	tt_assert(v[0].iov_base == NULL);
1513e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1514e985b929SDavid van Moolenbroek 	i = evbuffer_peek(tmp_buf, 50, NULL, v, 20);
1515e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 0);
1516e985b929SDavid van Moolenbroek 	tt_assert(v[0].iov_base == NULL);
1517e985b929SDavid van Moolenbroek 
1518e985b929SDavid van Moolenbroek 	/* Okay, now time to have fun with pointers. */
1519e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1520e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET);
1521e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 50, &ptr, v, 20);
1522e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 3);
1523e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], " of chunk [1]\n");
1524e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[1], "Contents of chunk [2]\n");
1525e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/
1526e985b929SDavid van Moolenbroek 
1527e985b929SDavid van Moolenbroek 	/* advance to the start of another chain. */
1528e985b929SDavid van Moolenbroek 	memset(v, 0, sizeof(v));
1529e985b929SDavid van Moolenbroek 	evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD);
1530e985b929SDavid van Moolenbroek 	i = evbuffer_peek(buf, 44, &ptr, v, 20);
1531e985b929SDavid van Moolenbroek 	tt_int_op(i, ==, 2);
1532e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[0], "Contents of chunk [2]\n");
1533e985b929SDavid van Moolenbroek 	tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
1534e985b929SDavid van Moolenbroek 
1535e985b929SDavid van Moolenbroek end:
1536e985b929SDavid van Moolenbroek 	if (buf)
1537e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1538e985b929SDavid van Moolenbroek 	if (tmp_buf)
1539e985b929SDavid van Moolenbroek 		evbuffer_free(tmp_buf);
1540e985b929SDavid van Moolenbroek }
1541e985b929SDavid van Moolenbroek 
1542e985b929SDavid van Moolenbroek /* Check whether evbuffer freezing works right.  This is called twice,
1543e985b929SDavid van Moolenbroek    once with the argument "start" and once with the argument "end".
1544e985b929SDavid van Moolenbroek    When we test "start", we freeze the start of an evbuffer and make sure
1545e985b929SDavid van Moolenbroek    that modifying the start of the buffer doesn't work.  When we test
1546e985b929SDavid van Moolenbroek    "end", we freeze the end of an evbuffer and make sure that modifying
1547e985b929SDavid van Moolenbroek    the end of the buffer doesn't work.
1548e985b929SDavid van Moolenbroek  */
1549e985b929SDavid van Moolenbroek static void
test_evbuffer_freeze(void * ptr)1550e985b929SDavid van Moolenbroek test_evbuffer_freeze(void *ptr)
1551e985b929SDavid van Moolenbroek {
1552e985b929SDavid van Moolenbroek 	struct evbuffer *buf = NULL, *tmp_buf=NULL;
1553e985b929SDavid van Moolenbroek 	const char string[] = /* Year's End, Richard Wilbur */
1554e985b929SDavid van Moolenbroek 	    "I've known the wind by water banks to shake\n"
1555e985b929SDavid van Moolenbroek 	    "The late leaves down, which frozen where they fell\n"
1556e985b929SDavid van Moolenbroek 	    "And held in ice as dancers in a spell\n"
1557e985b929SDavid van Moolenbroek 	    "Fluttered all winter long into a lake...";
1558e985b929SDavid van Moolenbroek 	const int start = !strcmp(ptr, "start");
1559e985b929SDavid van Moolenbroek 	char *cp;
1560e985b929SDavid van Moolenbroek 	char charbuf[128];
1561e985b929SDavid van Moolenbroek 	int r;
1562e985b929SDavid van Moolenbroek 	size_t orig_length;
1563e985b929SDavid van Moolenbroek 	struct evbuffer_iovec v[1];
1564e985b929SDavid van Moolenbroek 
1565e985b929SDavid van Moolenbroek 	if (!start)
1566e985b929SDavid van Moolenbroek 		tt_str_op(ptr, ==, "end");
1567e985b929SDavid van Moolenbroek 
1568e985b929SDavid van Moolenbroek 	buf = evbuffer_new();
1569e985b929SDavid van Moolenbroek 	tmp_buf = evbuffer_new();
1570e985b929SDavid van Moolenbroek 	tt_assert(tmp_buf);
1571e985b929SDavid van Moolenbroek 
1572e985b929SDavid van Moolenbroek 	evbuffer_add(buf, string, strlen(string));
1573e985b929SDavid van Moolenbroek 	evbuffer_freeze(buf, start); /* Freeze the start or the end.*/
1574e985b929SDavid van Moolenbroek 
1575e985b929SDavid van Moolenbroek #define FREEZE_EQ(a, startcase, endcase)		\
1576e985b929SDavid van Moolenbroek 	do {						\
1577e985b929SDavid van Moolenbroek 	    if (start) {				\
1578e985b929SDavid van Moolenbroek 		    tt_int_op((a), ==, (startcase));	\
1579e985b929SDavid van Moolenbroek 	    } else {					\
1580e985b929SDavid van Moolenbroek 		    tt_int_op((a), ==, (endcase));	\
1581e985b929SDavid van Moolenbroek 	    }						\
1582e985b929SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
1583e985b929SDavid van Moolenbroek 
1584e985b929SDavid van Moolenbroek 
1585e985b929SDavid van Moolenbroek 	orig_length = evbuffer_get_length(buf);
1586e985b929SDavid van Moolenbroek 
1587e985b929SDavid van Moolenbroek 	/* These functions all manipulate the end of buf. */
1588e985b929SDavid van Moolenbroek 	r = evbuffer_add(buf, "abc", 0);
1589e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, 0, -1);
1590e985b929SDavid van Moolenbroek 	r = evbuffer_reserve_space(buf, 10, v, 1);
1591e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, 1, -1);
1592e985b929SDavid van Moolenbroek 	if (r == 0) {
1593e985b929SDavid van Moolenbroek 		memset(v[0].iov_base, 'X', 10);
1594e985b929SDavid van Moolenbroek 		v[0].iov_len = 10;
1595e985b929SDavid van Moolenbroek 	}
1596e985b929SDavid van Moolenbroek 	r = evbuffer_commit_space(buf, v, 1);
1597e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, 0, -1);
1598e985b929SDavid van Moolenbroek 	r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
1599e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, 0, -1);
1600e985b929SDavid van Moolenbroek 	r = evbuffer_add_printf(buf, "Hello %s", "world");
1601e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, 11, -1);
1602e985b929SDavid van Moolenbroek 	/* TODO: test add_buffer, add_file, read */
1603e985b929SDavid van Moolenbroek 
1604e985b929SDavid van Moolenbroek 	if (!start)
1605e985b929SDavid van Moolenbroek 		tt_int_op(orig_length, ==, evbuffer_get_length(buf));
1606e985b929SDavid van Moolenbroek 
1607e985b929SDavid van Moolenbroek 	orig_length = evbuffer_get_length(buf);
1608e985b929SDavid van Moolenbroek 
1609e985b929SDavid van Moolenbroek 	/* These functions all manipulate the start of buf. */
1610e985b929SDavid van Moolenbroek 	r = evbuffer_remove(buf, charbuf, 1);
1611e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, -1, 1);
1612e985b929SDavid van Moolenbroek 	r = evbuffer_drain(buf, 3);
1613e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, -1, 0);
1614e985b929SDavid van Moolenbroek 	r = evbuffer_prepend(buf, "dummy", 5);
1615e985b929SDavid van Moolenbroek 	FREEZE_EQ(r, -1, 0);
1616e985b929SDavid van Moolenbroek 	cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF);
1617e985b929SDavid van Moolenbroek 	FREEZE_EQ(cp==NULL, 1, 0);
1618e985b929SDavid van Moolenbroek 	if (cp)
1619e985b929SDavid van Moolenbroek 		free(cp);
1620e985b929SDavid van Moolenbroek 	/* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
1621e985b929SDavid van Moolenbroek 
1622e985b929SDavid van Moolenbroek 	if (start)
1623e985b929SDavid van Moolenbroek 		tt_int_op(orig_length, ==, evbuffer_get_length(buf));
1624e985b929SDavid van Moolenbroek 
1625e985b929SDavid van Moolenbroek end:
1626e985b929SDavid van Moolenbroek 	if (buf)
1627e985b929SDavid van Moolenbroek 		evbuffer_free(buf);
1628e985b929SDavid van Moolenbroek 
1629e985b929SDavid van Moolenbroek 	if (tmp_buf)
1630e985b929SDavid van Moolenbroek 		evbuffer_free(tmp_buf);
1631e985b929SDavid van Moolenbroek }
1632e985b929SDavid van Moolenbroek 
1633e985b929SDavid van Moolenbroek static void *
setup_passthrough(const struct testcase_t * testcase)1634e985b929SDavid van Moolenbroek setup_passthrough(const struct testcase_t *testcase)
1635e985b929SDavid van Moolenbroek {
1636e985b929SDavid van Moolenbroek 	return testcase->setup_data;
1637e985b929SDavid van Moolenbroek }
1638e985b929SDavid van Moolenbroek static int
cleanup_passthrough(const struct testcase_t * testcase,void * ptr)1639e985b929SDavid van Moolenbroek cleanup_passthrough(const struct testcase_t *testcase, void *ptr)
1640e985b929SDavid van Moolenbroek {
1641e985b929SDavid van Moolenbroek 	(void) ptr;
1642e985b929SDavid van Moolenbroek 	return 1;
1643e985b929SDavid van Moolenbroek }
1644e985b929SDavid van Moolenbroek 
1645e985b929SDavid van Moolenbroek static const struct testcase_setup_t nil_setup = {
1646e985b929SDavid van Moolenbroek 	setup_passthrough,
1647e985b929SDavid van Moolenbroek 	cleanup_passthrough
1648e985b929SDavid van Moolenbroek };
1649e985b929SDavid van Moolenbroek 
1650e985b929SDavid van Moolenbroek struct testcase_t evbuffer_testcases[] = {
1651e985b929SDavid van Moolenbroek 	{ "evbuffer", test_evbuffer, 0, NULL, NULL },
1652e985b929SDavid van Moolenbroek 	{ "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
1653e985b929SDavid van Moolenbroek 	{ "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
1654e985b929SDavid van Moolenbroek 	{ "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
1655e985b929SDavid van Moolenbroek 	{ "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, __UNCONST("add") },
1656e985b929SDavid van Moolenbroek 	{ "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, __UNCONST("fill") },
1657e985b929SDavid van Moolenbroek 	{ "expand", test_evbuffer_expand, 0, NULL, NULL },
1658e985b929SDavid van Moolenbroek 	{ "reference", test_evbuffer_reference, 0, NULL, NULL },
1659e985b929SDavid van Moolenbroek 	{ "iterative", test_evbuffer_iterative, 0, NULL, NULL },
1660e985b929SDavid van Moolenbroek 	{ "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
1661e985b929SDavid van Moolenbroek 	{ "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
1662e985b929SDavid van Moolenbroek 	{ "find", test_evbuffer_find, 0, NULL, NULL },
1663e985b929SDavid van Moolenbroek 	{ "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
1664e985b929SDavid van Moolenbroek 	{ "search", test_evbuffer_search, 0, NULL, NULL },
1665e985b929SDavid van Moolenbroek 	{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
1666e985b929SDavid van Moolenbroek 	{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
1667e985b929SDavid van Moolenbroek 	{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
1668e985b929SDavid van Moolenbroek 	{ "peek", test_evbuffer_peek, 0, NULL, NULL },
1669e985b929SDavid van Moolenbroek 	{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, __UNCONST("start") },
1670e985b929SDavid van Moolenbroek 	{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, __UNCONST("end") },
1671e985b929SDavid van Moolenbroek 	/* TODO: need a temp file implementation for Windows */
1672e985b929SDavid van Moolenbroek 	{ "add_file_sendfile", test_evbuffer_add_file, TT_FORK, &nil_setup,
1673e985b929SDavid van Moolenbroek 	  __UNCONST("sendfile") },
1674e985b929SDavid van Moolenbroek 	{ "add_file_mmap", test_evbuffer_add_file, TT_FORK, &nil_setup,
1675e985b929SDavid van Moolenbroek 	  __UNCONST("mmap") },
1676e985b929SDavid van Moolenbroek 	{ "add_file_linear", test_evbuffer_add_file, TT_FORK, &nil_setup,
1677e985b929SDavid van Moolenbroek 	  __UNCONST("linear") },
1678e985b929SDavid van Moolenbroek 
1679e985b929SDavid van Moolenbroek 	END_OF_TESTCASES
1680e985b929SDavid van Moolenbroek };
1681