ipc/chromium/src/third_party/libevent/test/regress_buffer.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial