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