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