regress_buffer.c revision 1.3.4.2 1 /* $NetBSD: regress_buffer.c,v 1.3.4.2 2014/05/22 15:48:10 yamt Exp $ */
2 /*
3 * Copyright (c) 2003-2007 Niels Provos <provos (at) 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.3.4.2 2014/05/22 15:48:10 yamt 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
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
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
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
291 no_cleanup(const void *data, size_t datalen, void *extra)
292 {
293 }
294
295 static void
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
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
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
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
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
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
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 *
710 failing_malloc(size_t how_much)
711 {
712 errno = ENOMEM;
713 return NULL;
714 }
715 #endif
716
717 static void
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
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
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 evbuffer_add_printf(buf, "%*.*s", j, j, abc);
996
997 /* Only check for rep violations every so often.
998 Walking over the whole list of chains can get
999 pretty expensive as it gets long.
1000 */
1001 if ((n % 337) == 0)
1002 evbuffer_validate(buf);
1003
1004 sum += j;
1005 n++;
1006 }
1007 }
1008 evbuffer_validate(buf);
1009
1010 tt_uint_op(sum, ==, evbuffer_get_length(buf));
1011
1012 {
1013 size_t a,w,u;
1014 a=w=u=0;
1015 evbuffer_get_waste(buf, &a, &w, &u);
1016 if (0)
1017 printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
1018 (unsigned)a, (unsigned)w, (unsigned)u);
1019 tt_assert( ((double)w)/a < .125);
1020 }
1021 end:
1022 evbuffer_free(buf);
1023
1024 }
1025
1026 static void
1027 test_evbuffer_find(void *ptr)
1028 {
1029 u_char* p;
1030 const char* test1 = "1234567890\r\n";
1031 const char* test2 = "1234567890\r";
1032 #define EVBUFFER_INITIAL_LENGTH 256
1033 char test3[EVBUFFER_INITIAL_LENGTH];
1034 unsigned int i;
1035 struct evbuffer * buf = evbuffer_new();
1036
1037 tt_assert(buf);
1038
1039 /* make sure evbuffer_find doesn't match past the end of the buffer */
1040 evbuffer_add(buf, __UNCONST(test1), strlen(test1));
1041 evbuffer_validate(buf);
1042 evbuffer_drain(buf, strlen(test1));
1043 evbuffer_validate(buf);
1044 evbuffer_add(buf, __UNCONST(test2), strlen(test2));
1045 evbuffer_validate(buf);
1046 p = evbuffer_find(buf, __UNCONST("\r\n"), 2);
1047 tt_want(p == NULL);
1048
1049 /*
1050 * drain the buffer and do another find; in r309 this would
1051 * read past the allocated buffer causing a valgrind error.
1052 */
1053 evbuffer_drain(buf, strlen(test2));
1054 evbuffer_validate(buf);
1055 for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
1056 test3[i] = 'a';
1057 test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
1058 evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
1059 evbuffer_validate(buf);
1060 p = evbuffer_find(buf, __UNCONST("xy"), 2);
1061 tt_want(p == NULL);
1062
1063 /* simple test for match at end of allocated buffer */
1064 p = evbuffer_find(buf, __UNCONST("ax"), 2);
1065 tt_assert(p != NULL);
1066 tt_want(strncmp((char*)p, "ax", 2) == 0);
1067
1068 end:
1069 if (buf)
1070 evbuffer_free(buf);
1071 }
1072
1073 static void
1074 test_evbuffer_ptr_set(void *ptr)
1075 {
1076 struct evbuffer *buf = evbuffer_new();
1077 struct evbuffer_ptr pos;
1078 struct evbuffer_iovec v[1];
1079
1080 tt_assert(buf);
1081
1082 /* create some chains */
1083 evbuffer_reserve_space(buf, 5000, v, 1);
1084 v[0].iov_len = 5000;
1085 memset(v[0].iov_base, 1, v[0].iov_len);
1086 evbuffer_commit_space(buf, v, 1);
1087 evbuffer_validate(buf);
1088
1089 evbuffer_reserve_space(buf, 4000, v, 1);
1090 v[0].iov_len = 4000;
1091 memset(v[0].iov_base, 2, v[0].iov_len);
1092 evbuffer_commit_space(buf, v, 1);
1093
1094 evbuffer_reserve_space(buf, 3000, v, 1);
1095 v[0].iov_len = 3000;
1096 memset(v[0].iov_base, 3, v[0].iov_len);
1097 evbuffer_commit_space(buf, v, 1);
1098 evbuffer_validate(buf);
1099
1100 tt_int_op(evbuffer_get_length(buf), ==, 12000);
1101
1102 tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1);
1103 tt_assert(pos.pos == -1);
1104 tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
1105 tt_assert(pos.pos == 0);
1106 tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1);
1107
1108 tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
1109 tt_assert(pos.pos == 0);
1110 tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0);
1111 tt_assert(pos.pos == 10000);
1112 tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
1113 tt_assert(pos.pos == 11000);
1114 tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
1115 tt_assert(pos.pos == -1);
1116
1117 end:
1118 if (buf)
1119 evbuffer_free(buf);
1120 }
1121
1122 static void
1123 test_evbuffer_search(void *ptr)
1124 {
1125 struct evbuffer *buf = evbuffer_new();
1126 struct evbuffer *tmp = evbuffer_new();
1127 struct evbuffer_ptr pos, end;
1128
1129 tt_assert(buf);
1130 tt_assert(tmp);
1131
1132 /* set up our chains */
1133 evbuffer_add_printf(tmp, "hello"); /* 5 chars */
1134 evbuffer_add_buffer(buf, tmp);
1135 evbuffer_add_printf(tmp, "foo"); /* 3 chars */
1136 evbuffer_add_buffer(buf, tmp);
1137 evbuffer_add_printf(tmp, "cat"); /* 3 chars */
1138 evbuffer_add_buffer(buf, tmp);
1139 evbuffer_add_printf(tmp, "attack");
1140 evbuffer_add_buffer(buf, tmp);
1141
1142 pos = evbuffer_search(buf, "attack", 6, NULL);
1143 tt_int_op(pos.pos, ==, 11);
1144 pos = evbuffer_search(buf, "attacker", 8, NULL);
1145 tt_int_op(pos.pos, ==, -1);
1146
1147 /* test continuing search */
1148 pos = evbuffer_search(buf, "oc", 2, NULL);
1149 tt_int_op(pos.pos, ==, 7);
1150 pos = evbuffer_search(buf, "cat", 3, &pos);
1151 tt_int_op(pos.pos, ==, 8);
1152 pos = evbuffer_search(buf, "tacking", 7, &pos);
1153 tt_int_op(pos.pos, ==, -1);
1154
1155 evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET);
1156 pos = evbuffer_search(buf, "foo", 3, &pos);
1157 tt_int_op(pos.pos, ==, 5);
1158
1159 evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD);
1160 pos = evbuffer_search(buf, "tat", 3, &pos);
1161 tt_int_op(pos.pos, ==, 10);
1162
1163 /* test bounded search. */
1164 /* Set "end" to the first t in "attack". */
1165 evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
1166 pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
1167 tt_int_op(pos.pos, ==, 5);
1168 pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
1169 tt_int_op(pos.pos, ==, 5);
1170 pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
1171 tt_int_op(pos.pos, ==, -1);
1172 pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
1173 tt_int_op(pos.pos, ==, -1);
1174
1175
1176 end:
1177 if (buf)
1178 evbuffer_free(buf);
1179 if (tmp)
1180 evbuffer_free(tmp);
1181 }
1182
1183 static void
1184 log_change_callback(struct evbuffer *buffer,
1185 const struct evbuffer_cb_info *cbinfo,
1186 void *arg)
1187 {
1188
1189 size_t old_len = cbinfo->orig_size;
1190 size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted;
1191 struct evbuffer *out = arg;
1192 evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len,
1193 (unsigned long)new_len);
1194 }
1195 static void
1196 self_draining_callback(struct evbuffer *evbuffer, size_t old_len,
1197 size_t new_len, void *arg)
1198 {
1199 if (new_len > old_len)
1200 evbuffer_drain(evbuffer, new_len);
1201 }
1202
1203 static void
1204 test_evbuffer_callbacks(void *ptr)
1205 {
1206 struct evbuffer *buf = evbuffer_new();
1207 struct evbuffer *buf_out1 = evbuffer_new();
1208 struct evbuffer *buf_out2 = evbuffer_new();
1209 struct evbuffer_cb_entry *cb1, *cb2;
1210
1211 tt_assert(buf);
1212 tt_assert(buf_out1);
1213 tt_assert(buf_out2);
1214
1215 cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1216 cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1217
1218 /* Let's run through adding and deleting some stuff from the buffer
1219 * and turning the callbacks on and off and removing them. The callback
1220 * adds a summary of length changes to buf_out1/buf_out2 when called. */
1221 /* size: 0-> 36. */
1222 evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
1223 evbuffer_validate(buf);
1224 evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
1225 evbuffer_drain(buf, 10); /*36->26*/
1226 evbuffer_validate(buf);
1227 evbuffer_prepend(buf, "Hello", 5);/*26->31*/
1228 evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
1229 evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
1230 evbuffer_remove_cb_entry(buf, cb1);
1231 evbuffer_validate(buf);
1232 evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
1233 tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
1234 evbuffer_add(buf, "X", 1); /* 0->1 */
1235 tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
1236 evbuffer_validate(buf);
1237
1238 tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
1239 "0->36; 36->26; 26->31; 31->38; ");
1240 tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
1241 "0->36; 31->38; 38->0; 0->1; ");
1242 evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
1243 evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
1244 /* Let's test the obsolete buffer_setcb function too. */
1245 cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1246 tt_assert(cb1 != NULL);
1247 cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1248 tt_assert(cb2 != NULL);
1249 evbuffer_setcb(buf, self_draining_callback, NULL);
1250 evbuffer_add_printf(buf, "This should get drained right away.");
1251 tt_uint_op(evbuffer_get_length(buf), ==, 0);
1252 tt_uint_op(evbuffer_get_length(buf_out1), ==, 0);
1253 tt_uint_op(evbuffer_get_length(buf_out2), ==, 0);
1254 evbuffer_setcb(buf, NULL, NULL);
1255 evbuffer_add_printf(buf, "This will not.");
1256 tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
1257 evbuffer_validate(buf);
1258 evbuffer_drain(buf, evbuffer_get_length(buf));
1259 evbuffer_validate(buf);
1260 #if 0
1261 /* Now let's try a suspended callback. */
1262 cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
1263 cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
1264 evbuffer_cb_suspend(buf,cb2);
1265 evbuffer_prepend(buf,"Hello world",11); /*0->11*/
1266 evbuffer_validate(buf);
1267 evbuffer_cb_suspend(buf,cb1);
1268 evbuffer_add(buf,"more",4); /* 11->15 */
1269 evbuffer_cb_unsuspend(buf,cb2);
1270 evbuffer_drain(buf, 4); /* 15->11 */
1271 evbuffer_cb_unsuspend(buf,cb1);
1272 evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */
1273
1274 tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
1275 "0->11; 11->11; 11->0; ");
1276 tt_str_op(evbuffer_pullup(buf_out2, -1), ==,
1277 "0->15; 15->11; 11->0; ");
1278 #endif
1279
1280 end:
1281 if (buf)
1282 evbuffer_free(buf);
1283 if (buf_out1)
1284 evbuffer_free(buf_out1);
1285 if (buf_out2)
1286 evbuffer_free(buf_out2);
1287 }
1288
1289 static int ref_done_cb_called_count = 0;
1290 static void *ref_done_cb_called_with = NULL;
1291 static const void *ref_done_cb_called_with_data = NULL;
1292 static size_t ref_done_cb_called_with_len = 0;
1293 static void ref_done_cb(const void *data, size_t len, void *info)
1294 {
1295 ++ref_done_cb_called_count;
1296 ref_done_cb_called_with = info;
1297 ref_done_cb_called_with_data = data;
1298 ref_done_cb_called_with_len = len;
1299 }
1300
1301 static void
1302 test_evbuffer_add_reference(void *ptr)
1303 {
1304 const char chunk1[] = "If you have found the answer to such a problem";
1305 const char chunk2[] = "you ought to write it up for publication";
1306 /* -- Knuth's "Notes on the Exercises" from TAOCP */
1307 char tmp[16];
1308 size_t len1 = strlen(chunk1), len2=strlen(chunk2);
1309
1310 struct evbuffer *buf1 = NULL, *buf2 = NULL;
1311
1312 buf1 = evbuffer_new();
1313 tt_assert(buf1);
1314
1315 evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111);
1316 evbuffer_add(buf1, ", ", 2);
1317 evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222);
1318 tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2);
1319
1320 /* Make sure we can drain a little from a reference. */
1321 tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6);
1322 tt_int_op(memcmp(tmp, "If you", 6), ==, 0);
1323 tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5);
1324 tt_int_op(memcmp(tmp, " have", 5), ==, 0);
1325
1326 /* Make sure that prepending does not meddle with immutable data */
1327 tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0);
1328 tt_int_op(memcmp(chunk1, "If you", 6), ==, 0);
1329 evbuffer_validate(buf1);
1330
1331 /* Make sure that when the chunk is over, the callback is invoked. */
1332 evbuffer_drain(buf1, 7); /* Remove prepended stuff. */
1333 evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */
1334 tt_int_op(ref_done_cb_called_count, ==, 0);
1335 evbuffer_remove(buf1, tmp, 1);
1336 tt_int_op(tmp[0], ==, 'm');
1337 tt_assert(ref_done_cb_called_with == (void*)111);
1338 tt_assert(ref_done_cb_called_with_data == chunk1);
1339 tt_assert(ref_done_cb_called_with_len == len1);
1340 tt_int_op(ref_done_cb_called_count, ==, 1);
1341 evbuffer_validate(buf1);
1342
1343 /* Drain some of the remaining chunk, then add it to another buffer */
1344 evbuffer_drain(buf1, 6); /* Remove the ", you ". */
1345 buf2 = evbuffer_new();
1346 tt_assert(buf2);
1347 tt_int_op(ref_done_cb_called_count, ==, 1);
1348 evbuffer_add(buf2, "I ", 2);
1349
1350 evbuffer_add_buffer(buf2, buf1);
1351 tt_int_op(ref_done_cb_called_count, ==, 1);
1352 evbuffer_remove(buf2, tmp, 16);
1353 tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0);
1354 evbuffer_drain(buf2, evbuffer_get_length(buf2));
1355 tt_int_op(ref_done_cb_called_count, ==, 2);
1356 tt_assert(ref_done_cb_called_with == (void*)222);
1357 evbuffer_validate(buf2);
1358
1359 /* Now add more stuff to buf1 and make sure that it gets removed on
1360 * free. */
1361 evbuffer_add(buf1, "You shake and shake the ", 24);
1362 evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb,
1363 (void*)3333);
1364 evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 42);
1365 evbuffer_free(buf1);
1366 buf1 = NULL;
1367 tt_int_op(ref_done_cb_called_count, ==, 3);
1368 tt_assert(ref_done_cb_called_with == (void*)3333);
1369
1370 end:
1371 if (buf1)
1372 evbuffer_free(buf1);
1373 if (buf2)
1374 evbuffer_free(buf2);
1375 }
1376
1377 /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
1378 static void
1379 test_evbuffer_prepend(void *ptr)
1380 {
1381 struct evbuffer *buf1 = NULL, *buf2 = NULL;
1382 char tmp[128];
1383 int n;
1384
1385 buf1 = evbuffer_new();
1386 tt_assert(buf1);
1387
1388 /* Case 0: The evbuffer is entirely empty. */
1389 evbuffer_prepend(buf1, "This string has 29 characters", 29);
1390 evbuffer_validate(buf1);
1391
1392 /* Case 1: Prepend goes entirely in new chunk. */
1393 evbuffer_prepend(buf1, "Short.", 6);
1394 evbuffer_validate(buf1);
1395
1396 /* Case 2: prepend goes entirely in first chunk. */
1397 evbuffer_drain(buf1, 6+11);
1398 evbuffer_prepend(buf1, "it", 2);
1399 evbuffer_validate(buf1);
1400 tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign,
1401 "it has", 6));
1402
1403 /* Case 3: prepend is split over multiple chunks. */
1404 evbuffer_prepend(buf1, "It is no longer true to say ", 28);
1405 evbuffer_validate(buf1);
1406 n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1);
1407 tmp[n]='\0';
1408 tt_str_op(tmp,==,"It is no longer true to say it has 29 characters");
1409
1410 buf2 = evbuffer_new();
1411 tt_assert(buf2);
1412
1413 /* Case 4: prepend a buffer to an empty buffer. */
1414 n = 999;
1415 evbuffer_add_printf(buf1, "Here is string %d. ", n++);
1416 evbuffer_prepend_buffer(buf2, buf1);
1417 evbuffer_validate(buf2);
1418
1419 /* Case 5: prepend a buffer to a nonempty buffer. */
1420 evbuffer_add_printf(buf1, "Here is string %d. ", n++);
1421 evbuffer_prepend_buffer(buf2, buf1);
1422 evbuffer_validate(buf2);
1423 evbuffer_validate(buf1);
1424 n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
1425 tmp[n]='\0';
1426 tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
1427
1428 end:
1429 if (buf1)
1430 evbuffer_free(buf1);
1431 if (buf2)
1432 evbuffer_free(buf2);
1433
1434 }
1435
1436 static void
1437 test_evbuffer_peek(void *info)
1438 {
1439 struct evbuffer *buf = NULL, *tmp_buf = NULL;
1440 int i;
1441 struct evbuffer_iovec v[20];
1442 struct evbuffer_ptr ptr;
1443
1444 #define tt_iov_eq(v, s) \
1445 tt_int_op((v)->iov_len, ==, strlen(s)); \
1446 tt_assert(!memcmp((v)->iov_base, (s), strlen(s)))
1447
1448 /* Let's make a very fragmented buffer. */
1449 buf = evbuffer_new();
1450 tmp_buf = evbuffer_new();
1451 for (i = 0; i < 16; ++i) {
1452 evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i);
1453 evbuffer_add_buffer(buf, tmp_buf);
1454 }
1455
1456 /* How many chunks do we need for everything? */
1457 i = evbuffer_peek(buf, -1, NULL, NULL, 0);
1458 tt_int_op(i, ==, 16);
1459
1460 /* Simple peek: get everything. */
1461 i = evbuffer_peek(buf, -1, NULL, v, 20);
1462 tt_int_op(i, ==, 16); /* we used only 16 chunks. */
1463 tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1464 tt_iov_eq(&v[3], "Contents of chunk [3]\n");
1465 tt_iov_eq(&v[12], "Contents of chunk [12]\n");
1466 tt_iov_eq(&v[15], "Contents of chunk [15]\n");
1467
1468 /* Just get one chunk worth. */
1469 memset(v, 0, sizeof(v));
1470 i = evbuffer_peek(buf, -1, NULL, v, 1);
1471 tt_int_op(i, ==, 1);
1472 tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1473 tt_assert(v[1].iov_base == NULL);
1474
1475 /* Suppose we want at least the first 40 bytes. */
1476 memset(v, 0, sizeof(v));
1477 i = evbuffer_peek(buf, 40, NULL, v, 16);
1478 tt_int_op(i, ==, 2);
1479 tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1480 tt_iov_eq(&v[1], "Contents of chunk [1]\n");
1481 tt_assert(v[2].iov_base == NULL);
1482
1483 /* How many chunks do we need for 100 bytes? */
1484 memset(v, 0, sizeof(v));
1485 i = evbuffer_peek(buf, 100, NULL, NULL, 0);
1486 tt_int_op(i, ==, 5);
1487 tt_assert(v[0].iov_base == NULL);
1488
1489 /* Now we ask for more bytes than we provide chunks for */
1490 memset(v, 0, sizeof(v));
1491 i = evbuffer_peek(buf, 60, NULL, v, 1);
1492 tt_int_op(i, ==, 3);
1493 tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1494 tt_assert(v[1].iov_base == NULL);
1495
1496 /* Now we ask for more bytes than the buffer has. */
1497 memset(v, 0, sizeof(v));
1498 i = evbuffer_peek(buf, 65536, NULL, v, 20);
1499 tt_int_op(i, ==, 16); /* we used only 16 chunks. */
1500 tt_iov_eq(&v[0], "Contents of chunk [0]\n");
1501 tt_iov_eq(&v[3], "Contents of chunk [3]\n");
1502 tt_iov_eq(&v[12], "Contents of chunk [12]\n");
1503 tt_iov_eq(&v[15], "Contents of chunk [15]\n");
1504 tt_assert(v[16].iov_base == NULL);
1505
1506 /* What happens if we try an empty buffer? */
1507 memset(v, 0, sizeof(v));
1508 i = evbuffer_peek(tmp_buf, -1, NULL, v, 20);
1509 tt_int_op(i, ==, 0);
1510 tt_assert(v[0].iov_base == NULL);
1511 memset(v, 0, sizeof(v));
1512 i = evbuffer_peek(tmp_buf, 50, NULL, v, 20);
1513 tt_int_op(i, ==, 0);
1514 tt_assert(v[0].iov_base == NULL);
1515
1516 /* Okay, now time to have fun with pointers. */
1517 memset(v, 0, sizeof(v));
1518 evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET);
1519 i = evbuffer_peek(buf, 50, &ptr, v, 20);
1520 tt_int_op(i, ==, 3);
1521 tt_iov_eq(&v[0], " of chunk [1]\n");
1522 tt_iov_eq(&v[1], "Contents of chunk [2]\n");
1523 tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/
1524
1525 /* advance to the start of another chain. */
1526 memset(v, 0, sizeof(v));
1527 evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD);
1528 i = evbuffer_peek(buf, 44, &ptr, v, 20);
1529 tt_int_op(i, ==, 2);
1530 tt_iov_eq(&v[0], "Contents of chunk [2]\n");
1531 tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
1532
1533 end:
1534 if (buf)
1535 evbuffer_free(buf);
1536 if (tmp_buf)
1537 evbuffer_free(tmp_buf);
1538 }
1539
1540 /* Check whether evbuffer freezing works right. This is called twice,
1541 once with the argument "start" and once with the argument "end".
1542 When we test "start", we freeze the start of an evbuffer and make sure
1543 that modifying the start of the buffer doesn't work. When we test
1544 "end", we freeze the end of an evbuffer and make sure that modifying
1545 the end of the buffer doesn't work.
1546 */
1547 static void
1548 test_evbuffer_freeze(void *ptr)
1549 {
1550 struct evbuffer *buf = NULL, *tmp_buf=NULL;
1551 const char string[] = /* Year's End, Richard Wilbur */
1552 "I've known the wind by water banks to shake\n"
1553 "The late leaves down, which frozen where they fell\n"
1554 "And held in ice as dancers in a spell\n"
1555 "Fluttered all winter long into a lake...";
1556 const int start = !strcmp(ptr, "start");
1557 char *cp;
1558 char charbuf[128];
1559 int r;
1560 size_t orig_length;
1561 struct evbuffer_iovec v[1];
1562
1563 if (!start)
1564 tt_str_op(ptr, ==, "end");
1565
1566 buf = evbuffer_new();
1567 tmp_buf = evbuffer_new();
1568 tt_assert(tmp_buf);
1569
1570 evbuffer_add(buf, string, strlen(string));
1571 evbuffer_freeze(buf, start); /* Freeze the start or the end.*/
1572
1573 #define FREEZE_EQ(a, startcase, endcase) \
1574 do { \
1575 if (start) { \
1576 tt_int_op((a), ==, (startcase)); \
1577 } else { \
1578 tt_int_op((a), ==, (endcase)); \
1579 } \
1580 } while (/*CONSTCOND*/0)
1581
1582
1583 orig_length = evbuffer_get_length(buf);
1584
1585 /* These functions all manipulate the end of buf. */
1586 r = evbuffer_add(buf, "abc", 0);
1587 FREEZE_EQ(r, 0, -1);
1588 r = evbuffer_reserve_space(buf, 10, v, 1);
1589 FREEZE_EQ(r, 1, -1);
1590 if (r == 0) {
1591 memset(v[0].iov_base, 'X', 10);
1592 v[0].iov_len = 10;
1593 }
1594 r = evbuffer_commit_space(buf, v, 1);
1595 FREEZE_EQ(r, 0, -1);
1596 r = evbuffer_add_reference(buf, string, 5, NULL, NULL);
1597 FREEZE_EQ(r, 0, -1);
1598 r = evbuffer_add_printf(buf, "Hello %s", "world");
1599 FREEZE_EQ(r, 11, -1);
1600 /* TODO: test add_buffer, add_file, read */
1601
1602 if (!start)
1603 tt_int_op(orig_length, ==, evbuffer_get_length(buf));
1604
1605 orig_length = evbuffer_get_length(buf);
1606
1607 /* These functions all manipulate the start of buf. */
1608 r = evbuffer_remove(buf, charbuf, 1);
1609 FREEZE_EQ(r, -1, 1);
1610 r = evbuffer_drain(buf, 3);
1611 FREEZE_EQ(r, -1, 0);
1612 r = evbuffer_prepend(buf, "dummy", 5);
1613 FREEZE_EQ(r, -1, 0);
1614 cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF);
1615 FREEZE_EQ(cp==NULL, 1, 0);
1616 if (cp)
1617 free(cp);
1618 /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
1619
1620 if (start)
1621 tt_int_op(orig_length, ==, evbuffer_get_length(buf));
1622
1623 end:
1624 if (buf)
1625 evbuffer_free(buf);
1626
1627 if (tmp_buf)
1628 evbuffer_free(tmp_buf);
1629 }
1630
1631 static void *
1632 setup_passthrough(const struct testcase_t *testcase)
1633 {
1634 return testcase->setup_data;
1635 }
1636 static int
1637 cleanup_passthrough(const struct testcase_t *testcase, void *ptr)
1638 {
1639 (void) ptr;
1640 return 1;
1641 }
1642
1643 static const struct testcase_setup_t nil_setup = {
1644 setup_passthrough,
1645 cleanup_passthrough
1646 };
1647
1648 struct testcase_t evbuffer_testcases[] = {
1649 { "evbuffer", test_evbuffer, 0, NULL, NULL },
1650 { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
1651 { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },
1652 { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL },
1653 { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, __UNCONST("add") },
1654 { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, __UNCONST("fill") },
1655 { "expand", test_evbuffer_expand, 0, NULL, NULL },
1656 { "reference", test_evbuffer_reference, 0, NULL, NULL },
1657 { "iterative", test_evbuffer_iterative, 0, NULL, NULL },
1658 { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL },
1659 { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL },
1660 { "find", test_evbuffer_find, 0, NULL, NULL },
1661 { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL },
1662 { "search", test_evbuffer_search, 0, NULL, NULL },
1663 { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
1664 { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
1665 { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
1666 { "peek", test_evbuffer_peek, 0, NULL, NULL },
1667 { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, __UNCONST("start") },
1668 { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, __UNCONST("end") },
1669 /* TODO: need a temp file implementation for Windows */
1670 { "add_file_sendfile", test_evbuffer_add_file, TT_FORK, &nil_setup,
1671 __UNCONST("sendfile") },
1672 { "add_file_mmap", test_evbuffer_add_file, TT_FORK, &nil_setup,
1673 __UNCONST("mmap") },
1674 { "add_file_linear", test_evbuffer_add_file, TT_FORK, &nil_setup,
1675 __UNCONST("linear") },
1676
1677 END_OF_TESTCASES
1678 };
1679