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