1 /* $NetBSD: regress_buffer.c,v 1.5 2015/08/28 13:04:48 joerg Exp $ */
3 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
4 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
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 $");
38 #include <sys/types.h>
40 #ifdef _EVENT_HAVE_SYS_TIME_H
43 #include <sys/queue.h>
45 #include <sys/socket.h>
57 #include "event2/event.h"
58 #include "event2/buffer.h"
59 #include "event2/buffer_compat.h"
60 #include "event2/util.h"
62 #include "evbuffer-internal.h"
63 #include "log-internal.h"
67 /* Validates that an evbuffer is good. Returns false if it isn't, true if it
70 _evbuffer_validate(struct evbuffer
*buf
)
72 struct evbuffer_chain
*chain
;
74 int found_last_with_datap
= 0;
76 if (buf
->first
== NULL
) {
77 tt_assert(buf
->last
== NULL
);
78 tt_assert(buf
->total_len
== 0);
83 tt_assert(buf
->last_with_datap
);
84 if (buf
->last_with_datap
== &buf
->first
)
85 found_last_with_datap
= 1;
87 while (chain
!= NULL
) {
88 if (&chain
->next
== buf
->last_with_datap
)
89 found_last_with_datap
= 1;
91 if (chain
->next
== NULL
) {
92 tt_assert(buf
->last
== chain
);
94 tt_assert(chain
->buffer_len
>= chain
->misalign
+ chain
->off
);
99 tt_assert(*buf
->last_with_datap
);
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);
109 while (chain
!= NULL
) {
110 tt_assert(chain
->off
== 0);
114 tt_assert(buf
->last_with_datap
== &buf
->first
);
116 tt_assert(found_last_with_datap
);
118 tt_assert(sum
== buf
->total_len
);
125 evbuffer_get_waste(struct evbuffer
*buf
, size_t *allocatedp
, size_t *wastedp
, size_t *usedp
)
127 struct evbuffer_chain
*chain
;
133 /* skip empty at start */
134 while (chain
&& chain
->off
==0) {
136 a
+= chain
->buffer_len
;
139 /* first nonempty chain: stuff at the end only is wasted. */
142 a
+= chain
->buffer_len
;
144 if (chain
->next
&& chain
->next
->off
)
145 w
+= (size_t)(chain
->buffer_len
- (chain
->misalign
+ chain
->off
));
148 /* subsequent nonempty chains */
149 while (chain
&& chain
->off
) {
151 a
+= chain
->buffer_len
;
152 w
+= (size_t)chain
->misalign
;
154 if (chain
->next
&& chain
->next
->off
)
155 w
+= (size_t) (chain
->buffer_len
- (chain
->misalign
+ chain
->off
));
158 /* subsequent empty chains */
161 a
+= chain
->buffer_len
;
168 #define evbuffer_validate(buf) \
169 TT_STMT_BEGIN if (!_evbuffer_validate(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
172 test_evbuffer(void *ptr
)
174 static char buffer
[512], *tmp
;
175 struct evbuffer
*evb
= evbuffer_new();
176 struct evbuffer
*evb_two
= evbuffer_new();
180 evbuffer_validate(evb
);
181 evbuffer_add_printf(evb
, "%s/%d", "hello", 1);
182 evbuffer_validate(evb
);
184 tt_assert(evbuffer_get_length(evb
) == 7);
185 tt_assert(!memcmp((char*)EVBUFFER_DATA(evb
), "hello/1", 1));
187 evbuffer_add_buffer(evb
, evb_two
);
188 evbuffer_validate(evb
);
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));
195 evbuffer_add_printf(evb_two
, "%s", "/hello");
196 evbuffer_validate(evb
);
197 evbuffer_add_buffer(evb
, evb_two
);
198 evbuffer_validate(evb
);
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);
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);
209 tmp
= (char *)evbuffer_pullup(evb
, 7 + 512);
211 tt_assert(!strncmp(tmp
, "1/hello", 7));
212 tt_assert(!memcmp(tmp
+ 7, buffer
, sizeof(buffer
)));
213 evbuffer_validate(evb
);
215 evbuffer_prepend(evb
, "something", 9);
216 evbuffer_validate(evb
);
217 evbuffer_prepend(evb
, "else", 4);
218 evbuffer_validate(evb
);
220 tmp
= (char *)evbuffer_pullup(evb
, 4 + 9 + 7);
221 tt_assert(!strncmp(tmp
, "elsesomething1/hello", 4 + 9 + 7));
222 evbuffer_validate(evb
);
224 evbuffer_drain(evb
, -1);
225 evbuffer_validate(evb
);
226 evbuffer_drain(evb_two
, -1);
227 evbuffer_validate(evb
);
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
);
237 tt_assert(evbuffer_get_length(evb_two
) == 0);
238 tt_assert(evbuffer_get_length(evb
) == i
* sizeof(buffer
));
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
);
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");
253 evbuffer_validate(evb
);
256 /* testing one-vector reserve and commit */
258 struct evbuffer_iovec v
[1];
262 for (ii
= 0; ii
< 3; ++ii
) {
263 r
= evbuffer_reserve_space(evb
, 10000, v
, 1);
265 tt_assert(v
[0].iov_len
>= 10000);
266 tt_assert(v
[0].iov_base
!= NULL
);
268 evbuffer_validate(evb
);
270 for (j
= 0; j
< 10000; ++j
) {
273 evbuffer_validate(evb
);
275 tt_int_op(evbuffer_commit_space(evb
, v
, 1), ==, 0);
276 evbuffer_validate(evb
);
278 tt_assert(evbuffer_get_length(evb
) >= 10000);
280 evbuffer_drain(evb
, j
* 5000);
281 evbuffer_validate(evb
);
287 evbuffer_free(evb_two
);
291 no_cleanup(const void *data
, size_t datalen
, void *extra
)
296 test_evbuffer_remove_buffer_with_empty(void *ptr
)
298 struct evbuffer
*src
= evbuffer_new();
299 struct evbuffer
*dst
= evbuffer_new();
302 evbuffer_validate(src
);
303 evbuffer_validate(dst
);
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
);
313 evbuffer_validate(src
);
314 evbuffer_validate(dst
);
316 /* move three bytes over */
317 evbuffer_remove_buffer(src
, dst
, 3);
319 evbuffer_validate(src
);
320 evbuffer_validate(dst
);
328 test_evbuffer_reserve2(void *ptr
)
330 /* Test the two-vector cases of reserve/commit. */
331 struct evbuffer
*buf
= evbuffer_new();
333 struct evbuffer_iovec v
[2];
337 /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/
338 n
= evbuffer_reserve_space(buf
, 1024, v
, 2);
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);
345 remaining
= 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
);
352 /* Ask for another same-chunk request, in an existing chunk. Use 8
354 n
= evbuffer_reserve_space(buf
, 32, v
, 2);
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);
360 tt_int_op(0, ==, evbuffer_commit_space(buf
, v
, 1));
361 tt_int_op(evbuffer_get_length(buf
), ==, 520);
363 evbuffer_validate(buf
);
365 /* Now ask for a request that will be split. Use only one byte of it,
367 n
= evbuffer_reserve_space(buf
, remaining
+64, v
, 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);
374 memset(v
[0].iov_base
, 'Z', 1);
376 tt_int_op(0, ==, evbuffer_commit_space(buf
, v
, 1));
377 tt_int_op(evbuffer_get_length(buf
), ==, 521);
379 evbuffer_validate(buf
);
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
);
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);
392 memset(v
[1].iov_base
, 'x', 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
);
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);
402 tt_int_op(v
[0].iov_len
, ==, 921);
403 tt_int_op(v
[1].iov_len
, ==, 60);
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');
417 tt_int_op(cp
[i
], ==, 'x');
424 test_evbuffer_reserve_many(void *ptr
)
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];
432 int add_data
= ptr
&& !strcmp(ptr
, "add");
433 int fill_first
= ptr
&& !strcmp(ptr
, "fill");
436 /* When reserving the the first chunk, we just allocate it */
437 n
= evbuffer_reserve_space(buf
, 128, v
, 2);
438 evbuffer_validate(buf
);
440 tt_assert(v
[0].iov_len
>= 128);
444 *(char*)v
[0].iov_base
= 'X';
446 n
= evbuffer_commit_space(buf
, v
, 1);
448 } else if (fill_first
) {
449 memset(v
[0].iov_base
, 'X', v
[0].iov_len
);
450 n
= evbuffer_commit_space(buf
, v
, 1);
452 n
= evbuffer_reserve_space(buf
, 128, v
, 2);
455 tt_assert(v
[0].iov_base
!= cp1
);
459 /* Make another chunk get added. */
460 n
= evbuffer_reserve_space(buf
, sz
+128, v
, 2);
461 evbuffer_validate(buf
);
463 sz
= v
[0].iov_len
+ v
[1].iov_len
;
464 tt_int_op(sz
, >=, v
[0].iov_len
+128);
466 tt_assert(v
[0].iov_base
== cp1
+ 1);
468 tt_assert(v
[0].iov_base
== cp1
);
473 /* And a third chunk. */
474 n
= evbuffer_reserve_space(buf
, sz
+128, v
, 3);
475 evbuffer_validate(buf
);
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
;
481 /* Now force a reallocation by asking for more space in only 2
483 n
= evbuffer_reserve_space(buf
, sz
+128, v
, 2);
484 evbuffer_validate(buf
);
487 tt_assert(cp1
== v
[0].iov_base
);
497 test_evbuffer_expand(void *ptr
)
500 struct evbuffer
*buf
;
504 memset(data
, 'X', sizeof(data
));
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
);
511 evbuffer_get_waste(buf
, &a
,&w
,&u
);
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);
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
);
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);
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
);
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
);
553 /* add, expand, pull-up: This used to crash libevent. */
554 buf
= evbuffer_new();
556 evbuffer_add(buf
, data
, sizeof(data
));
557 evbuffer_add(buf
, data
, sizeof(data
));
558 evbuffer_add(buf
, data
, sizeof(data
));
560 evbuffer_validate(buf
);
561 evbuffer_expand(buf
, 1024);
562 evbuffer_validate(buf
);
563 evbuffer_pullup(buf
, -1);
564 evbuffer_validate(buf
);
571 static int reference_cb_called
;
573 reference_cb(const void *data
, size_t len
, void *extra
)
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
;
584 test_evbuffer_reference(void *ptr
)
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;
592 tt_assert(evbuffer_add_reference(src
, data
, strlen(data
),
593 reference_cb
, (void *)0xdeadaffe) != -1);
595 evbuffer_reserve_space(dst
, strlen(data
), v
, 1);
596 tt_assert(evbuffer_remove(src
, v
[0].iov_base
, 10) != -1);
598 evbuffer_validate(src
);
599 evbuffer_validate(dst
);
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);
606 tt_assert(evbuffer_remove(src
, ((char*)(v
[0].iov_base
)) + 10,
607 strlen(data
) - 10) != -1);
609 v
[0].iov_len
= strlen(data
);
611 evbuffer_commit_space(dst
, v
, 1);
612 evbuffer_validate(src
);
613 evbuffer_validate(dst
);
615 tt_int_op(reference_cb_called
, ==, 1);
617 tt_assert(!memcmp(evbuffer_pullup(dst
, strlen(data
)),
618 data
, strlen(data
)));
619 evbuffer_validate(dst
);
626 int _evbuffer_testing_use_sendfile(void);
627 int _evbuffer_testing_use_mmap(void);
628 int _evbuffer_testing_use_linear_file_access(void);
631 test_evbuffer_add_file(void *ptr
)
633 const char *impl
= ptr
;
634 struct evbuffer
*src
= evbuffer_new();
635 const char *data
= "this is what we add as file system data.";
639 evutil_socket_t xpair
[2] = {-1, -1};
640 int r
=0, n_written
=0;
642 /* Add a test for a big file. XXXX */
645 if (!strcmp(impl
, "sendfile")) {
646 if (!_evbuffer_testing_use_sendfile())
648 TT_BLATHER(("Using sendfile-based implementaion"));
649 } else if (!strcmp(impl
, "mmap")) {
650 if (!_evbuffer_testing_use_mmap())
652 TT_BLATHER(("Using mmap-based implementaion"));
653 } else if (!strcmp(impl
, "linear")) {
654 if (!_evbuffer_testing_use_linear_file_access())
656 TT_BLATHER(("Using read-based implementaion"));
658 TT_DIE(("Didn't recognize the implementation"));
661 /* Say that it drains to a fd so that we can use sendfile. */
662 evbuffer_set_flags(src
, EVBUFFER_FLAG_DRAINS_TO_FD
);
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");
670 if (evutil_socketpair(AF_UNIX
, SOCK_STREAM
, 0, xpair
) == -1)
671 tt_abort_msg("socketpair failed");
674 datalen
= strlen(data
);
675 fd
= regress_make_tmpfile(data
, datalen
);
679 tt_assert(evbuffer_add_file(src
, fd
, 0, datalen
) != -1);
681 evbuffer_validate(src
);
683 while (evbuffer_get_length(src
) &&
684 (r
= evbuffer_write(src
, xpair
[0])) > 0) {
685 evbuffer_validate(src
);
688 tt_int_op(r
, !=, -1);
689 tt_int_op(n_written
, ==, datalen
);
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.");
699 evbuffer_validate(src
);
702 evutil_closesocket(xpair
[0]);
704 evutil_closesocket(xpair
[1]);
708 #ifndef _EVENT_DISABLE_MM_REPLACEMENT
710 failing_malloc(size_t how_much
)
718 test_evbuffer_readln(void *ptr
)
720 struct evbuffer
*evb
= evbuffer_new();
721 struct evbuffer
*evb_tmp
= evbuffer_new();
726 #define tt_line_eq(content) \
728 if (!cp || sz != strlen(content) || strcmp(cp, content)) { \
729 TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \
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");
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
);
747 evbuffer_add(evb
, s
, strlen(s
));
749 evbuffer_validate(evb
);
750 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_ANY
);
753 evbuffer_validate(evb
);
754 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_ANY
);
756 evbuffer_validate(evb
);
757 evbuffer_drain(evb
, evbuffer_get_length(evb
));
758 tt_assert(evbuffer_get_length(evb
) == 0);
759 evbuffer_validate(evb
);
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");
768 evbuffer_validate(evb
);
770 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF
);
771 tt_line_eq("Line with good crlf");
773 evbuffer_validate(evb
);
775 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF
);
778 evbuffer_validate(evb
);
780 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF
);
783 evbuffer_validate(evb
);
784 evbuffer_add(evb
, s
, 1);
785 evbuffer_validate(evb
);
787 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF
);
789 evbuffer_validate(evb
);
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");
798 evbuffer_validate(evb
);
800 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
803 evbuffer_validate(evb
);
805 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
807 evbuffer_validate(evb
);
808 evbuffer_add(evb
, "\n", 1);
809 evbuffer_validate(evb
);
811 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
814 tt_assert(evbuffer_get_length(evb
) == 0);
815 evbuffer_validate(evb
);
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");
822 evbuffer_validate(evb
);
824 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
826 evbuffer_validate(evb
);
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");
833 tt_assert(evbuffer_get_length(evb
) == 0);
834 evbuffer_validate(evb
);
837 s
= "An\rand a nl\n\nText";
838 evbuffer_add(evb
, s
, strlen(s
));
839 evbuffer_validate(evb
);
841 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
842 tt_line_eq("An\rand a nl");
844 evbuffer_validate(evb
);
846 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
849 evbuffer_validate(evb
);
851 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
854 evbuffer_add(evb
, "\n", 1);
855 evbuffer_validate(evb
);
856 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
859 evbuffer_validate(evb
);
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
);
868 evbuffer_add(evb_tmp
, s
, strlen(s
));
869 evbuffer_validate(evb
);
870 evbuffer_add_buffer(evb
, evb_tmp
);
871 evbuffer_validate(evb
);
873 evbuffer_add(evb_tmp
, s
, strlen(s
));
874 evbuffer_validate(evb
);
875 evbuffer_add_buffer(evb
, evb_tmp
);
876 evbuffer_validate(evb
);
878 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
879 tt_line_eq(" and a bad crlf\nand a good one");
881 evbuffer_validate(evb
);
883 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
886 evbuffer_validate(evb
);
888 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
891 evbuffer_validate(evb
);
892 evbuffer_add(evb
, "\n", 1);
893 evbuffer_validate(evb
);
894 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_CRLF_STRICT
);
897 evbuffer_validate(evb
);
898 tt_assert(evbuffer_get_length(evb
) == 0);
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
);
907 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
908 tt_line_eq("one line");
910 evbuffer_validate(evb
);
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
);
919 /* now we should get the next line back */
920 event_set_mem_functions(malloc
, realloc
, free
);
922 cp
= evbuffer_readln(evb
, &sz
, EVBUFFER_EOL_LF
);
923 tt_line_eq("two line");
925 evbuffer_validate(evb
);
929 evbuffer_free(evb_tmp
);
934 test_evbuffer_search_eol(void *ptr
)
936 struct evbuffer
*buf
= evbuffer_new();
937 struct evbuffer_ptr ptr1
, ptr2
;
941 s
= "string! \r\n\r\nx\n";
942 evbuffer_add(buf
, s
, strlen(s
));
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);
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);
953 evbuffer_ptr_set(buf
, &ptr1
, 1, EVBUFFER_PTR_ADD
);
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);
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);
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);
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);
974 evbuffer_ptr_set(buf
, &ptr1
, 1, EVBUFFER_PTR_ADD
);
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);
985 test_evbuffer_iterative(void *ptr
)
987 struct evbuffer
*buf
= evbuffer_new();
988 const char *abc
= "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz";
989 unsigned i
, j
, sum
, n
;
993 for (i
= 0; i
< 1000; ++i
) {
994 for (j
= 1; j
< strlen(abc
); ++j
) {
996 evutil_snprintf(format
, sizeof(format
), "%%%u.%us", j
, j
);
997 evbuffer_add_printf(buf
, fmtcheck(format
, "%s"), abc
);
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.
1004 evbuffer_validate(buf
);
1010 evbuffer_validate(buf
);
1012 tt_uint_op(sum
, ==, evbuffer_get_length(buf
));
1017 evbuffer_get_waste(buf
, &a
, &w
, &u
);
1019 printf("Allocated: %u.\nWasted: %u.\nUsed: %u.",
1020 (unsigned)a
, (unsigned)w
, (unsigned)u
);
1021 tt_assert( ((double)w
)/a
< .125);
1029 test_evbuffer_find(void *ptr
)
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
];
1037 struct evbuffer
* buf
= evbuffer_new();
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);
1052 * drain the buffer and do another find; in r309 this would
1053 * read past the allocated buffer causing a valgrind error.
1055 evbuffer_drain(buf
, strlen(test2
));
1056 evbuffer_validate(buf
);
1057 for (i
= 0; i
< EVBUFFER_INITIAL_LENGTH
; ++i
)
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);
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);
1076 test_evbuffer_ptr_set(void *ptr
)
1078 struct evbuffer
*buf
= evbuffer_new();
1079 struct evbuffer_ptr pos
;
1080 struct evbuffer_iovec v
[1];
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
);
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);
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
);
1102 tt_int_op(evbuffer_get_length(buf
), ==, 12000);
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);
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);
1125 test_evbuffer_search(void *ptr
)
1127 struct evbuffer
*buf
= evbuffer_new();
1128 struct evbuffer
*tmp
= evbuffer_new();
1129 struct evbuffer_ptr pos
, end
;
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
);
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);
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);
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);
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);
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);
1186 log_change_callback(struct evbuffer
*buffer
,
1187 const struct evbuffer_cb_info
*cbinfo
,
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
);
1198 self_draining_callback(struct evbuffer
*evbuffer
, size_t old_len
,
1199 size_t new_len
, void *arg
)
1201 if (new_len
> old_len
)
1202 evbuffer_drain(evbuffer
, new_len
);
1206 test_evbuffer_callbacks(void *ptr
)
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
;
1214 tt_assert(buf_out1
);
1215 tt_assert(buf_out2
);
1217 cb1
= evbuffer_add_cb(buf
, log_change_callback
, buf_out1
);
1218 cb2
= evbuffer_add_cb(buf
, log_change_callback
, buf_out2
);
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. */
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
);
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
);
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 */
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; ");
1286 evbuffer_free(buf_out1
);
1288 evbuffer_free(buf_out2
);
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;
1295 static void ref_done_cb(const void *data
, size_t len
, void *info
)
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
;
1304 test_evbuffer_add_reference(void *ptr
)
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 */
1310 size_t len1
= strlen(chunk1
), len2
=strlen(chunk2
);
1312 struct evbuffer
*buf1
= NULL
, *buf2
= NULL
;
1314 buf1
= evbuffer_new();
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);
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);
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
);
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
);
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();
1349 tt_int_op(ref_done_cb_called_count
, ==, 1);
1350 evbuffer_add(buf2
, "I ", 2);
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
);
1361 /* Now add more stuff to buf1 and make sure that it gets removed on
1363 evbuffer_add(buf1
, "You shake and shake the ", 24);
1364 evbuffer_add_reference(buf1
, "ketchup bottle", 14, ref_done_cb
,
1366 evbuffer_add(buf1
, ". Nothing comes and then a lot'll.", 42);
1367 evbuffer_free(buf1
);
1369 tt_int_op(ref_done_cb_called_count
, ==, 3);
1370 tt_assert(ref_done_cb_called_with
== (void*)3333);
1374 evbuffer_free(buf1
);
1376 evbuffer_free(buf2
);
1379 /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */
1381 test_evbuffer_prepend(void *ptr
)
1383 struct evbuffer
*buf1
= NULL
, *buf2
= NULL
;
1387 buf1
= evbuffer_new();
1390 /* Case 0: The evbuffer is entirely empty. */
1391 evbuffer_prepend(buf1
, "This string has 29 characters", 29);
1392 evbuffer_validate(buf1
);
1394 /* Case 1: Prepend goes entirely in new chunk. */
1395 evbuffer_prepend(buf1
, "Short.", 6);
1396 evbuffer_validate(buf1
);
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
,
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);
1410 tt_str_op(tmp
,==,"It is no longer true to say it has 29 characters");
1412 buf2
= evbuffer_new();
1415 /* Case 4: prepend a buffer to an empty buffer. */
1417 evbuffer_add_printf(buf1
, "Here is string %d. ", n
++);
1418 evbuffer_prepend_buffer(buf2
, buf1
);
1419 evbuffer_validate(buf2
);
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);
1428 tt_str_op(tmp
,==,"Here is string 1000. Here is string 999. ");
1432 evbuffer_free(buf1
);
1434 evbuffer_free(buf2
);
1439 test_evbuffer_peek(void *info
)
1441 struct evbuffer
*buf
= NULL
, *tmp_buf
= NULL
;
1443 struct evbuffer_iovec v
[20];
1444 struct evbuffer_ptr ptr
;
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)))
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
);
1458 /* How many chunks do we need for everything? */
1459 i
= evbuffer_peek(buf
, -1, NULL
, NULL
, 0);
1460 tt_int_op(i
, ==, 16);
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");
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
);
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
);
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
);
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
);
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
);
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
);
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*/
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*/
1539 evbuffer_free(tmp_buf
);
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.
1550 test_evbuffer_freeze(void *ptr
)
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");
1563 struct evbuffer_iovec v
[1];
1566 tt_str_op(ptr
, ==, "end");
1568 buf
= evbuffer_new();
1569 tmp_buf
= evbuffer_new();
1572 evbuffer_add(buf
, string
, strlen(string
));
1573 evbuffer_freeze(buf
, start
); /* Freeze the start or the end.*/
1575 #define FREEZE_EQ(a, startcase, endcase) \
1578 tt_int_op((a), ==, (startcase)); \
1580 tt_int_op((a), ==, (endcase)); \
1582 } while (/*CONSTCOND*/0)
1585 orig_length
= evbuffer_get_length(buf
);
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);
1593 memset(v
[0].iov_base
, 'X', 10);
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 */
1605 tt_int_op(orig_length
, ==, evbuffer_get_length(buf
));
1607 orig_length
= evbuffer_get_length(buf
);
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);
1620 /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */
1623 tt_int_op(orig_length
, ==, evbuffer_get_length(buf
));
1630 evbuffer_free(tmp_buf
);
1634 setup_passthrough(const struct testcase_t
*testcase
)
1636 return testcase
->setup_data
;
1639 cleanup_passthrough(const struct testcase_t
*testcase
, void *ptr
)
1645 static const struct testcase_setup_t nil_setup
= {
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") },