1 1.6 christos /* $NetBSD: regress_buffer.c,v 1.7 2024/08/18 20:47:23 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 2003-2007 Niels Provos <provos (at) citi.umich.edu> 5 1.1 christos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 6 1.1 christos * 7 1.1 christos * Redistribution and use in source and binary forms, with or without 8 1.1 christos * modification, are permitted provided that the following conditions 9 1.1 christos * are met: 10 1.1 christos * 1. Redistributions of source code must retain the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer. 12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 christos * notice, this list of conditions and the following disclaimer in the 14 1.1 christos * documentation and/or other materials provided with the distribution. 15 1.1 christos * 3. The name of the author may not be used to endorse or promote products 16 1.1 christos * derived from this software without specific prior written permission. 17 1.1 christos * 18 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 christos */ 29 1.1 christos #include "util-internal.h" 30 1.1 christos 31 1.1 christos #ifdef _WIN32 32 1.1 christos #include <winsock2.h> 33 1.1 christos #include <windows.h> 34 1.1 christos #endif 35 1.1 christos 36 1.1 christos #include "event2/event-config.h" 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 "defer-internal.h" 63 1.1 christos #include "evbuffer-internal.h" 64 1.1 christos #include "log-internal.h" 65 1.1 christos 66 1.1 christos #include "regress.h" 67 1.1 christos 68 1.7 christos #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 69 1.7 christos 70 1.1 christos /* Validates that an evbuffer is good. Returns false if it isn't, true if it 71 1.1 christos * is*/ 72 1.1 christos static int 73 1.1 christos evbuffer_validate_(struct evbuffer *buf) 74 1.1 christos { 75 1.1 christos struct evbuffer_chain *chain; 76 1.1 christos size_t sum = 0; 77 1.1 christos int found_last_with_datap = 0; 78 1.1 christos 79 1.1 christos if (buf->first == NULL) { 80 1.1 christos tt_assert(buf->last == NULL); 81 1.1 christos tt_assert(buf->total_len == 0); 82 1.1 christos } 83 1.1 christos 84 1.1 christos chain = buf->first; 85 1.1 christos 86 1.1 christos tt_assert(buf->last_with_datap); 87 1.1 christos if (buf->last_with_datap == &buf->first) 88 1.1 christos found_last_with_datap = 1; 89 1.1 christos 90 1.1 christos while (chain != NULL) { 91 1.1 christos if (&chain->next == buf->last_with_datap) 92 1.1 christos found_last_with_datap = 1; 93 1.1 christos sum += chain->off; 94 1.1 christos if (chain->next == NULL) { 95 1.1 christos tt_assert(buf->last == chain); 96 1.1 christos } 97 1.1 christos tt_assert(chain->buffer_len >= chain->misalign + chain->off); 98 1.1 christos chain = chain->next; 99 1.1 christos } 100 1.1 christos 101 1.1 christos if (buf->first) 102 1.1 christos tt_assert(*buf->last_with_datap); 103 1.1 christos 104 1.1 christos if (*buf->last_with_datap) { 105 1.1 christos chain = *buf->last_with_datap; 106 1.1 christos if (chain->off == 0 || buf->total_len == 0) { 107 1.1 christos tt_assert(chain->off == 0) 108 1.1 christos tt_assert(chain == buf->first); 109 1.1 christos tt_assert(buf->total_len == 0); 110 1.1 christos } 111 1.1 christos chain = chain->next; 112 1.1 christos while (chain != NULL) { 113 1.1 christos tt_assert(chain->off == 0); 114 1.1 christos chain = chain->next; 115 1.1 christos } 116 1.1 christos } else { 117 1.1 christos tt_assert(buf->last_with_datap == &buf->first); 118 1.1 christos } 119 1.1 christos tt_assert(found_last_with_datap); 120 1.1 christos 121 1.1 christos tt_assert(sum == buf->total_len); 122 1.1 christos return 1; 123 1.1 christos end: 124 1.1 christos return 0; 125 1.1 christos } 126 1.1 christos 127 1.1 christos static void 128 1.1 christos evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp) 129 1.1 christos { 130 1.1 christos struct evbuffer_chain *chain; 131 1.1 christos size_t a, w, u; 132 1.1 christos int n = 0; 133 1.1 christos u = a = w = 0; 134 1.1 christos 135 1.1 christos chain = buf->first; 136 1.1 christos /* skip empty at start */ 137 1.1 christos while (chain && chain->off==0) { 138 1.1 christos ++n; 139 1.1 christos a += chain->buffer_len; 140 1.1 christos chain = chain->next; 141 1.1 christos } 142 1.1 christos /* first nonempty chain: stuff at the end only is wasted. */ 143 1.1 christos if (chain) { 144 1.1 christos ++n; 145 1.1 christos a += chain->buffer_len; 146 1.1 christos u += chain->off; 147 1.1 christos if (chain->next && chain->next->off) 148 1.1 christos w += (size_t)(chain->buffer_len - (chain->misalign + chain->off)); 149 1.1 christos chain = chain->next; 150 1.1 christos } 151 1.1 christos /* subsequent nonempty chains */ 152 1.1 christos while (chain && chain->off) { 153 1.1 christos ++n; 154 1.1 christos a += chain->buffer_len; 155 1.1 christos w += (size_t)chain->misalign; 156 1.1 christos u += chain->off; 157 1.1 christos if (chain->next && chain->next->off) 158 1.1 christos w += (size_t) (chain->buffer_len - (chain->misalign + chain->off)); 159 1.1 christos chain = chain->next; 160 1.1 christos } 161 1.1 christos /* subsequent empty chains */ 162 1.1 christos while (chain) { 163 1.1 christos ++n; 164 1.1 christos a += chain->buffer_len; 165 1.1 christos } 166 1.1 christos *allocatedp = a; 167 1.1 christos *wastedp = w; 168 1.1 christos *usedp = u; 169 1.1 christos } 170 1.1 christos 171 1.1 christos #define evbuffer_validate(buf) \ 172 1.1 christos TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END 173 1.1 christos 174 1.1 christos static void 175 1.1 christos test_evbuffer(void *ptr) 176 1.1 christos { 177 1.1 christos static char buffer[512], *tmp; 178 1.1 christos struct evbuffer *evb = evbuffer_new(); 179 1.1 christos struct evbuffer *evb_two = evbuffer_new(); 180 1.1 christos size_t sz_tmp; 181 1.1 christos int i; 182 1.1 christos 183 1.1 christos evbuffer_validate(evb); 184 1.1 christos evbuffer_add_printf(evb, "%s/%d", "hello", 1); 185 1.1 christos evbuffer_validate(evb); 186 1.1 christos 187 1.1 christos tt_assert(evbuffer_get_length(evb) == 7); 188 1.1 christos tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1)); 189 1.1 christos 190 1.1 christos evbuffer_add_buffer(evb, evb_two); 191 1.1 christos evbuffer_validate(evb); 192 1.1 christos 193 1.1 christos evbuffer_drain(evb, strlen("hello/")); 194 1.1 christos evbuffer_validate(evb); 195 1.1 christos tt_assert(evbuffer_get_length(evb) == 1); 196 1.1 christos tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1)); 197 1.1 christos 198 1.1 christos evbuffer_add_printf(evb_two, "%s", "/hello"); 199 1.1 christos evbuffer_validate(evb); 200 1.1 christos evbuffer_add_buffer(evb, evb_two); 201 1.1 christos evbuffer_validate(evb); 202 1.1 christos 203 1.1 christos tt_assert(evbuffer_get_length(evb_two) == 0); 204 1.1 christos tt_assert(evbuffer_get_length(evb) == 7); 205 1.7 christos tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7)); 206 1.1 christos 207 1.1 christos memset(buffer, 0, sizeof(buffer)); 208 1.1 christos evbuffer_add(evb, buffer, sizeof(buffer)); 209 1.1 christos evbuffer_validate(evb); 210 1.1 christos tt_assert(evbuffer_get_length(evb) == 7 + 512); 211 1.1 christos 212 1.1 christos tmp = (char *)evbuffer_pullup(evb, 7 + 512); 213 1.1 christos tt_assert(tmp); 214 1.1 christos tt_assert(!strncmp(tmp, "1/hello", 7)); 215 1.1 christos tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer))); 216 1.1 christos evbuffer_validate(evb); 217 1.1 christos 218 1.1 christos evbuffer_prepend(evb, "something", 9); 219 1.1 christos evbuffer_validate(evb); 220 1.1 christos evbuffer_prepend(evb, "else", 4); 221 1.1 christos evbuffer_validate(evb); 222 1.1 christos 223 1.1 christos tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7); 224 1.1 christos tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7)); 225 1.1 christos evbuffer_validate(evb); 226 1.1 christos 227 1.1 christos evbuffer_drain(evb, -1); 228 1.1 christos evbuffer_validate(evb); 229 1.1 christos evbuffer_drain(evb_two, -1); 230 1.1 christos evbuffer_validate(evb); 231 1.1 christos 232 1.1 christos for (i = 0; i < 3; ++i) { 233 1.1 christos evbuffer_add(evb_two, buffer, sizeof(buffer)); 234 1.1 christos evbuffer_validate(evb_two); 235 1.1 christos evbuffer_add_buffer(evb, evb_two); 236 1.1 christos evbuffer_validate(evb); 237 1.1 christos evbuffer_validate(evb_two); 238 1.1 christos } 239 1.1 christos 240 1.1 christos tt_assert(evbuffer_get_length(evb_two) == 0); 241 1.1 christos tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer)); 242 1.1 christos 243 1.1 christos /* test remove buffer */ 244 1.1 christos sz_tmp = (size_t)(sizeof(buffer)*2.5); 245 1.1 christos evbuffer_remove_buffer(evb, evb_two, sz_tmp); 246 1.1 christos tt_assert(evbuffer_get_length(evb_two) == sz_tmp); 247 1.1 christos tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2); 248 1.1 christos evbuffer_validate(evb); 249 1.1 christos 250 1.1 christos if (memcmp(evbuffer_pullup( 251 1.1 christos evb, -1), buffer, sizeof(buffer) / 2) != 0 || 252 1.1 christos memcmp(evbuffer_pullup( 253 1.3 christos evb_two, -1), buffer, sizeof(buffer)) != 0) 254 1.1 christos tt_abort_msg("Pullup did not preserve content"); 255 1.1 christos 256 1.1 christos evbuffer_validate(evb); 257 1.1 christos 258 1.1 christos 259 1.1 christos /* testing one-vector reserve and commit */ 260 1.1 christos { 261 1.1 christos struct evbuffer_iovec v[1]; 262 1.1 christos char *buf; 263 1.1 christos int i, j, r; 264 1.1 christos 265 1.1 christos for (i = 0; i < 3; ++i) { 266 1.1 christos r = evbuffer_reserve_space(evb, 10000, v, 1); 267 1.1 christos tt_int_op(r, ==, 1); 268 1.1 christos tt_assert(v[0].iov_len >= 10000); 269 1.1 christos tt_assert(v[0].iov_base != NULL); 270 1.1 christos 271 1.1 christos evbuffer_validate(evb); 272 1.1 christos buf = v[0].iov_base; 273 1.1 christos for (j = 0; j < 10000; ++j) { 274 1.1 christos buf[j] = j; 275 1.1 christos } 276 1.1 christos evbuffer_validate(evb); 277 1.1 christos 278 1.1 christos tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0); 279 1.1 christos evbuffer_validate(evb); 280 1.1 christos 281 1.1 christos tt_assert(evbuffer_get_length(evb) >= 10000); 282 1.1 christos 283 1.1 christos evbuffer_drain(evb, j * 5000); 284 1.1 christos evbuffer_validate(evb); 285 1.1 christos } 286 1.1 christos } 287 1.1 christos 288 1.1 christos end: 289 1.1 christos evbuffer_free(evb); 290 1.1 christos evbuffer_free(evb_two); 291 1.1 christos } 292 1.1 christos 293 1.1 christos static void 294 1.1 christos no_cleanup(const void *data, size_t datalen, void *extra) 295 1.1 christos { 296 1.1 christos } 297 1.1 christos 298 1.1 christos static void 299 1.1 christos test_evbuffer_remove_buffer_with_empty(void *ptr) 300 1.1 christos { 301 1.7 christos struct evbuffer *src = evbuffer_new(); 302 1.7 christos struct evbuffer *dst = evbuffer_new(); 303 1.7 christos char buf[2] = { 'A', 'A' }; 304 1.7 christos 305 1.7 christos evbuffer_validate(src); 306 1.7 christos evbuffer_validate(dst); 307 1.7 christos 308 1.7 christos /* setup the buffers */ 309 1.7 christos /* we need more data in src than we will move later */ 310 1.7 christos evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); 311 1.7 christos evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); 312 1.7 christos /* we need one buffer in dst and one empty buffer at the end */ 313 1.7 christos evbuffer_add(dst, buf, sizeof(buf)); 314 1.7 christos evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL); 315 1.7 christos 316 1.7 christos evbuffer_validate(src); 317 1.7 christos evbuffer_validate(dst); 318 1.7 christos 319 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "AAAA", 4); 320 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "AA", 2); 321 1.7 christos 322 1.7 christos /* move three bytes over */ 323 1.7 christos evbuffer_remove_buffer(src, dst, 3); 324 1.7 christos 325 1.7 christos evbuffer_validate(src); 326 1.7 christos evbuffer_validate(dst); 327 1.7 christos 328 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "A", 1); 329 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "AAAAA", 5); 330 1.7 christos 331 1.7 christos end: 332 1.7 christos evbuffer_free(src); 333 1.7 christos evbuffer_free(dst); 334 1.7 christos } 335 1.7 christos 336 1.7 christos static void 337 1.7 christos test_evbuffer_remove_buffer_with_empty2(void *ptr) 338 1.7 christos { 339 1.7 christos struct evbuffer *src = evbuffer_new(); 340 1.7 christos struct evbuffer *dst = evbuffer_new(); 341 1.7 christos struct evbuffer *buf = evbuffer_new(); 342 1.7 christos 343 1.7 christos evbuffer_add(buf, "foo", 3); 344 1.7 christos evbuffer_add_reference(buf, "foo", 3, NULL, NULL); 345 1.7 christos 346 1.7 christos evbuffer_add_reference(src, "foo", 3, NULL, NULL); 347 1.7 christos evbuffer_add_reference(src, NULL, 0, NULL, NULL); 348 1.7 christos evbuffer_add_buffer(src, buf); 349 1.7 christos 350 1.7 christos evbuffer_add(buf, "foo", 3); 351 1.7 christos evbuffer_add_reference(buf, "foo", 3, NULL, NULL); 352 1.7 christos 353 1.7 christos evbuffer_add_reference(dst, "foo", 3, NULL, NULL); 354 1.7 christos evbuffer_add_reference(dst, NULL, 0, NULL, NULL); 355 1.7 christos evbuffer_add_buffer(dst, buf); 356 1.7 christos 357 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 9); 358 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 9); 359 1.7 christos 360 1.7 christos evbuffer_validate(src); 361 1.7 christos evbuffer_validate(dst); 362 1.7 christos 363 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoofoo", 9); 364 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoo", 9); 365 1.7 christos 366 1.7 christos evbuffer_remove_buffer(src, dst, 8); 367 1.7 christos 368 1.7 christos evbuffer_validate(src); 369 1.7 christos evbuffer_validate(dst); 370 1.7 christos 371 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 1); 372 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 17); 373 1.7 christos 374 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); 375 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofoofoofo", 17); 376 1.7 christos 377 1.7 christos end: 378 1.7 christos evbuffer_free(src); 379 1.7 christos evbuffer_free(dst); 380 1.7 christos evbuffer_free(buf); 381 1.7 christos } 382 1.7 christos 383 1.7 christos static void 384 1.7 christos test_evbuffer_remove_buffer_with_empty3(void *ptr) 385 1.7 christos { 386 1.7 christos struct evbuffer *src = evbuffer_new(); 387 1.7 christos struct evbuffer *dst = evbuffer_new(); 388 1.7 christos struct evbuffer *buf = evbuffer_new(); 389 1.7 christos 390 1.7 christos evbuffer_add(buf, "foo", 3); 391 1.7 christos evbuffer_add_reference(buf, NULL, 0, NULL, NULL); 392 1.7 christos 393 1.7 christos evbuffer_add_reference(src, "foo", 3, NULL, NULL); 394 1.7 christos evbuffer_add_reference(src, NULL, 0, NULL, NULL); 395 1.7 christos evbuffer_prepend_buffer(src, buf); 396 1.7 christos 397 1.7 christos evbuffer_add(buf, "foo", 3); 398 1.7 christos evbuffer_add_reference(buf, NULL, 0, NULL, NULL); 399 1.7 christos 400 1.7 christos evbuffer_add_reference(dst, "foo", 3, NULL, NULL); 401 1.7 christos evbuffer_add_reference(dst, NULL, 0, NULL, NULL); 402 1.7 christos evbuffer_prepend_buffer(dst, buf); 403 1.7 christos 404 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 6); 405 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 6); 406 1.7 christos 407 1.7 christos evbuffer_validate(src); 408 1.7 christos evbuffer_validate(dst); 409 1.7 christos 410 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoo", 6); 411 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoo", 6); 412 1.7 christos 413 1.7 christos evbuffer_remove_buffer(src, dst, 5); 414 1.7 christos 415 1.7 christos evbuffer_validate(src); 416 1.7 christos evbuffer_validate(dst); 417 1.7 christos 418 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 1); 419 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 11); 420 1.7 christos 421 1.7 christos tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); 422 1.7 christos tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofo", 11); 423 1.7 christos 424 1.7 christos end: 425 1.7 christos evbuffer_free(src); 426 1.7 christos evbuffer_free(dst); 427 1.7 christos evbuffer_free(buf); 428 1.7 christos } 429 1.7 christos 430 1.7 christos static void 431 1.7 christos test_evbuffer_pullup_with_empty(void *ptr) 432 1.7 christos { 433 1.7 christos struct evbuffer *buf = NULL; 434 1.7 christos 435 1.7 christos buf = evbuffer_new(); 436 1.7 christos evbuffer_add(buf, "foo", 3); 437 1.7 christos evbuffer_add_reference(buf, NULL, 0, NULL, NULL); 438 1.7 christos evbuffer_validate(buf); 439 1.7 christos tt_int_op(evbuffer_get_length(buf), ==, 3); 440 1.7 christos tt_mem_op(evbuffer_pullup(buf, -1), ==, "foo", 3); 441 1.7 christos 442 1.7 christos evbuffer_free(buf); 443 1.7 christos buf = evbuffer_new(); 444 1.7 christos evbuffer_validate(buf); 445 1.7 christos tt_int_op(evbuffer_get_length(buf), ==, 0); 446 1.7 christos tt_int_op(evbuffer_pullup(buf, -1), ==, NULL); 447 1.7 christos 448 1.7 christos evbuffer_free(buf); 449 1.7 christos buf = evbuffer_new(); 450 1.7 christos evbuffer_add(buf, "foo", 3); 451 1.7 christos evbuffer_add_reference(buf, NULL, 0, NULL, NULL); 452 1.7 christos evbuffer_validate(buf); 453 1.7 christos tt_mem_op(evbuffer_pullup(buf, 3), ==, "foo", 3); 454 1.7 christos 455 1.7 christos end: 456 1.7 christos if (buf) 457 1.7 christos evbuffer_free(buf); 458 1.7 christos } 459 1.7 christos 460 1.7 christos static void 461 1.7 christos test_evbuffer_remove_buffer_with_empty_front(void *ptr) 462 1.7 christos { 463 1.7 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 464 1.7 christos 465 1.7 christos buf1 = evbuffer_new(); 466 1.7 christos tt_assert(buf1); 467 1.7 christos 468 1.7 christos buf2 = evbuffer_new(); 469 1.7 christos tt_assert(buf2); 470 1.7 christos 471 1.7 christos tt_int_op(evbuffer_add_reference(buf1, "foo", 3, NULL, NULL), ==, 0); 472 1.7 christos tt_int_op(evbuffer_prepend(buf1, "", 0), ==, 0); 473 1.7 christos tt_int_op(evbuffer_remove_buffer(buf1, buf2, 1), ==, 1); 474 1.7 christos tt_int_op(evbuffer_add(buf1, "bar", 3), ==, 0); 475 1.7 christos tt_mem_op(evbuffer_pullup(buf1, -1), ==, "oobar", 5); 476 1.7 christos 477 1.7 christos evbuffer_validate(buf1); 478 1.7 christos evbuffer_validate(buf2); 479 1.7 christos 480 1.7 christos end: 481 1.7 christos if (buf1) 482 1.7 christos evbuffer_free(buf1); 483 1.7 christos if (buf2) 484 1.7 christos evbuffer_free(buf2); 485 1.7 christos } 486 1.7 christos 487 1.7 christos static void 488 1.7 christos test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty(void *ptr) 489 1.7 christos { 490 1.7 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 491 1.1 christos 492 1.7 christos buf1 = evbuffer_new(); 493 1.7 christos tt_assert(buf1); 494 1.7 christos 495 1.7 christos buf2 = evbuffer_new(); 496 1.7 christos tt_assert(buf2); 497 1.1 christos 498 1.7 christos tt_int_op(evbuffer_add(buf1, "aaaaaa", 6), ==, 0); 499 1.1 christos 500 1.7 christos // buf1: aaaaaab 501 1.7 christos // buf2: 502 1.7 christos { 503 1.7 christos struct evbuffer_iovec iovecs[2]; 504 1.7 christos /** we want two chains, to leave one chain empty */ 505 1.7 christos tt_int_op(evbuffer_reserve_space(buf1, 971, iovecs, 2), ==, 2); 506 1.7 christos tt_int_op(iovecs[0].iov_len, >=, 1); 507 1.7 christos tt_int_op(iovecs[1].iov_len, >=, 1); 508 1.7 christos tt_assert(*(char *)(iovecs[0].iov_base) = 'b'); 509 1.7 christos tt_assert(iovecs[0].iov_len = 1); 510 1.7 christos tt_int_op(evbuffer_commit_space(buf1, iovecs, 1), ==, 0); 511 1.7 christos } 512 1.7 christos 513 1.7 christos // buf1: aaaaaab 514 1.7 christos // buf2: dddcc 515 1.7 christos tt_int_op(evbuffer_add(buf2, "cc", 2), ==, 0); 516 1.7 christos tt_int_op(evbuffer_prepend(buf2, "ddd", 3), ==, 0); 517 1.7 christos 518 1.7 christos // buf1: 519 1.7 christos // buf2: aaaaaabdddcc 520 1.7 christos tt_int_op(evbuffer_prepend_buffer(buf2, buf1), ==, 0); 521 1.7 christos 522 1.7 christos // buf1: aaaaaabdddcc 523 1.7 christos // buf2: 524 1.7 christos tt_int_op(evbuffer_add_buffer(buf1, buf2), ==, 0); 525 1.7 christos 526 1.7 christos // buf1: c 527 1.7 christos // buf2: aaaaaabdddc 528 1.7 christos tt_int_op(evbuffer_remove_buffer(buf1, buf2, 11), ==, 11); 529 1.1 christos 530 1.7 christos // This fails today, we observe "aaaaaabcddd" instead! 531 1.7 christos tt_mem_op(evbuffer_pullup(buf2, -1), ==, "aaaaaabdddc", 11); 532 1.1 christos 533 1.7 christos evbuffer_validate(buf1); 534 1.7 christos evbuffer_validate(buf2); 535 1.1 christos 536 1.7 christos end: 537 1.7 christos if (buf1) 538 1.7 christos evbuffer_free(buf1); 539 1.7 christos if (buf2) 540 1.7 christos evbuffer_free(buf2); 541 1.7 christos } 542 1.7 christos 543 1.7 christos static void 544 1.7 christos test_evbuffer_add_buffer_with_empty(void *ptr) 545 1.7 christos { 546 1.7 christos struct evbuffer *src = evbuffer_new(); 547 1.7 christos struct evbuffer *dst = evbuffer_new(); 548 1.7 christos struct evbuffer *buf = evbuffer_new(); 549 1.7 christos 550 1.7 christos evbuffer_add(buf, "foo", 3); 551 1.7 christos 552 1.7 christos evbuffer_add_reference(src, "foo", 3, NULL, NULL); 553 1.7 christos evbuffer_add_reference(src, NULL, 0, NULL, NULL); 554 1.7 christos evbuffer_add_buffer(src, buf); 555 1.7 christos 556 1.7 christos evbuffer_add(buf, "foo", 3); 557 1.7 christos 558 1.7 christos evbuffer_add_reference(dst, "foo", 3, NULL, NULL); 559 1.7 christos evbuffer_add_reference(dst, NULL, 0, NULL, NULL); 560 1.7 christos evbuffer_add_buffer(dst, buf); 561 1.7 christos 562 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 6); 563 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 6); 564 1.7 christos 565 1.7 christos evbuffer_validate(src); 566 1.7 christos evbuffer_validate(dst); 567 1.7 christos 568 1.7 christos end: 569 1.7 christos evbuffer_free(src); 570 1.7 christos evbuffer_free(dst); 571 1.7 christos evbuffer_free(buf); 572 1.7 christos } 573 1.7 christos 574 1.7 christos static void 575 1.7 christos test_evbuffer_add_buffer_with_empty2(void *ptr) 576 1.7 christos { 577 1.7 christos struct evbuffer *src = evbuffer_new(); 578 1.7 christos struct evbuffer *dst = evbuffer_new(); 579 1.7 christos struct evbuffer *buf = evbuffer_new(); 580 1.7 christos 581 1.7 christos evbuffer_add(buf, "foo", 3); 582 1.7 christos 583 1.7 christos evbuffer_add_reference(src, NULL, 0, NULL, NULL); 584 1.7 christos evbuffer_add_buffer(src, buf); 585 1.7 christos 586 1.7 christos evbuffer_add(buf, "foo", 3); 587 1.7 christos 588 1.7 christos evbuffer_add_reference(dst, NULL, 0, NULL, NULL); 589 1.7 christos evbuffer_add_buffer(dst, buf); 590 1.7 christos 591 1.7 christos tt_int_op(evbuffer_get_length(src), ==, 3); 592 1.7 christos tt_int_op(evbuffer_get_length(dst), ==, 3); 593 1.7 christos 594 1.7 christos evbuffer_validate(src); 595 1.7 christos evbuffer_validate(dst); 596 1.7 christos 597 1.7 christos end: 598 1.7 christos evbuffer_free(src); 599 1.7 christos evbuffer_free(dst); 600 1.7 christos evbuffer_free(buf); 601 1.1 christos } 602 1.1 christos 603 1.1 christos static void 604 1.1 christos test_evbuffer_reserve2(void *ptr) 605 1.1 christos { 606 1.1 christos /* Test the two-vector cases of reserve/commit. */ 607 1.1 christos struct evbuffer *buf = evbuffer_new(); 608 1.1 christos int n, i; 609 1.1 christos struct evbuffer_iovec v[2]; 610 1.1 christos size_t remaining; 611 1.1 christos char *cp, *cp2; 612 1.1 christos 613 1.1 christos /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/ 614 1.1 christos n = evbuffer_reserve_space(buf, 1024, v, 2); 615 1.1 christos tt_int_op(n, ==, 1); 616 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 0); 617 1.1 christos tt_assert(v[0].iov_base != NULL); 618 1.1 christos tt_int_op(v[0].iov_len, >=, 1024); 619 1.1 christos memset(v[0].iov_base, 'X', 512); 620 1.1 christos cp = v[0].iov_base; 621 1.1 christos remaining = v[0].iov_len - 512; 622 1.1 christos v[0].iov_len = 512; 623 1.1 christos evbuffer_validate(buf); 624 1.1 christos tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); 625 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 512); 626 1.1 christos evbuffer_validate(buf); 627 1.1 christos 628 1.1 christos /* Ask for another same-chunk request, in an existing chunk. Use 8 629 1.1 christos * bytes of it. */ 630 1.1 christos n = evbuffer_reserve_space(buf, 32, v, 2); 631 1.1 christos tt_int_op(n, ==, 1); 632 1.1 christos tt_assert(cp + 512 == v[0].iov_base); 633 1.1 christos tt_int_op(remaining, ==, v[0].iov_len); 634 1.1 christos memset(v[0].iov_base, 'Y', 8); 635 1.1 christos v[0].iov_len = 8; 636 1.1 christos tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); 637 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 520); 638 1.1 christos remaining -= 8; 639 1.1 christos evbuffer_validate(buf); 640 1.1 christos 641 1.1 christos /* Now ask for a request that will be split. Use only one byte of it, 642 1.1 christos though. */ 643 1.1 christos n = evbuffer_reserve_space(buf, remaining+64, v, 2); 644 1.1 christos tt_int_op(n, ==, 2); 645 1.1 christos tt_assert(cp + 520 == v[0].iov_base); 646 1.1 christos tt_int_op(remaining, ==, v[0].iov_len); 647 1.1 christos tt_assert(v[1].iov_base); 648 1.1 christos tt_assert(v[1].iov_len >= 64); 649 1.1 christos cp2 = v[1].iov_base; 650 1.1 christos memset(v[0].iov_base, 'Z', 1); 651 1.1 christos v[0].iov_len = 1; 652 1.1 christos tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); 653 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 521); 654 1.1 christos remaining -= 1; 655 1.1 christos evbuffer_validate(buf); 656 1.1 christos 657 1.1 christos /* Now ask for a request that will be split. Use some of the first 658 1.1 christos * part and some of the second. */ 659 1.1 christos n = evbuffer_reserve_space(buf, remaining+64, v, 2); 660 1.1 christos evbuffer_validate(buf); 661 1.1 christos tt_int_op(n, ==, 2); 662 1.1 christos tt_assert(cp + 521 == v[0].iov_base); 663 1.1 christos tt_int_op(remaining, ==, v[0].iov_len); 664 1.1 christos tt_assert(v[1].iov_base == cp2); 665 1.1 christos tt_assert(v[1].iov_len >= 64); 666 1.1 christos memset(v[0].iov_base, 'W', 400); 667 1.1 christos v[0].iov_len = 400; 668 1.1 christos memset(v[1].iov_base, 'x', 60); 669 1.1 christos v[1].iov_len = 60; 670 1.1 christos tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2)); 671 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 981); 672 1.1 christos evbuffer_validate(buf); 673 1.1 christos 674 1.1 christos /* Now peek to make sure stuff got made how we like. */ 675 1.1 christos memset(v,0,sizeof(v)); 676 1.1 christos n = evbuffer_peek(buf, -1, NULL, v, 2); 677 1.1 christos tt_int_op(n, ==, 2); 678 1.1 christos tt_int_op(v[0].iov_len, ==, 921); 679 1.1 christos tt_int_op(v[1].iov_len, ==, 60); 680 1.1 christos 681 1.1 christos cp = v[0].iov_base; 682 1.1 christos for (i=0; i<512; ++i) 683 1.1 christos tt_int_op(cp[i], ==, 'X'); 684 1.1 christos for (i=512; i<520; ++i) 685 1.1 christos tt_int_op(cp[i], ==, 'Y'); 686 1.1 christos for (i=520; i<521; ++i) 687 1.1 christos tt_int_op(cp[i], ==, 'Z'); 688 1.1 christos for (i=521; i<921; ++i) 689 1.1 christos tt_int_op(cp[i], ==, 'W'); 690 1.1 christos 691 1.1 christos cp = v[1].iov_base; 692 1.1 christos for (i=0; i<60; ++i) 693 1.1 christos tt_int_op(cp[i], ==, 'x'); 694 1.1 christos 695 1.1 christos end: 696 1.1 christos evbuffer_free(buf); 697 1.1 christos } 698 1.1 christos 699 1.1 christos static void 700 1.1 christos test_evbuffer_reserve_many(void *ptr) 701 1.1 christos { 702 1.1 christos /* This is a glass-box test to handle expanding a buffer with more 703 1.1 christos * chunks and reallocating chunks as needed */ 704 1.1 christos struct evbuffer *buf = evbuffer_new(); 705 1.1 christos struct evbuffer_iovec v[8]; 706 1.1 christos int n; 707 1.1 christos size_t sz; 708 1.1 christos int add_data = ptr && !strcmp(ptr, "add"); 709 1.1 christos int fill_first = ptr && !strcmp(ptr, "fill"); 710 1.1 christos char *cp1, *cp2; 711 1.1 christos 712 1.1 christos /* When reserving the the first chunk, we just allocate it */ 713 1.1 christos n = evbuffer_reserve_space(buf, 128, v, 2); 714 1.1 christos evbuffer_validate(buf); 715 1.1 christos tt_int_op(n, ==, 1); 716 1.1 christos tt_assert(v[0].iov_len >= 128); 717 1.1 christos sz = v[0].iov_len; 718 1.1 christos cp1 = v[0].iov_base; 719 1.1 christos if (add_data) { 720 1.1 christos *(char*)v[0].iov_base = 'X'; 721 1.1 christos v[0].iov_len = 1; 722 1.1 christos n = evbuffer_commit_space(buf, v, 1); 723 1.1 christos tt_int_op(n, ==, 0); 724 1.1 christos } else if (fill_first) { 725 1.1 christos memset(v[0].iov_base, 'X', v[0].iov_len); 726 1.1 christos n = evbuffer_commit_space(buf, v, 1); 727 1.1 christos tt_int_op(n, ==, 0); 728 1.1 christos n = evbuffer_reserve_space(buf, 128, v, 2); 729 1.1 christos tt_int_op(n, ==, 1); 730 1.1 christos sz = v[0].iov_len; 731 1.1 christos tt_assert(v[0].iov_base != cp1); 732 1.1 christos cp1 = v[0].iov_base; 733 1.1 christos } 734 1.1 christos 735 1.1 christos /* Make another chunk get added. */ 736 1.1 christos n = evbuffer_reserve_space(buf, sz+128, v, 2); 737 1.1 christos evbuffer_validate(buf); 738 1.1 christos tt_int_op(n, ==, 2); 739 1.1 christos sz = v[0].iov_len + v[1].iov_len; 740 1.1 christos tt_int_op(sz, >=, v[0].iov_len+128); 741 1.1 christos if (add_data) { 742 1.1 christos tt_assert(v[0].iov_base == cp1 + 1); 743 1.1 christos } else { 744 1.1 christos tt_assert(v[0].iov_base == cp1); 745 1.1 christos } 746 1.1 christos cp1 = v[0].iov_base; 747 1.1 christos cp2 = v[1].iov_base; 748 1.1 christos 749 1.1 christos /* And a third chunk. */ 750 1.1 christos n = evbuffer_reserve_space(buf, sz+128, v, 3); 751 1.1 christos evbuffer_validate(buf); 752 1.1 christos tt_int_op(n, ==, 3); 753 1.1 christos tt_assert(cp1 == v[0].iov_base); 754 1.1 christos tt_assert(cp2 == v[1].iov_base); 755 1.1 christos sz = v[0].iov_len + v[1].iov_len + v[2].iov_len; 756 1.1 christos 757 1.1 christos /* Now force a reallocation by asking for more space in only 2 758 1.1 christos * buffers. */ 759 1.1 christos n = evbuffer_reserve_space(buf, sz+128, v, 2); 760 1.1 christos evbuffer_validate(buf); 761 1.1 christos if (add_data) { 762 1.1 christos tt_int_op(n, ==, 2); 763 1.1 christos tt_assert(cp1 == v[0].iov_base); 764 1.1 christos } else { 765 1.1 christos tt_int_op(n, ==, 1); 766 1.1 christos } 767 1.1 christos 768 1.1 christos end: 769 1.1 christos evbuffer_free(buf); 770 1.1 christos } 771 1.1 christos 772 1.1 christos static void 773 1.7 christos test_evbuffer_reserve_with_empty(void *ptr) 774 1.7 christos { 775 1.7 christos struct evbuffer *buf; 776 1.7 christos struct evbuffer_iovec v[2]; 777 1.7 christos 778 1.7 christos tt_assert(buf = evbuffer_new()); 779 1.7 christos evbuffer_add(buf, "a", 1); 780 1.7 christos tt_int_op(evbuffer_reserve_space(buf, 1<<12, v, 2), ==, 2); 781 1.7 christos v[0].iov_len = 1; 782 1.7 christos *(char *)v[0].iov_base = 'b'; 783 1.7 christos tt_int_op(evbuffer_commit_space(buf, v, 1), ==, 0); 784 1.7 christos evbuffer_add(buf, "c", 1); 785 1.7 christos tt_mem_op(evbuffer_pullup(buf, -1), ==, "abc", 2); 786 1.7 christos 787 1.7 christos evbuffer_validate(buf); 788 1.7 christos 789 1.7 christos end: 790 1.7 christos if (buf) 791 1.7 christos evbuffer_free(buf); 792 1.7 christos } 793 1.7 christos 794 1.7 christos /* regression for evbuffer_expand_fast_() with invalid last_with_datap that has 795 1.7 christos * been left after evbuffer_prepend() with empty chain in it */ 796 1.7 christos static void 797 1.7 christos test_evbuffer_reserve_invalid_last_with_datap(void *ptr) 798 1.7 christos { 799 1.7 christos struct evbuffer *buf = NULL; 800 1.7 christos struct evbuffer_iovec vec[2]; 801 1.7 christos const int nvec = ARRAY_SIZE(vec); 802 1.7 christos int i, avec; 803 1.7 christos 804 1.7 christos buf = evbuffer_new(); 805 1.7 christos tt_assert(buf); 806 1.7 christos 807 1.7 christos /* prepend with an empty chain */ 808 1.7 christos evbuffer_add_reference(buf, "", 0, NULL, NULL); 809 1.7 christos evbuffer_prepend(buf, "foo", 3); 810 1.7 christos /* after invalid last_with_datap will create new chain */ 811 1.7 christos evbuffer_add(buf, "", 0); 812 1.7 christos /* we need to create at least 2 "used" (in evbuffer_expand_fast_()) chains */ 813 1.7 christos tt_int_op(avec = evbuffer_reserve_space(buf, 1<<12, vec, nvec), >=, 1); 814 1.7 christos for (i = 0; i < avec; ++i) 815 1.7 christos vec[i].iov_len = 0; 816 1.7 christos tt_int_op(evbuffer_commit_space(buf, vec, avec), ==, 0); 817 1.7 christos 818 1.7 christos /* and an actual problem, that triggers an assert(chain == buf->first) in 819 1.7 christos * evbuffer_expand_fast_() */ 820 1.7 christos tt_int_op(evbuffer_reserve_space(buf, 1<<13, vec, nvec), >=, 1); 821 1.7 christos 822 1.7 christos evbuffer_validate(buf); 823 1.7 christos 824 1.7 christos end: 825 1.7 christos if (buf) 826 1.7 christos evbuffer_free(buf); 827 1.7 christos } 828 1.7 christos 829 1.7 christos static void 830 1.1 christos test_evbuffer_expand(void *ptr) 831 1.1 christos { 832 1.1 christos char data[4096]; 833 1.1 christos struct evbuffer *buf; 834 1.1 christos size_t a,w,u; 835 1.1 christos void *buffer; 836 1.1 christos 837 1.1 christos memset(data, 'X', sizeof(data)); 838 1.1 christos 839 1.1 christos /* Make sure that expand() works on an empty buffer */ 840 1.1 christos buf = evbuffer_new(); 841 1.1 christos tt_int_op(evbuffer_expand(buf, 20000), ==, 0); 842 1.1 christos evbuffer_validate(buf); 843 1.1 christos a=w=u=0; 844 1.1 christos evbuffer_get_waste(buf, &a,&w,&u); 845 1.1 christos tt_assert(w == 0); 846 1.1 christos tt_assert(u == 0); 847 1.1 christos tt_assert(a >= 20000); 848 1.1 christos tt_assert(buf->first); 849 1.1 christos tt_assert(buf->first == buf->last); 850 1.1 christos tt_assert(buf->first->off == 0); 851 1.1 christos tt_assert(buf->first->buffer_len >= 20000); 852 1.1 christos 853 1.1 christos /* Make sure that expand() works as a no-op when there's enough 854 1.1 christos * contiguous space already. */ 855 1.1 christos buffer = buf->first->buffer; 856 1.1 christos evbuffer_add(buf, data, 1024); 857 1.1 christos tt_int_op(evbuffer_expand(buf, 1024), ==, 0); 858 1.1 christos tt_assert(buf->first->buffer == buffer); 859 1.1 christos evbuffer_validate(buf); 860 1.1 christos evbuffer_free(buf); 861 1.1 christos 862 1.1 christos /* Make sure that expand() can work by moving misaligned data 863 1.1 christos * when it makes sense to do so. */ 864 1.1 christos buf = evbuffer_new(); 865 1.1 christos evbuffer_add(buf, data, 400); 866 1.1 christos { 867 1.1 christos int n = (int)(buf->first->buffer_len - buf->first->off - 1); 868 1.1 christos tt_assert(n < (int)sizeof(data)); 869 1.1 christos evbuffer_add(buf, data, n); 870 1.1 christos } 871 1.1 christos tt_assert(buf->first == buf->last); 872 1.1 christos tt_assert(buf->first->off == buf->first->buffer_len - 1); 873 1.1 christos evbuffer_drain(buf, buf->first->off - 1); 874 1.1 christos tt_assert(1 == evbuffer_get_length(buf)); 875 1.1 christos tt_assert(buf->first->misalign > 0); 876 1.1 christos tt_assert(buf->first->off == 1); 877 1.1 christos buffer = buf->first->buffer; 878 1.1 christos tt_assert(evbuffer_expand(buf, 40) == 0); 879 1.1 christos tt_assert(buf->first == buf->last); 880 1.1 christos tt_assert(buf->first->off == 1); 881 1.1 christos tt_assert(buf->first->buffer == buffer); 882 1.1 christos tt_assert(buf->first->misalign == 0); 883 1.1 christos evbuffer_validate(buf); 884 1.1 christos evbuffer_free(buf); 885 1.1 christos 886 1.1 christos /* add, expand, pull-up: This used to crash libevent. */ 887 1.1 christos buf = evbuffer_new(); 888 1.1 christos 889 1.1 christos evbuffer_add(buf, data, sizeof(data)); 890 1.1 christos evbuffer_add(buf, data, sizeof(data)); 891 1.1 christos evbuffer_add(buf, data, sizeof(data)); 892 1.1 christos 893 1.1 christos evbuffer_validate(buf); 894 1.1 christos evbuffer_expand(buf, 1024); 895 1.1 christos evbuffer_validate(buf); 896 1.1 christos evbuffer_pullup(buf, -1); 897 1.1 christos evbuffer_validate(buf); 898 1.1 christos 899 1.1 christos end: 900 1.1 christos evbuffer_free(buf); 901 1.1 christos } 902 1.1 christos 903 1.7 christos static void 904 1.7 christos test_evbuffer_expand_overflow(void *ptr) 905 1.7 christos { 906 1.7 christos struct evbuffer *buf; 907 1.7 christos 908 1.7 christos buf = evbuffer_new(); 909 1.7 christos evbuffer_add(buf, "1", 1); 910 1.7 christos evbuffer_expand(buf, EVBUFFER_CHAIN_MAX); 911 1.7 christos evbuffer_validate(buf); 912 1.7 christos 913 1.7 christos evbuffer_expand(buf, EV_SIZE_MAX); 914 1.7 christos evbuffer_validate(buf); 915 1.7 christos 916 1.7 christos end: 917 1.7 christos evbuffer_free(buf); 918 1.7 christos } 919 1.7 christos 920 1.7 christos static void 921 1.7 christos test_evbuffer_add1(void *ptr) 922 1.7 christos { 923 1.7 christos struct evbuffer *buf; 924 1.7 christos char *str; 925 1.7 christos 926 1.7 christos buf = evbuffer_new(); 927 1.7 christos evbuffer_add(buf, "1", 1); 928 1.7 christos evbuffer_validate(buf); 929 1.7 christos evbuffer_expand(buf, 2048); 930 1.7 christos evbuffer_validate(buf); 931 1.7 christos evbuffer_add(buf, "2", 1); 932 1.7 christos evbuffer_validate(buf); 933 1.7 christos evbuffer_add_printf(buf, "3"); 934 1.7 christos evbuffer_validate(buf); 935 1.7 christos 936 1.7 christos tt_assert(evbuffer_get_length(buf) == 3); 937 1.7 christos str = (char *)evbuffer_pullup(buf, -1); 938 1.7 christos tt_assert(str[0] == '1'); 939 1.7 christos tt_assert(str[1] == '2'); 940 1.7 christos tt_assert(str[2] == '3'); 941 1.7 christos end: 942 1.7 christos evbuffer_free(buf); 943 1.7 christos } 944 1.7 christos 945 1.7 christos static void 946 1.7 christos test_evbuffer_add2(void *ptr) 947 1.7 christos { 948 1.7 christos struct evbuffer *buf; 949 1.7 christos static char data[4096]; 950 1.7 christos int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10; 951 1.7 christos char *str; 952 1.7 christos int len; 953 1.7 christos 954 1.7 christos memset(data, 'P', sizeof(data)); 955 1.7 christos buf = evbuffer_new(); 956 1.7 christos evbuffer_add(buf, data, data_len); 957 1.7 christos evbuffer_validate(buf); 958 1.7 christos evbuffer_expand(buf, 100); 959 1.7 christos evbuffer_validate(buf); 960 1.7 christos evbuffer_add(buf, "2", 1); 961 1.7 christos evbuffer_validate(buf); 962 1.7 christos evbuffer_add_printf(buf, "3"); 963 1.7 christos evbuffer_validate(buf); 964 1.7 christos 965 1.7 christos len = evbuffer_get_length(buf); 966 1.7 christos tt_assert(len == data_len+2); 967 1.7 christos str = (char *)evbuffer_pullup(buf, -1); 968 1.7 christos tt_assert(str[len-3] == 'P'); 969 1.7 christos tt_assert(str[len-2] == '2'); 970 1.7 christos tt_assert(str[len-1] == '3'); 971 1.7 christos end: 972 1.7 christos evbuffer_free(buf); 973 1.7 christos } 974 1.1 christos 975 1.1 christos static int reference_cb_called; 976 1.1 christos static void 977 1.1 christos reference_cb(const void *data, size_t len, void *extra) 978 1.1 christos { 979 1.1 christos tt_str_op(data, ==, "this is what we add as read-only memory."); 980 1.1 christos tt_int_op(len, ==, strlen(data)); 981 1.1 christos tt_want(extra == (void *)0xdeadaffe); 982 1.1 christos ++reference_cb_called; 983 1.1 christos end: 984 1.1 christos ; 985 1.1 christos } 986 1.1 christos 987 1.1 christos static void 988 1.1 christos test_evbuffer_reference(void *ptr) 989 1.1 christos { 990 1.1 christos struct evbuffer *src = evbuffer_new(); 991 1.1 christos struct evbuffer *dst = evbuffer_new(); 992 1.1 christos struct evbuffer_iovec v[1]; 993 1.1 christos const char *data = "this is what we add as read-only memory."; 994 1.1 christos reference_cb_called = 0; 995 1.1 christos 996 1.1 christos tt_assert(evbuffer_add_reference(src, data, strlen(data), 997 1.1 christos reference_cb, (void *)0xdeadaffe) != -1); 998 1.1 christos 999 1.1 christos evbuffer_reserve_space(dst, strlen(data), v, 1); 1000 1.1 christos tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1); 1001 1.1 christos 1002 1.1 christos evbuffer_validate(src); 1003 1.1 christos evbuffer_validate(dst); 1004 1.1 christos 1005 1.1 christos /* make sure that we don't write data at the beginning */ 1006 1.1 christos evbuffer_prepend(src, "aaaaa", 5); 1007 1.1 christos evbuffer_validate(src); 1008 1.1 christos evbuffer_drain(src, 5); 1009 1.1 christos 1010 1.1 christos tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10, 1011 1.1 christos strlen(data) - 10) != -1); 1012 1.1 christos 1013 1.1 christos v[0].iov_len = strlen(data); 1014 1.1 christos 1015 1.1 christos evbuffer_commit_space(dst, v, 1); 1016 1.1 christos evbuffer_validate(src); 1017 1.1 christos evbuffer_validate(dst); 1018 1.1 christos 1019 1.1 christos tt_int_op(reference_cb_called, ==, 1); 1020 1.1 christos 1021 1.1 christos tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)), 1022 1.1 christos data, strlen(data))); 1023 1.1 christos evbuffer_validate(dst); 1024 1.1 christos 1025 1.1 christos end: 1026 1.1 christos evbuffer_free(dst); 1027 1.1 christos evbuffer_free(src); 1028 1.1 christos } 1029 1.1 christos 1030 1.7 christos static void 1031 1.7 christos test_evbuffer_reference2(void *ptr) 1032 1.7 christos { 1033 1.7 christos struct evbuffer *buf; 1034 1.7 christos static char data[4096]; 1035 1.7 christos int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10; 1036 1.7 christos char *str; 1037 1.7 christos int len; 1038 1.7 christos 1039 1.7 christos memset(data, 'P', sizeof(data)); 1040 1.7 christos buf = evbuffer_new(); 1041 1.7 christos evbuffer_add(buf, data, data_len); 1042 1.7 christos evbuffer_validate(buf); 1043 1.7 christos evbuffer_expand(buf, 100); 1044 1.7 christos evbuffer_validate(buf); 1045 1.7 christos evbuffer_add_reference(buf, "2", 1, no_cleanup, NULL); 1046 1.7 christos evbuffer_validate(buf); 1047 1.7 christos evbuffer_add_printf(buf, "3"); 1048 1.7 christos evbuffer_validate(buf); 1049 1.7 christos 1050 1.7 christos len = evbuffer_get_length(buf); 1051 1.7 christos tt_assert(len == data_len+2); 1052 1.7 christos str = (char *)evbuffer_pullup(buf, -1); 1053 1.7 christos tt_assert(str[len-3] == 'P'); 1054 1.7 christos tt_assert(str[len-2] == '2'); 1055 1.7 christos tt_assert(str[len-1] == '3'); 1056 1.7 christos end: 1057 1.7 christos evbuffer_free(buf); 1058 1.7 christos } 1059 1.7 christos 1060 1.7 christos static struct event_base *addfile_test_event_base; 1061 1.7 christos static int addfile_test_done_writing; 1062 1.7 christos static int addfile_test_total_written; 1063 1.7 christos static int addfile_test_total_read; 1064 1.1 christos 1065 1.1 christos static void 1066 1.1 christos addfile_test_writecb(evutil_socket_t fd, short what, void *arg) 1067 1.1 christos { 1068 1.1 christos struct evbuffer *b = arg; 1069 1.1 christos int r; 1070 1.1 christos evbuffer_validate(b); 1071 1.1 christos while (evbuffer_get_length(b)) { 1072 1.1 christos r = evbuffer_write(b, fd); 1073 1.1 christos if (r > 0) { 1074 1.1 christos addfile_test_total_written += r; 1075 1.1 christos TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written)); 1076 1.1 christos } else { 1077 1.1 christos int e = evutil_socket_geterror(fd); 1078 1.1 christos if (EVUTIL_ERR_RW_RETRIABLE(e)) 1079 1.1 christos return; 1080 1.1 christos tt_fail_perror("write"); 1081 1.1 christos event_base_loopexit(addfile_test_event_base,NULL); 1082 1.1 christos } 1083 1.1 christos evbuffer_validate(b); 1084 1.1 christos } 1085 1.1 christos addfile_test_done_writing = 1; 1086 1.1 christos return; 1087 1.1 christos end: 1088 1.1 christos event_base_loopexit(addfile_test_event_base,NULL); 1089 1.1 christos } 1090 1.1 christos 1091 1.1 christos static void 1092 1.1 christos addfile_test_readcb(evutil_socket_t fd, short what, void *arg) 1093 1.1 christos { 1094 1.1 christos struct evbuffer *b = arg; 1095 1.1 christos int e, r = 0; 1096 1.1 christos do { 1097 1.1 christos r = evbuffer_read(b, fd, 1024); 1098 1.1 christos if (r > 0) { 1099 1.1 christos addfile_test_total_read += r; 1100 1.1 christos TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read)); 1101 1.1 christos } 1102 1.1 christos } while (r > 0); 1103 1.1 christos if (r < 0) { 1104 1.1 christos e = evutil_socket_geterror(fd); 1105 1.1 christos if (! EVUTIL_ERR_RW_RETRIABLE(e)) { 1106 1.1 christos tt_fail_perror("read"); 1107 1.1 christos event_base_loopexit(addfile_test_event_base,NULL); 1108 1.1 christos } 1109 1.1 christos } 1110 1.1 christos if (addfile_test_done_writing && 1111 1.1 christos addfile_test_total_read >= addfile_test_total_written) { 1112 1.1 christos event_base_loopexit(addfile_test_event_base,NULL); 1113 1.1 christos } 1114 1.1 christos } 1115 1.1 christos 1116 1.1 christos static void 1117 1.1 christos test_evbuffer_add_file(void *ptr) 1118 1.1 christos { 1119 1.1 christos struct basic_test_data *testdata = ptr; 1120 1.1 christos const char *impl = testdata->setup_data; 1121 1.1 christos struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new(); 1122 1.1 christos char *tmpfilename = NULL; 1123 1.1 christos char *data = NULL; 1124 1.1 christos const char *expect_data; 1125 1.1 christos size_t datalen, expect_len; 1126 1.1 christos const char *compare; 1127 1.1 christos int fd = -1; 1128 1.1 christos int want_ismapping = -1, want_cansendfile = -1; 1129 1.1 christos unsigned flags = 0; 1130 1.1 christos int use_segment = 1, use_bigfile = 0, map_from_offset = 0, 1131 1.1 christos view_from_offset = 0; 1132 1.1 christos struct evbuffer_file_segment *seg = NULL; 1133 1.1 christos ev_off_t starting_offset = 0, mapping_len = -1; 1134 1.1 christos ev_off_t segment_offset = 0, segment_len = -1; 1135 1.1 christos struct event *rev=NULL, *wev=NULL; 1136 1.1 christos struct event_base *base = testdata->base; 1137 1.1 christos evutil_socket_t pair[2] = {-1, -1}; 1138 1.1 christos struct evutil_weakrand_state seed = { 123456789U }; 1139 1.1 christos 1140 1.1 christos /* This test is highly parameterized based on substrings of its 1141 1.1 christos * argument. The strings are: */ 1142 1.1 christos tt_assert(impl); 1143 1.1 christos if (strstr(impl, "nosegment")) { 1144 1.1 christos /* If nosegment is set, use the older evbuffer_add_file 1145 1.1 christos * interface */ 1146 1.1 christos use_segment = 0; 1147 1.1 christos } 1148 1.1 christos if (strstr(impl, "bigfile")) { 1149 1.1 christos /* If bigfile is set, use a 512K file. Else use a smaller 1150 1.1 christos * one. */ 1151 1.1 christos use_bigfile = 1; 1152 1.1 christos } 1153 1.1 christos if (strstr(impl, "map_offset")) { 1154 1.1 christos /* If map_offset is set, we build the file segment starting 1155 1.1 christos * from a point other than byte 0 and ending somewhere other 1156 1.1 christos * than the last byte. Otherwise we map the whole thing */ 1157 1.1 christos map_from_offset = 1; 1158 1.1 christos } 1159 1.1 christos if (strstr(impl, "offset_in_segment")) { 1160 1.1 christos /* If offset_in_segment is set, we add a subsection of the 1161 1.1 christos * file semgment starting from a point other than byte 0 of 1162 1.1 christos * the segment. */ 1163 1.1 christos view_from_offset = 1; 1164 1.1 christos } 1165 1.1 christos if (strstr(impl, "sendfile")) { 1166 1.1 christos /* If sendfile is set, we try to use a sendfile/splice style 1167 1.1 christos * backend. */ 1168 1.1 christos flags = EVBUF_FS_DISABLE_MMAP; 1169 1.1 christos want_cansendfile = 1; 1170 1.1 christos want_ismapping = 0; 1171 1.1 christos } else if (strstr(impl, "mmap")) { 1172 1.1 christos /* If sendfile is set, we try to use a mmap/CreateFileMapping 1173 1.1 christos * style backend. */ 1174 1.1 christos flags = EVBUF_FS_DISABLE_SENDFILE; 1175 1.1 christos want_ismapping = 1; 1176 1.1 christos want_cansendfile = 0; 1177 1.1 christos } else if (strstr(impl, "linear")) { 1178 1.1 christos /* If linear is set, we try to use a read-the-whole-thing 1179 1.1 christos * backend. */ 1180 1.1 christos flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP; 1181 1.1 christos want_ismapping = 0; 1182 1.1 christos want_cansendfile = 0; 1183 1.1 christos } else if (strstr(impl, "default")) { 1184 1.1 christos /* The caller doesn't care which backend we use. */ 1185 1.1 christos ; 1186 1.1 christos } else { 1187 1.1 christos /* The caller must choose a backend. */ 1188 1.1 christos TT_DIE(("Didn't recognize the implementation")); 1189 1.1 christos } 1190 1.1 christos 1191 1.1 christos if (use_bigfile) { 1192 1.1 christos unsigned int i; 1193 1.1 christos datalen = 1024*512; 1194 1.1 christos data = malloc(1024*512); 1195 1.1 christos tt_assert(data); 1196 1.1 christos for (i = 0; i < datalen; ++i) 1197 1.1 christos data[i] = (char)evutil_weakrand_(&seed); 1198 1.1 christos } else { 1199 1.1 christos data = strdup("here is a relatively small string."); 1200 1.1 christos tt_assert(data); 1201 1.1 christos datalen = strlen(data); 1202 1.1 christos } 1203 1.1 christos 1204 1.1 christos fd = regress_make_tmpfile(data, datalen, &tmpfilename); 1205 1.1 christos 1206 1.1 christos if (map_from_offset) { 1207 1.1 christos starting_offset = datalen/4 + 1; 1208 1.1 christos mapping_len = datalen / 2 - 1; 1209 1.1 christos expect_data = data + starting_offset; 1210 1.1 christos expect_len = mapping_len; 1211 1.1 christos } else { 1212 1.1 christos expect_data = data; 1213 1.1 christos expect_len = datalen; 1214 1.1 christos } 1215 1.1 christos if (view_from_offset) { 1216 1.1 christos tt_assert(use_segment); /* Can't do this with add_file*/ 1217 1.1 christos segment_offset = expect_len / 3; 1218 1.1 christos segment_len = expect_len / 2; 1219 1.1 christos expect_data = expect_data + segment_offset; 1220 1.1 christos expect_len = segment_len; 1221 1.1 christos } 1222 1.1 christos 1223 1.1 christos if (use_segment) { 1224 1.1 christos seg = evbuffer_file_segment_new(fd, starting_offset, 1225 1.1 christos mapping_len, flags); 1226 1.1 christos tt_assert(seg); 1227 1.1 christos if (want_ismapping >= 0) { 1228 1.1 christos if (seg->is_mapping != (unsigned)want_ismapping) 1229 1.1 christos tt_skip(); 1230 1.1 christos } 1231 1.1 christos if (want_cansendfile >= 0) { 1232 1.1 christos if (seg->can_sendfile != (unsigned)want_cansendfile) 1233 1.1 christos tt_skip(); 1234 1.1 christos } 1235 1.1 christos } 1236 1.1 christos 1237 1.1 christos /* Say that it drains to a fd so that we can use sendfile. */ 1238 1.1 christos evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD); 1239 1.1 christos 1240 1.1 christos #if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__) 1241 1.1 christos /* We need to use a pair of AF_INET sockets, since Solaris 1242 1.1 christos doesn't support sendfile() over AF_UNIX. */ 1243 1.1 christos if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) 1244 1.1 christos tt_abort_msg("ersatz_socketpair failed"); 1245 1.1 christos #else 1246 1.1 christos if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) 1247 1.1 christos tt_abort_msg("socketpair failed"); 1248 1.1 christos #endif 1249 1.1 christos evutil_make_socket_nonblocking(pair[0]); 1250 1.1 christos evutil_make_socket_nonblocking(pair[1]); 1251 1.1 christos 1252 1.1 christos tt_assert(fd != -1); 1253 1.1 christos 1254 1.1 christos if (use_segment) { 1255 1.1 christos tt_assert(evbuffer_add_file_segment(src, seg, 1256 1.1 christos segment_offset, segment_len)!=-1); 1257 1.1 christos } else { 1258 1.1 christos tt_assert(evbuffer_add_file(src, fd, starting_offset, 1259 1.1 christos mapping_len) != -1); 1260 1.1 christos } 1261 1.1 christos 1262 1.1 christos evbuffer_validate(src); 1263 1.1 christos 1264 1.1 christos addfile_test_event_base = base; 1265 1.7 christos addfile_test_done_writing = 0; 1266 1.7 christos addfile_test_total_written = 0; 1267 1.7 christos addfile_test_total_read = 0; 1268 1.7 christos 1269 1.1 christos wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST, 1270 1.1 christos addfile_test_writecb, src); 1271 1.1 christos rev = event_new(base, pair[1], EV_READ|EV_PERSIST, 1272 1.1 christos addfile_test_readcb, dest); 1273 1.1 christos 1274 1.1 christos event_add(wev, NULL); 1275 1.1 christos event_add(rev, NULL); 1276 1.1 christos event_base_dispatch(base); 1277 1.1 christos 1278 1.1 christos evbuffer_validate(src); 1279 1.1 christos evbuffer_validate(dest); 1280 1.1 christos 1281 1.1 christos tt_assert(addfile_test_done_writing); 1282 1.1 christos tt_int_op(addfile_test_total_written, ==, expect_len); 1283 1.1 christos tt_int_op(addfile_test_total_read, ==, expect_len); 1284 1.1 christos 1285 1.1 christos compare = (char *)evbuffer_pullup(dest, expect_len); 1286 1.1 christos tt_assert(compare != NULL); 1287 1.1 christos if (memcmp(compare, expect_data, expect_len)) { 1288 1.1 christos tt_abort_msg("Data from add_file differs."); 1289 1.1 christos } 1290 1.1 christos 1291 1.1 christos evbuffer_validate(dest); 1292 1.1 christos end: 1293 1.1 christos if (data) 1294 1.1 christos free(data); 1295 1.1 christos if (seg) 1296 1.1 christos evbuffer_file_segment_free(seg); 1297 1.1 christos if (src) 1298 1.1 christos evbuffer_free(src); 1299 1.1 christos if (dest) 1300 1.1 christos evbuffer_free(dest); 1301 1.1 christos if (pair[0] >= 0) 1302 1.1 christos evutil_closesocket(pair[0]); 1303 1.1 christos if (pair[1] >= 0) 1304 1.1 christos evutil_closesocket(pair[1]); 1305 1.3 christos if (wev) 1306 1.3 christos event_free(wev); 1307 1.3 christos if (rev) 1308 1.3 christos event_free(rev); 1309 1.1 christos if (tmpfilename) { 1310 1.1 christos unlink(tmpfilename); 1311 1.1 christos free(tmpfilename); 1312 1.1 christos } 1313 1.1 christos } 1314 1.1 christos 1315 1.1 christos static int file_segment_cleanup_cb_called_count = 0; 1316 1.1 christos static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL; 1317 1.1 christos static int file_segment_cleanup_cb_called_with_flags = 0; 1318 1.1 christos static void* file_segment_cleanup_cb_called_with_arg = NULL; 1319 1.1 christos static void 1320 1.1 christos file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg) 1321 1.1 christos { 1322 1.1 christos ++file_segment_cleanup_cb_called_count; 1323 1.1 christos file_segment_cleanup_cb_called_with = seg; 1324 1.1 christos file_segment_cleanup_cb_called_with_flags = flags; 1325 1.1 christos file_segment_cleanup_cb_called_with_arg = arg; 1326 1.1 christos } 1327 1.1 christos 1328 1.1 christos static void 1329 1.1 christos test_evbuffer_file_segment_add_cleanup_cb(void* ptr) 1330 1.1 christos { 1331 1.1 christos char *tmpfilename = NULL; 1332 1.1 christos int fd = -1; 1333 1.1 christos struct evbuffer *evb = NULL; 1334 1.2 christos struct evbuffer_file_segment *seg = NULL, *segptr; 1335 1.1 christos char const* arg = "token"; 1336 1.1 christos 1337 1.1 christos fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename); 1338 1.2 christos tt_int_op(fd, >=, 0); 1339 1.1 christos 1340 1.1 christos evb = evbuffer_new(); 1341 1.1 christos tt_assert(evb); 1342 1.1 christos 1343 1.2 christos segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0); 1344 1.1 christos tt_assert(seg); 1345 1.1 christos 1346 1.1 christos evbuffer_file_segment_add_cleanup_cb( 1347 1.1 christos seg, &file_segment_cleanup_cp, (void*)arg); 1348 1.1 christos 1349 1.1 christos tt_assert(fd != -1); 1350 1.1 christos 1351 1.1 christos tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1); 1352 1.2 christos 1353 1.1 christos evbuffer_validate(evb); 1354 1.1 christos 1355 1.1 christos tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); 1356 1.1 christos evbuffer_file_segment_free(seg); 1357 1.2 christos seg = NULL; /* Prevent double-free. */ 1358 1.1 christos 1359 1.1 christos tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); 1360 1.1 christos evbuffer_free(evb); 1361 1.2 christos evb = NULL; /* pevent double-free */ 1362 1.2 christos 1363 1.1 christos tt_int_op(file_segment_cleanup_cb_called_count, ==, 1); 1364 1.2 christos tt_assert(file_segment_cleanup_cb_called_with == segptr); 1365 1.1 christos tt_assert(file_segment_cleanup_cb_called_with_flags == 0); 1366 1.1 christos tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg); 1367 1.1 christos 1368 1.1 christos end: 1369 1.2 christos if (evb) 1370 1.2 christos evbuffer_free(evb); 1371 1.2 christos if (seg) 1372 1.2 christos evbuffer_file_segment_free(seg); 1373 1.1 christos if (tmpfilename) { 1374 1.1 christos unlink(tmpfilename); 1375 1.1 christos free(tmpfilename); 1376 1.1 christos } 1377 1.1 christos } 1378 1.1 christos 1379 1.1 christos #ifndef EVENT__DISABLE_MM_REPLACEMENT 1380 1.1 christos static void * 1381 1.1 christos failing_malloc(size_t how_much) 1382 1.1 christos { 1383 1.1 christos errno = ENOMEM; 1384 1.1 christos return NULL; 1385 1.1 christos } 1386 1.1 christos #endif 1387 1.1 christos 1388 1.1 christos static void 1389 1.1 christos test_evbuffer_readln(void *ptr) 1390 1.1 christos { 1391 1.1 christos struct evbuffer *evb = evbuffer_new(); 1392 1.1 christos struct evbuffer *evb_tmp = evbuffer_new(); 1393 1.1 christos const char *s; 1394 1.1 christos char *cp = NULL; 1395 1.1 christos size_t sz; 1396 1.1 christos 1397 1.1 christos #define tt_line_eq(content) \ 1398 1.1 christos TT_STMT_BEGIN \ 1399 1.1 christos if (!cp || sz != strlen(content) || strcmp(cp, content)) { \ 1400 1.1 christos TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \ 1401 1.1 christos } \ 1402 1.1 christos TT_STMT_END 1403 1.1 christos 1404 1.1 christos /* Test EOL_ANY. */ 1405 1.1 christos s = "complex silly newline\r\n\n\r\n\n\rmore\0\n"; 1406 1.1 christos evbuffer_add(evb, s, strlen(s)+2); 1407 1.1 christos evbuffer_validate(evb); 1408 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); 1409 1.1 christos tt_line_eq("complex silly newline"); 1410 1.1 christos free(cp); 1411 1.1 christos evbuffer_validate(evb); 1412 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); 1413 1.1 christos if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6)) 1414 1.1 christos tt_abort_msg("Not as expected"); 1415 1.1 christos tt_uint_op(evbuffer_get_length(evb), ==, 0); 1416 1.1 christos evbuffer_validate(evb); 1417 1.1 christos s = "\nno newline"; 1418 1.1 christos evbuffer_add(evb, s, strlen(s)); 1419 1.1 christos free(cp); 1420 1.1 christos evbuffer_validate(evb); 1421 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); 1422 1.1 christos tt_line_eq(""); 1423 1.1 christos free(cp); 1424 1.1 christos evbuffer_validate(evb); 1425 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); 1426 1.1 christos tt_assert(!cp); 1427 1.1 christos evbuffer_validate(evb); 1428 1.1 christos evbuffer_drain(evb, evbuffer_get_length(evb)); 1429 1.1 christos tt_assert(evbuffer_get_length(evb) == 0); 1430 1.1 christos evbuffer_validate(evb); 1431 1.1 christos 1432 1.1 christos /* Test EOL_CRLF */ 1433 1.1 christos s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n"; 1434 1.1 christos evbuffer_add(evb, s, strlen(s)); 1435 1.1 christos evbuffer_validate(evb); 1436 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); 1437 1.1 christos tt_line_eq("Line with\rin the middle"); 1438 1.1 christos free(cp); 1439 1.1 christos evbuffer_validate(evb); 1440 1.1 christos 1441 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); 1442 1.1 christos tt_line_eq("Line with good crlf"); 1443 1.1 christos free(cp); 1444 1.1 christos evbuffer_validate(evb); 1445 1.1 christos 1446 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); 1447 1.1 christos tt_line_eq(""); 1448 1.1 christos free(cp); 1449 1.1 christos evbuffer_validate(evb); 1450 1.1 christos 1451 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); 1452 1.1 christos tt_line_eq("final"); 1453 1.1 christos s = "x"; 1454 1.1 christos evbuffer_validate(evb); 1455 1.1 christos evbuffer_add(evb, s, 1); 1456 1.1 christos evbuffer_validate(evb); 1457 1.1 christos free(cp); 1458 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); 1459 1.1 christos tt_assert(!cp); 1460 1.1 christos evbuffer_validate(evb); 1461 1.1 christos 1462 1.1 christos /* Test CRLF_STRICT */ 1463 1.1 christos s = " and a bad crlf\nand a good one\r\n\r\nMore\r"; 1464 1.1 christos evbuffer_add(evb, s, strlen(s)); 1465 1.1 christos evbuffer_validate(evb); 1466 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1467 1.1 christos tt_line_eq("x and a bad crlf\nand a good one"); 1468 1.1 christos free(cp); 1469 1.1 christos evbuffer_validate(evb); 1470 1.1 christos 1471 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1472 1.1 christos tt_line_eq(""); 1473 1.1 christos free(cp); 1474 1.1 christos evbuffer_validate(evb); 1475 1.1 christos 1476 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1477 1.1 christos tt_assert(!cp); 1478 1.1 christos evbuffer_validate(evb); 1479 1.1 christos evbuffer_add(evb, "\n", 1); 1480 1.1 christos evbuffer_validate(evb); 1481 1.1 christos 1482 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1483 1.1 christos tt_line_eq("More"); 1484 1.1 christos free(cp); 1485 1.1 christos tt_assert(evbuffer_get_length(evb) == 0); 1486 1.1 christos evbuffer_validate(evb); 1487 1.1 christos 1488 1.1 christos s = "An internal CR\r is not an eol\r\nNor is a lack of one"; 1489 1.1 christos evbuffer_add(evb, s, strlen(s)); 1490 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1491 1.1 christos tt_line_eq("An internal CR\r is not an eol"); 1492 1.1 christos free(cp); 1493 1.1 christos evbuffer_validate(evb); 1494 1.1 christos 1495 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1496 1.1 christos tt_assert(!cp); 1497 1.1 christos evbuffer_validate(evb); 1498 1.1 christos 1499 1.1 christos evbuffer_add(evb, "\r\n", 2); 1500 1.1 christos evbuffer_validate(evb); 1501 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1502 1.1 christos tt_line_eq("Nor is a lack of one"); 1503 1.1 christos free(cp); 1504 1.1 christos tt_assert(evbuffer_get_length(evb) == 0); 1505 1.1 christos evbuffer_validate(evb); 1506 1.1 christos 1507 1.1 christos /* Test LF */ 1508 1.1 christos s = "An\rand a nl\n\nText"; 1509 1.1 christos evbuffer_add(evb, s, strlen(s)); 1510 1.1 christos evbuffer_validate(evb); 1511 1.1 christos 1512 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1513 1.1 christos tt_line_eq("An\rand a nl"); 1514 1.1 christos free(cp); 1515 1.1 christos evbuffer_validate(evb); 1516 1.1 christos 1517 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1518 1.1 christos tt_line_eq(""); 1519 1.1 christos free(cp); 1520 1.1 christos evbuffer_validate(evb); 1521 1.1 christos 1522 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1523 1.1 christos tt_assert(!cp); 1524 1.1 christos free(cp); 1525 1.1 christos evbuffer_add(evb, "\n", 1); 1526 1.1 christos evbuffer_validate(evb); 1527 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1528 1.1 christos tt_line_eq("Text"); 1529 1.1 christos free(cp); 1530 1.1 christos evbuffer_validate(evb); 1531 1.1 christos 1532 1.1 christos /* Test NUL */ 1533 1.1 christos tt_int_op(evbuffer_get_length(evb), ==, 0); 1534 1.1 christos { 1535 1.1 christos char x[] = 1536 1.1 christos "NUL\n\0\0" 1537 1.1 christos "The all-zeros character which may serve\0" 1538 1.1 christos "to accomplish time fill\0and media fill"; 1539 1.1 christos /* Add all but the final NUL of x. */ 1540 1.1 christos evbuffer_add(evb, x, sizeof(x)-1); 1541 1.1 christos } 1542 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); 1543 1.1 christos tt_line_eq("NUL\n"); 1544 1.1 christos free(cp); 1545 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); 1546 1.1 christos tt_line_eq(""); 1547 1.1 christos free(cp); 1548 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); 1549 1.1 christos tt_line_eq("The all-zeros character which may serve"); 1550 1.1 christos free(cp); 1551 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); 1552 1.1 christos tt_line_eq("to accomplish time fill"); 1553 1.1 christos free(cp); 1554 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); 1555 1.1 christos tt_ptr_op(cp, ==, NULL); 1556 1.1 christos evbuffer_drain(evb, -1); 1557 1.1 christos 1558 1.1 christos /* Test CRLF_STRICT - across boundaries*/ 1559 1.1 christos s = " and a bad crlf\nand a good one\r"; 1560 1.1 christos evbuffer_add(evb_tmp, s, strlen(s)); 1561 1.1 christos evbuffer_validate(evb); 1562 1.1 christos evbuffer_add_buffer(evb, evb_tmp); 1563 1.1 christos evbuffer_validate(evb); 1564 1.1 christos s = "\n\r"; 1565 1.1 christos evbuffer_add(evb_tmp, s, strlen(s)); 1566 1.1 christos evbuffer_validate(evb); 1567 1.1 christos evbuffer_add_buffer(evb, evb_tmp); 1568 1.1 christos evbuffer_validate(evb); 1569 1.1 christos s = "\nMore\r"; 1570 1.1 christos evbuffer_add(evb_tmp, s, strlen(s)); 1571 1.1 christos evbuffer_validate(evb); 1572 1.1 christos evbuffer_add_buffer(evb, evb_tmp); 1573 1.1 christos evbuffer_validate(evb); 1574 1.1 christos 1575 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1576 1.1 christos tt_line_eq(" and a bad crlf\nand a good one"); 1577 1.1 christos free(cp); 1578 1.1 christos evbuffer_validate(evb); 1579 1.1 christos 1580 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1581 1.1 christos tt_line_eq(""); 1582 1.1 christos free(cp); 1583 1.1 christos evbuffer_validate(evb); 1584 1.1 christos 1585 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1586 1.1 christos tt_assert(!cp); 1587 1.1 christos free(cp); 1588 1.1 christos evbuffer_validate(evb); 1589 1.1 christos evbuffer_add(evb, "\n", 1); 1590 1.1 christos evbuffer_validate(evb); 1591 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); 1592 1.1 christos tt_line_eq("More"); 1593 1.1 christos free(cp); cp = NULL; 1594 1.1 christos evbuffer_validate(evb); 1595 1.1 christos tt_assert(evbuffer_get_length(evb) == 0); 1596 1.1 christos 1597 1.1 christos /* Test memory problem*/ 1598 1.1 christos s = "one line\ntwo line\nblue line"; 1599 1.1 christos evbuffer_add(evb_tmp, s, strlen(s)); 1600 1.1 christos evbuffer_validate(evb); 1601 1.1 christos evbuffer_add_buffer(evb, evb_tmp); 1602 1.1 christos evbuffer_validate(evb); 1603 1.1 christos 1604 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1605 1.1 christos tt_line_eq("one line"); 1606 1.1 christos free(cp); cp = NULL; 1607 1.1 christos evbuffer_validate(evb); 1608 1.1 christos 1609 1.1 christos /* the next call to readline should fail */ 1610 1.1 christos #ifndef EVENT__DISABLE_MM_REPLACEMENT 1611 1.1 christos event_set_mem_functions(failing_malloc, realloc, free); 1612 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1613 1.1 christos tt_assert(cp == NULL); 1614 1.1 christos evbuffer_validate(evb); 1615 1.1 christos 1616 1.1 christos /* now we should get the next line back */ 1617 1.1 christos event_set_mem_functions(malloc, realloc, free); 1618 1.1 christos #endif 1619 1.1 christos cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); 1620 1.1 christos tt_line_eq("two line"); 1621 1.1 christos free(cp); cp = NULL; 1622 1.1 christos evbuffer_validate(evb); 1623 1.1 christos 1624 1.1 christos end: 1625 1.1 christos evbuffer_free(evb); 1626 1.1 christos evbuffer_free(evb_tmp); 1627 1.1 christos if (cp) free(cp); 1628 1.1 christos } 1629 1.1 christos 1630 1.1 christos static void 1631 1.1 christos test_evbuffer_search_eol(void *ptr) 1632 1.1 christos { 1633 1.1 christos struct evbuffer *buf = evbuffer_new(); 1634 1.1 christos struct evbuffer_ptr ptr1, ptr2; 1635 1.1 christos const char *s; 1636 1.1 christos size_t eol_len; 1637 1.1 christos 1638 1.1 christos s = "string! \r\n\r\nx\n"; 1639 1.1 christos evbuffer_add(buf, s, strlen(s)); 1640 1.1 christos eol_len = -1; 1641 1.1 christos ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF); 1642 1.1 christos tt_int_op(ptr1.pos, ==, 8); 1643 1.1 christos tt_int_op(eol_len, ==, 2); 1644 1.1 christos 1645 1.1 christos eol_len = -1; 1646 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); 1647 1.1 christos tt_int_op(ptr2.pos, ==, 8); 1648 1.1 christos tt_int_op(eol_len, ==, 2); 1649 1.1 christos 1650 1.1 christos evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); 1651 1.1 christos eol_len = -1; 1652 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); 1653 1.1 christos tt_int_op(ptr2.pos, ==, 9); 1654 1.1 christos tt_int_op(eol_len, ==, 1); 1655 1.1 christos 1656 1.1 christos eol_len = -1; 1657 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT); 1658 1.1 christos tt_int_op(ptr2.pos, ==, 10); 1659 1.1 christos tt_int_op(eol_len, ==, 2); 1660 1.1 christos 1661 1.1 christos eol_len = -1; 1662 1.1 christos ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF); 1663 1.1 christos tt_int_op(ptr1.pos, ==, 9); 1664 1.1 christos tt_int_op(eol_len, ==, 1); 1665 1.1 christos 1666 1.1 christos eol_len = -1; 1667 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); 1668 1.1 christos tt_int_op(ptr2.pos, ==, 9); 1669 1.1 christos tt_int_op(eol_len, ==, 1); 1670 1.1 christos 1671 1.1 christos evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); 1672 1.1 christos eol_len = -1; 1673 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); 1674 1.1 christos tt_int_op(ptr2.pos, ==, 11); 1675 1.1 christos tt_int_op(eol_len, ==, 1); 1676 1.1 christos 1677 1.1 christos tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); 1678 1.1 christos eol_len = -1; 1679 1.1 christos ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); 1680 1.1 christos tt_int_op(ptr2.pos, ==, -1); 1681 1.1 christos tt_int_op(eol_len, ==, 0); 1682 1.1 christos 1683 1.1 christos end: 1684 1.1 christos evbuffer_free(buf); 1685 1.1 christos } 1686 1.1 christos 1687 1.1 christos static void 1688 1.1 christos test_evbuffer_iterative(void *ptr) 1689 1.1 christos { 1690 1.1 christos struct evbuffer *buf = evbuffer_new(); 1691 1.1 christos const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz"; 1692 1.1 christos unsigned i, j, sum, n; 1693 1.1 christos 1694 1.1 christos sum = 0; 1695 1.1 christos n = 0; 1696 1.1 christos for (i = 0; i < 1000; ++i) { 1697 1.1 christos for (j = 1; j < strlen(abc); ++j) { 1698 1.1 christos char format[32]; 1699 1.1 christos evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j); 1700 1.1 christos evbuffer_add_printf(buf, format, abc); 1701 1.1 christos 1702 1.1 christos /* Only check for rep violations every so often. 1703 1.1 christos Walking over the whole list of chains can get 1704 1.1 christos pretty expensive as it gets long. 1705 1.1 christos */ 1706 1.1 christos if ((n % 337) == 0) 1707 1.1 christos evbuffer_validate(buf); 1708 1.1 christos 1709 1.1 christos sum += j; 1710 1.1 christos n++; 1711 1.1 christos } 1712 1.1 christos } 1713 1.1 christos evbuffer_validate(buf); 1714 1.1 christos 1715 1.1 christos tt_uint_op(sum, ==, evbuffer_get_length(buf)); 1716 1.1 christos 1717 1.1 christos { 1718 1.1 christos size_t a,w,u; 1719 1.1 christos a=w=u=0; 1720 1.1 christos evbuffer_get_waste(buf, &a, &w, &u); 1721 1.1 christos if (0) 1722 1.1 christos printf("Allocated: %u.\nWasted: %u.\nUsed: %u.", 1723 1.1 christos (unsigned)a, (unsigned)w, (unsigned)u); 1724 1.1 christos tt_assert( ((double)w)/a < .125); 1725 1.1 christos } 1726 1.1 christos end: 1727 1.1 christos evbuffer_free(buf); 1728 1.1 christos 1729 1.1 christos } 1730 1.1 christos 1731 1.1 christos static void 1732 1.1 christos test_evbuffer_find(void *ptr) 1733 1.1 christos { 1734 1.7 christos unsigned char* p; 1735 1.1 christos const char* test1 = "1234567890\r\n"; 1736 1.1 christos const char* test2 = "1234567890\r"; 1737 1.1 christos #define EVBUFFER_INITIAL_LENGTH 256 1738 1.1 christos char test3[EVBUFFER_INITIAL_LENGTH]; 1739 1.1 christos unsigned int i; 1740 1.1 christos struct evbuffer * buf = evbuffer_new(); 1741 1.1 christos 1742 1.1 christos tt_assert(buf); 1743 1.1 christos 1744 1.1 christos /* make sure evbuffer_find doesn't match past the end of the buffer */ 1745 1.7 christos evbuffer_add(buf, (unsigned char*)test1, strlen(test1)); 1746 1.1 christos evbuffer_validate(buf); 1747 1.1 christos evbuffer_drain(buf, strlen(test1)); 1748 1.1 christos evbuffer_validate(buf); 1749 1.7 christos evbuffer_add(buf, (unsigned char*)test2, strlen(test2)); 1750 1.1 christos evbuffer_validate(buf); 1751 1.7 christos p = evbuffer_find(buf, (unsigned char*)"\r\n", 2); 1752 1.1 christos tt_want(p == NULL); 1753 1.1 christos 1754 1.1 christos /* 1755 1.1 christos * drain the buffer and do another find; in r309 this would 1756 1.1 christos * read past the allocated buffer causing a valgrind error. 1757 1.1 christos */ 1758 1.1 christos evbuffer_drain(buf, strlen(test2)); 1759 1.1 christos evbuffer_validate(buf); 1760 1.1 christos for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i) 1761 1.1 christos test3[i] = 'a'; 1762 1.1 christos test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x'; 1763 1.7 christos evbuffer_add(buf, (unsigned char *)test3, EVBUFFER_INITIAL_LENGTH); 1764 1.1 christos evbuffer_validate(buf); 1765 1.7 christos p = evbuffer_find(buf, (unsigned char *)"xy", 2); 1766 1.1 christos tt_want(p == NULL); 1767 1.1 christos 1768 1.1 christos /* simple test for match at end of allocated buffer */ 1769 1.7 christos p = evbuffer_find(buf, (unsigned char *)"ax", 2); 1770 1.1 christos tt_assert(p != NULL); 1771 1.1 christos tt_want(strncmp((char*)p, "ax", 2) == 0); 1772 1.1 christos 1773 1.1 christos end: 1774 1.1 christos if (buf) 1775 1.1 christos evbuffer_free(buf); 1776 1.1 christos } 1777 1.1 christos 1778 1.1 christos static void 1779 1.1 christos test_evbuffer_ptr_set(void *ptr) 1780 1.1 christos { 1781 1.1 christos struct evbuffer *buf = evbuffer_new(); 1782 1.1 christos struct evbuffer_ptr pos; 1783 1.1 christos struct evbuffer_iovec v[1]; 1784 1.1 christos 1785 1.1 christos tt_assert(buf); 1786 1.1 christos 1787 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 0); 1788 1.1 christos 1789 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1790 1.1 christos tt_assert(pos.pos == 0); 1791 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1); 1792 1.1 christos tt_assert(pos.pos == -1); 1793 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1); 1794 1.1 christos tt_assert(pos.pos == -1); 1795 1.1 christos 1796 1.1 christos /* create some chains */ 1797 1.1 christos evbuffer_reserve_space(buf, 5000, v, 1); 1798 1.1 christos v[0].iov_len = 5000; 1799 1.1 christos memset(v[0].iov_base, 1, v[0].iov_len); 1800 1.1 christos evbuffer_commit_space(buf, v, 1); 1801 1.1 christos evbuffer_validate(buf); 1802 1.1 christos 1803 1.1 christos evbuffer_reserve_space(buf, 4000, v, 1); 1804 1.1 christos v[0].iov_len = 4000; 1805 1.1 christos memset(v[0].iov_base, 2, v[0].iov_len); 1806 1.1 christos evbuffer_commit_space(buf, v, 1); 1807 1.1 christos 1808 1.1 christos evbuffer_reserve_space(buf, 3000, v, 1); 1809 1.1 christos v[0].iov_len = 3000; 1810 1.1 christos memset(v[0].iov_base, 3, v[0].iov_len); 1811 1.1 christos evbuffer_commit_space(buf, v, 1); 1812 1.1 christos evbuffer_validate(buf); 1813 1.1 christos 1814 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, 12000); 1815 1.1 christos 1816 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1); 1817 1.1 christos tt_assert(pos.pos == -1); 1818 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1819 1.1 christos tt_assert(pos.pos == 0); 1820 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1); 1821 1.1 christos 1822 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1823 1.1 christos tt_assert(pos.pos == 0); 1824 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0); 1825 1.1 christos tt_assert(pos.pos == 10000); 1826 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); 1827 1.1 christos tt_assert(pos.pos == 11000); 1828 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); 1829 1.1 christos tt_assert(pos.pos == 12000); 1830 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1); 1831 1.1 christos tt_assert(pos.pos == -1); 1832 1.1 christos 1833 1.1 christos end: 1834 1.1 christos if (buf) 1835 1.1 christos evbuffer_free(buf); 1836 1.1 christos } 1837 1.1 christos 1838 1.1 christos static void 1839 1.1 christos test_evbuffer_search(void *ptr) 1840 1.1 christos { 1841 1.1 christos struct evbuffer *buf = evbuffer_new(); 1842 1.1 christos struct evbuffer *tmp = evbuffer_new(); 1843 1.1 christos struct evbuffer_ptr pos, end; 1844 1.1 christos 1845 1.1 christos tt_assert(buf); 1846 1.1 christos tt_assert(tmp); 1847 1.1 christos 1848 1.1 christos pos = evbuffer_search(buf, "x", 1, NULL); 1849 1.1 christos tt_int_op(pos.pos, ==, -1); 1850 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1851 1.1 christos pos = evbuffer_search(buf, "x", 1, &pos); 1852 1.1 christos tt_int_op(pos.pos, ==, -1); 1853 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1854 1.1 christos pos = evbuffer_search_range(buf, "x", 1, &pos, &pos); 1855 1.1 christos tt_int_op(pos.pos, ==, -1); 1856 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); 1857 1.1 christos pos = evbuffer_search_range(buf, "x", 1, &pos, NULL); 1858 1.1 christos tt_int_op(pos.pos, ==, -1); 1859 1.1 christos 1860 1.1 christos /* set up our chains */ 1861 1.1 christos evbuffer_add_printf(tmp, "hello"); /* 5 chars */ 1862 1.1 christos evbuffer_add_buffer(buf, tmp); 1863 1.1 christos evbuffer_add_printf(tmp, "foo"); /* 3 chars */ 1864 1.1 christos evbuffer_add_buffer(buf, tmp); 1865 1.1 christos evbuffer_add_printf(tmp, "cat"); /* 3 chars */ 1866 1.1 christos evbuffer_add_buffer(buf, tmp); 1867 1.1 christos evbuffer_add_printf(tmp, "attack"); 1868 1.1 christos evbuffer_add_buffer(buf, tmp); 1869 1.1 christos 1870 1.1 christos pos = evbuffer_search(buf, "attack", 6, NULL); 1871 1.1 christos tt_int_op(pos.pos, ==, 11); 1872 1.1 christos pos = evbuffer_search(buf, "attacker", 8, NULL); 1873 1.1 christos tt_int_op(pos.pos, ==, -1); 1874 1.1 christos 1875 1.1 christos /* test continuing search */ 1876 1.1 christos pos = evbuffer_search(buf, "oc", 2, NULL); 1877 1.1 christos tt_int_op(pos.pos, ==, 7); 1878 1.1 christos pos = evbuffer_search(buf, "cat", 3, &pos); 1879 1.1 christos tt_int_op(pos.pos, ==, 8); 1880 1.1 christos pos = evbuffer_search(buf, "tacking", 7, &pos); 1881 1.1 christos tt_int_op(pos.pos, ==, -1); 1882 1.1 christos 1883 1.1 christos evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET); 1884 1.1 christos pos = evbuffer_search(buf, "foo", 3, &pos); 1885 1.1 christos tt_int_op(pos.pos, ==, 5); 1886 1.1 christos 1887 1.1 christos evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD); 1888 1.1 christos pos = evbuffer_search(buf, "tat", 3, &pos); 1889 1.1 christos tt_int_op(pos.pos, ==, 10); 1890 1.1 christos 1891 1.1 christos /* test bounded search. */ 1892 1.1 christos /* Set "end" to the first t in "attack". */ 1893 1.1 christos evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET); 1894 1.1 christos pos = evbuffer_search_range(buf, "foo", 3, NULL, &end); 1895 1.1 christos tt_int_op(pos.pos, ==, 5); 1896 1.1 christos pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end); 1897 1.1 christos tt_int_op(pos.pos, ==, 5); 1898 1.1 christos pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end); 1899 1.1 christos tt_int_op(pos.pos, ==, -1); 1900 1.1 christos pos = evbuffer_search_range(buf, "ack", 3, NULL, &end); 1901 1.1 christos tt_int_op(pos.pos, ==, -1); 1902 1.1 christos 1903 1.1 christos /* Set "end" after the last byte in the buffer. */ 1904 1.1 christos tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0); 1905 1.1 christos 1906 1.1 christos pos = evbuffer_search_range(buf, "attack", 6, NULL, &end); 1907 1.1 christos tt_int_op(pos.pos, ==, 11); 1908 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0); 1909 1.1 christos pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); 1910 1.1 christos tt_int_op(pos.pos, ==, 11); 1911 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); 1912 1.1 christos pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); 1913 1.1 christos tt_int_op(pos.pos, ==, -1); 1914 1.1 christos tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); 1915 1.1 christos pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL); 1916 1.1 christos tt_int_op(pos.pos, ==, -1); 1917 1.1 christos 1918 1.1 christos end: 1919 1.1 christos if (buf) 1920 1.1 christos evbuffer_free(buf); 1921 1.1 christos if (tmp) 1922 1.1 christos evbuffer_free(tmp); 1923 1.1 christos } 1924 1.1 christos 1925 1.1 christos static void 1926 1.1 christos log_change_callback(struct evbuffer *buffer, 1927 1.1 christos const struct evbuffer_cb_info *cbinfo, 1928 1.1 christos void *arg) 1929 1.1 christos { 1930 1.1 christos 1931 1.1 christos size_t old_len = cbinfo->orig_size; 1932 1.1 christos size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted; 1933 1.1 christos struct evbuffer *out = arg; 1934 1.1 christos evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len, 1935 1.1 christos (unsigned long)new_len); 1936 1.1 christos } 1937 1.1 christos static void 1938 1.1 christos self_draining_callback(struct evbuffer *evbuffer, size_t old_len, 1939 1.1 christos size_t new_len, void *arg) 1940 1.1 christos { 1941 1.1 christos if (new_len > old_len) 1942 1.1 christos evbuffer_drain(evbuffer, new_len); 1943 1.1 christos } 1944 1.1 christos 1945 1.1 christos static void 1946 1.1 christos test_evbuffer_callbacks(void *ptr) 1947 1.1 christos { 1948 1.1 christos struct evbuffer *buf = evbuffer_new(); 1949 1.1 christos struct evbuffer *buf_out1 = evbuffer_new(); 1950 1.1 christos struct evbuffer *buf_out2 = evbuffer_new(); 1951 1.1 christos struct evbuffer_cb_entry *cb1, *cb2; 1952 1.1 christos 1953 1.1 christos tt_assert(buf); 1954 1.1 christos tt_assert(buf_out1); 1955 1.1 christos tt_assert(buf_out2); 1956 1.1 christos 1957 1.1 christos cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); 1958 1.1 christos cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); 1959 1.1 christos 1960 1.1 christos /* Let's run through adding and deleting some stuff from the buffer 1961 1.1 christos * and turning the callbacks on and off and removing them. The callback 1962 1.1 christos * adds a summary of length changes to buf_out1/buf_out2 when called. */ 1963 1.1 christos /* size: 0-> 36. */ 1964 1.1 christos evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2); 1965 1.1 christos evbuffer_validate(buf); 1966 1.1 christos evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED); 1967 1.1 christos evbuffer_drain(buf, 10); /*36->26*/ 1968 1.1 christos evbuffer_validate(buf); 1969 1.1 christos evbuffer_prepend(buf, "Hello", 5);/*26->31*/ 1970 1.1 christos evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED); 1971 1.1 christos evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/ 1972 1.1 christos evbuffer_remove_cb_entry(buf, cb1); 1973 1.1 christos evbuffer_validate(buf); 1974 1.1 christos evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/; 1975 1.1 christos tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL)); 1976 1.1 christos evbuffer_add(buf, "X", 1); /* 0->1 */ 1977 1.1 christos tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2)); 1978 1.1 christos evbuffer_validate(buf); 1979 1.1 christos 1980 1.3 christos tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==, 1981 1.1 christos "0->36; 36->26; 26->31; 31->38; "); 1982 1.3 christos tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==, 1983 1.1 christos "0->36; 31->38; 38->0; 0->1; "); 1984 1.1 christos evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1)); 1985 1.1 christos evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2)); 1986 1.1 christos /* Let's test the obsolete buffer_setcb function too. */ 1987 1.1 christos cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); 1988 1.1 christos tt_assert(cb1 != NULL); 1989 1.1 christos cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); 1990 1.1 christos tt_assert(cb2 != NULL); 1991 1.7 christos tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, 0); 1992 1.1 christos evbuffer_add_printf(buf, "This should get drained right away."); 1993 1.1 christos tt_uint_op(evbuffer_get_length(buf), ==, 0); 1994 1.1 christos tt_uint_op(evbuffer_get_length(buf_out1), ==, 0); 1995 1.1 christos tt_uint_op(evbuffer_get_length(buf_out2), ==, 0); 1996 1.7 christos tt_int_op(evbuffer_setcb(buf, NULL, NULL), ==, 0); 1997 1.1 christos evbuffer_add_printf(buf, "This will not."); 1998 1.3 christos tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not."); 1999 1.1 christos evbuffer_validate(buf); 2000 1.1 christos evbuffer_drain(buf, evbuffer_get_length(buf)); 2001 1.1 christos evbuffer_validate(buf); 2002 1.1 christos #if 0 2003 1.1 christos /* Now let's try a suspended callback. */ 2004 1.1 christos cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); 2005 1.1 christos cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); 2006 1.1 christos evbuffer_cb_suspend(buf,cb2); 2007 1.1 christos evbuffer_prepend(buf,"Hello world",11); /*0->11*/ 2008 1.1 christos evbuffer_validate(buf); 2009 1.1 christos evbuffer_cb_suspend(buf,cb1); 2010 1.1 christos evbuffer_add(buf,"more",4); /* 11->15 */ 2011 1.1 christos evbuffer_cb_unsuspend(buf,cb2); 2012 1.1 christos evbuffer_drain(buf, 4); /* 15->11 */ 2013 1.1 christos evbuffer_cb_unsuspend(buf,cb1); 2014 1.1 christos evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */ 2015 1.1 christos 2016 1.1 christos tt_str_op(evbuffer_pullup(buf_out1, -1), ==, 2017 1.1 christos "0->11; 11->11; 11->0; "); 2018 1.1 christos tt_str_op(evbuffer_pullup(buf_out2, -1), ==, 2019 1.1 christos "0->15; 15->11; 11->0; "); 2020 1.1 christos #endif 2021 1.1 christos 2022 1.7 christos /* the next call to readline should fail */ 2023 1.7 christos #ifndef EVENT__DISABLE_MM_REPLACEMENT 2024 1.7 christos event_set_mem_functions(failing_malloc, realloc, free); 2025 1.7 christos tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, -1); 2026 1.7 christos evbuffer_validate(buf); 2027 1.7 christos event_set_mem_functions(malloc, realloc, free); 2028 1.7 christos #endif 2029 1.7 christos 2030 1.1 christos end: 2031 1.1 christos if (buf) 2032 1.1 christos evbuffer_free(buf); 2033 1.1 christos if (buf_out1) 2034 1.1 christos evbuffer_free(buf_out1); 2035 1.1 christos if (buf_out2) 2036 1.1 christos evbuffer_free(buf_out2); 2037 1.1 christos } 2038 1.1 christos 2039 1.1 christos static int ref_done_cb_called_count = 0; 2040 1.1 christos static void *ref_done_cb_called_with = NULL; 2041 1.1 christos static const void *ref_done_cb_called_with_data = NULL; 2042 1.1 christos static size_t ref_done_cb_called_with_len = 0; 2043 1.1 christos static void ref_done_cb(const void *data, size_t len, void *info) 2044 1.1 christos { 2045 1.1 christos ++ref_done_cb_called_count; 2046 1.1 christos ref_done_cb_called_with = info; 2047 1.1 christos ref_done_cb_called_with_data = data; 2048 1.1 christos ref_done_cb_called_with_len = len; 2049 1.1 christos } 2050 1.1 christos 2051 1.1 christos static void 2052 1.1 christos test_evbuffer_add_reference(void *ptr) 2053 1.1 christos { 2054 1.1 christos const char chunk1[] = "If you have found the answer to such a problem"; 2055 1.1 christos const char chunk2[] = "you ought to write it up for publication"; 2056 1.1 christos /* -- Knuth's "Notes on the Exercises" from TAOCP */ 2057 1.1 christos char tmp[16]; 2058 1.1 christos size_t len1 = strlen(chunk1), len2=strlen(chunk2); 2059 1.1 christos 2060 1.1 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 2061 1.1 christos 2062 1.1 christos buf1 = evbuffer_new(); 2063 1.1 christos tt_assert(buf1); 2064 1.1 christos 2065 1.1 christos evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111); 2066 1.1 christos evbuffer_add(buf1, ", ", 2); 2067 1.1 christos evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222); 2068 1.1 christos tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); 2069 1.1 christos 2070 1.1 christos /* Make sure we can drain a little from a reference. */ 2071 1.1 christos tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); 2072 1.1 christos tt_int_op(memcmp(tmp, "If you", 6), ==, 0); 2073 1.1 christos tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); 2074 1.1 christos tt_int_op(memcmp(tmp, " have", 5), ==, 0); 2075 1.1 christos 2076 1.1 christos /* Make sure that prepending does not meddle with immutable data */ 2077 1.1 christos tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); 2078 1.1 christos tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); 2079 1.1 christos evbuffer_validate(buf1); 2080 1.1 christos 2081 1.1 christos /* Make sure that when the chunk is over, the callback is invoked. */ 2082 1.1 christos evbuffer_drain(buf1, 7); /* Remove prepended stuff. */ 2083 1.1 christos evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */ 2084 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 0); 2085 1.1 christos evbuffer_remove(buf1, tmp, 1); 2086 1.1 christos tt_int_op(tmp[0], ==, 'm'); 2087 1.1 christos tt_assert(ref_done_cb_called_with == (void*)111); 2088 1.1 christos tt_assert(ref_done_cb_called_with_data == chunk1); 2089 1.1 christos tt_assert(ref_done_cb_called_with_len == len1); 2090 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 1); 2091 1.1 christos evbuffer_validate(buf1); 2092 1.1 christos 2093 1.1 christos /* Drain some of the remaining chunk, then add it to another buffer */ 2094 1.1 christos evbuffer_drain(buf1, 6); /* Remove the ", you ". */ 2095 1.1 christos buf2 = evbuffer_new(); 2096 1.1 christos tt_assert(buf2); 2097 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 1); 2098 1.1 christos evbuffer_add(buf2, "I ", 2); 2099 1.1 christos 2100 1.1 christos evbuffer_add_buffer(buf2, buf1); 2101 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 1); 2102 1.1 christos evbuffer_remove(buf2, tmp, 16); 2103 1.1 christos tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0); 2104 1.1 christos evbuffer_drain(buf2, evbuffer_get_length(buf2)); 2105 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 2); 2106 1.1 christos tt_assert(ref_done_cb_called_with == (void*)222); 2107 1.1 christos evbuffer_validate(buf2); 2108 1.1 christos 2109 1.1 christos /* Now add more stuff to buf1 and make sure that it gets removed on 2110 1.1 christos * free. */ 2111 1.1 christos evbuffer_add(buf1, "You shake and shake the ", 24); 2112 1.1 christos evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb, 2113 1.1 christos (void*)3333); 2114 1.3 christos evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35); 2115 1.1 christos evbuffer_free(buf1); 2116 1.1 christos buf1 = NULL; 2117 1.1 christos tt_int_op(ref_done_cb_called_count, ==, 3); 2118 1.1 christos tt_assert(ref_done_cb_called_with == (void*)3333); 2119 1.1 christos 2120 1.1 christos end: 2121 1.1 christos if (buf1) 2122 1.1 christos evbuffer_free(buf1); 2123 1.1 christos if (buf2) 2124 1.1 christos evbuffer_free(buf2); 2125 1.1 christos } 2126 1.1 christos 2127 1.1 christos static void 2128 1.1 christos test_evbuffer_multicast(void *ptr) 2129 1.1 christos { 2130 1.1 christos const char chunk1[] = "If you have found the answer to such a problem"; 2131 1.1 christos const char chunk2[] = "you ought to write it up for publication"; 2132 1.1 christos /* -- Knuth's "Notes on the Exercises" from TAOCP */ 2133 1.1 christos char tmp[16]; 2134 1.1 christos size_t len1 = strlen(chunk1), len2=strlen(chunk2); 2135 1.1 christos 2136 1.1 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 2137 1.1 christos 2138 1.1 christos buf1 = evbuffer_new(); 2139 1.1 christos tt_assert(buf1); 2140 1.1 christos 2141 1.1 christos evbuffer_add(buf1, chunk1, len1); 2142 1.1 christos evbuffer_add(buf1, ", ", 2); 2143 1.1 christos evbuffer_add(buf1, chunk2, len2); 2144 1.1 christos tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); 2145 1.1 christos 2146 1.1 christos buf2 = evbuffer_new(); 2147 1.1 christos tt_assert(buf2); 2148 1.1 christos 2149 1.1 christos tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); 2150 1.1 christos /* nested references are not allowed */ 2151 1.1 christos tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1); 2152 1.1 christos tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1); 2153 1.1 christos 2154 1.1 christos /* both buffers contain the same amount of data */ 2155 1.1 christos tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1)); 2156 1.1 christos 2157 1.1 christos /* Make sure we can drain a little from the first buffer. */ 2158 1.1 christos tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); 2159 1.1 christos tt_int_op(memcmp(tmp, "If you", 6), ==, 0); 2160 1.1 christos tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); 2161 1.1 christos tt_int_op(memcmp(tmp, " have", 5), ==, 0); 2162 1.1 christos 2163 1.1 christos /* Make sure that prepending does not meddle with immutable data */ 2164 1.1 christos tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); 2165 1.1 christos tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); 2166 1.1 christos evbuffer_validate(buf1); 2167 1.1 christos 2168 1.1 christos /* Make sure we can drain a little from the second buffer. */ 2169 1.1 christos tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); 2170 1.1 christos tt_int_op(memcmp(tmp, "If you", 6), ==, 0); 2171 1.1 christos tt_int_op(evbuffer_remove(buf2, tmp, 5), ==, 5); 2172 1.1 christos tt_int_op(memcmp(tmp, " have", 5), ==, 0); 2173 1.1 christos 2174 1.1 christos /* Make sure that prepending does not meddle with immutable data */ 2175 1.1 christos tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0); 2176 1.1 christos tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); 2177 1.1 christos evbuffer_validate(buf2); 2178 1.1 christos 2179 1.1 christos /* Make sure the data can be read from the second buffer when the first is freed */ 2180 1.1 christos evbuffer_free(buf1); 2181 1.1 christos buf1 = NULL; 2182 1.1 christos 2183 1.1 christos tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); 2184 1.1 christos tt_int_op(memcmp(tmp, "I have", 6), ==, 0); 2185 1.1 christos 2186 1.1 christos tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); 2187 1.1 christos tt_int_op(memcmp(tmp, " foun", 6), ==, 0); 2188 1.1 christos 2189 1.1 christos end: 2190 1.1 christos if (buf1) 2191 1.1 christos evbuffer_free(buf1); 2192 1.1 christos if (buf2) 2193 1.1 christos evbuffer_free(buf2); 2194 1.1 christos } 2195 1.1 christos 2196 1.1 christos static void 2197 1.1 christos test_evbuffer_multicast_drain(void *ptr) 2198 1.1 christos { 2199 1.1 christos const char chunk1[] = "If you have found the answer to such a problem"; 2200 1.1 christos const char chunk2[] = "you ought to write it up for publication"; 2201 1.1 christos /* -- Knuth's "Notes on the Exercises" from TAOCP */ 2202 1.1 christos size_t len1 = strlen(chunk1), len2=strlen(chunk2); 2203 1.1 christos 2204 1.1 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 2205 1.1 christos 2206 1.1 christos buf1 = evbuffer_new(); 2207 1.1 christos tt_assert(buf1); 2208 1.1 christos 2209 1.1 christos evbuffer_add(buf1, chunk1, len1); 2210 1.1 christos evbuffer_add(buf1, ", ", 2); 2211 1.1 christos evbuffer_add(buf1, chunk2, len2); 2212 1.1 christos tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); 2213 1.1 christos 2214 1.1 christos buf2 = evbuffer_new(); 2215 1.1 christos tt_assert(buf2); 2216 1.1 christos 2217 1.1 christos tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); 2218 1.1 christos tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); 2219 1.1 christos tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0); 2220 1.1 christos tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); 2221 1.1 christos tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0); 2222 1.1 christos evbuffer_validate(buf1); 2223 1.1 christos evbuffer_validate(buf2); 2224 1.1 christos 2225 1.1 christos end: 2226 1.1 christos if (buf1) 2227 1.1 christos evbuffer_free(buf1); 2228 1.1 christos if (buf2) 2229 1.1 christos evbuffer_free(buf2); 2230 1.1 christos } 2231 1.1 christos 2232 1.7 christos static void 2233 1.7 christos check_prepend(struct evbuffer *buffer, 2234 1.7 christos const struct evbuffer_cb_info *cbinfo, 2235 1.7 christos void *arg) 2236 1.7 christos { 2237 1.7 christos tt_int_op(cbinfo->orig_size, ==, 3); 2238 1.7 christos tt_int_op(cbinfo->n_added, ==, 8096); 2239 1.7 christos tt_int_op(cbinfo->n_deleted, ==, 0); 2240 1.7 christos end: 2241 1.7 christos ; 2242 1.7 christos } 2243 1.1 christos /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */ 2244 1.1 christos static void 2245 1.1 christos test_evbuffer_prepend(void *ptr) 2246 1.1 christos { 2247 1.1 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 2248 1.7 christos char tmp[128], *buffer = malloc(8096); 2249 1.1 christos int n; 2250 1.1 christos 2251 1.1 christos buf1 = evbuffer_new(); 2252 1.1 christos tt_assert(buf1); 2253 1.1 christos 2254 1.1 christos /* Case 0: The evbuffer is entirely empty. */ 2255 1.1 christos evbuffer_prepend(buf1, "This string has 29 characters", 29); 2256 1.1 christos evbuffer_validate(buf1); 2257 1.1 christos 2258 1.1 christos /* Case 1: Prepend goes entirely in new chunk. */ 2259 1.1 christos evbuffer_prepend(buf1, "Short.", 6); 2260 1.1 christos evbuffer_validate(buf1); 2261 1.1 christos 2262 1.1 christos /* Case 2: prepend goes entirely in first chunk. */ 2263 1.1 christos evbuffer_drain(buf1, 6+11); 2264 1.1 christos evbuffer_prepend(buf1, "it", 2); 2265 1.1 christos evbuffer_validate(buf1); 2266 1.1 christos tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign, 2267 1.1 christos "it has", 6)); 2268 1.1 christos 2269 1.1 christos /* Case 3: prepend is split over multiple chunks. */ 2270 1.1 christos evbuffer_prepend(buf1, "It is no longer true to say ", 28); 2271 1.1 christos evbuffer_validate(buf1); 2272 1.1 christos n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1); 2273 1.2 christos tt_int_op(n, >=, 0); 2274 1.1 christos tmp[n]='\0'; 2275 1.1 christos tt_str_op(tmp,==,"It is no longer true to say it has 29 characters"); 2276 1.1 christos 2277 1.1 christos buf2 = evbuffer_new(); 2278 1.1 christos tt_assert(buf2); 2279 1.1 christos 2280 1.1 christos /* Case 4: prepend a buffer to an empty buffer. */ 2281 1.1 christos n = 999; 2282 1.1 christos evbuffer_add_printf(buf1, "Here is string %d. ", n++); 2283 1.1 christos evbuffer_prepend_buffer(buf2, buf1); 2284 1.1 christos evbuffer_validate(buf2); 2285 1.1 christos 2286 1.1 christos /* Case 5: prepend a buffer to a nonempty buffer. */ 2287 1.1 christos evbuffer_add_printf(buf1, "Here is string %d. ", n++); 2288 1.1 christos evbuffer_prepend_buffer(buf2, buf1); 2289 1.1 christos evbuffer_validate(buf2); 2290 1.1 christos evbuffer_validate(buf1); 2291 1.1 christos n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1); 2292 1.2 christos tt_int_op(n, >=, 0); 2293 1.1 christos tmp[n]='\0'; 2294 1.1 christos tt_str_op(tmp,==,"Here is string 1000. Here is string 999. "); 2295 1.1 christos 2296 1.7 christos /* Case 5: evbuffer_prepend() will need a new buffer, with callbacks */ 2297 1.7 christos memset(buffer, 'A', 8096); 2298 1.7 christos evbuffer_free(buf2); 2299 1.7 christos buf2 = evbuffer_new(); 2300 1.7 christos tt_assert(buf2); 2301 1.7 christos evbuffer_prepend(buf2, "foo", 3); 2302 1.7 christos evbuffer_add_cb(buf2, check_prepend, NULL); 2303 1.7 christos evbuffer_prepend(buf2, buffer, 8096); 2304 1.7 christos evbuffer_remove_cb(buf2, check_prepend, NULL); 2305 1.7 christos evbuffer_validate(buf2); 2306 1.7 christos tt_nstr_op(8096,(char *)evbuffer_pullup(buf2, 8096),==,buffer); 2307 1.7 christos evbuffer_drain(buf2, 8096); 2308 1.7 christos tt_nstr_op(3,(char *)evbuffer_pullup(buf2, 3),==,"foo"); 2309 1.7 christos evbuffer_drain(buf2, 3); 2310 1.7 christos 2311 1.1 christos end: 2312 1.7 christos free(buffer); 2313 1.1 christos if (buf1) 2314 1.1 christos evbuffer_free(buf1); 2315 1.1 christos if (buf2) 2316 1.1 christos evbuffer_free(buf2); 2317 1.1 christos 2318 1.1 christos } 2319 1.1 christos 2320 1.1 christos static void 2321 1.7 christos test_evbuffer_empty_reference_prepend(void *ptr) 2322 1.7 christos { 2323 1.7 christos struct evbuffer *buf = NULL; 2324 1.7 christos 2325 1.7 christos buf = evbuffer_new(); 2326 1.7 christos tt_assert(buf); 2327 1.7 christos 2328 1.7 christos /** empty chain could leave invalid last_with_datap */ 2329 1.7 christos evbuffer_add_reference(buf, "", 0, NULL, NULL); 2330 1.7 christos evbuffer_validate(buf); 2331 1.7 christos evbuffer_prepend(buf, "foo", 3); 2332 1.7 christos 2333 1.7 christos evbuffer_validate(buf); 2334 1.7 christos tt_assert(!strncmp((char *)evbuffer_pullup(buf, -1), "foo", 3)); 2335 1.7 christos evbuffer_validate(buf); 2336 1.7 christos 2337 1.7 christos end: 2338 1.7 christos if (buf) 2339 1.7 christos evbuffer_free(buf); 2340 1.7 christos } 2341 1.7 christos static void 2342 1.7 christos test_evbuffer_empty_reference_prepend_buffer(void *ptr) 2343 1.7 christos { 2344 1.7 christos struct evbuffer *buf1 = NULL, *buf2 = NULL; 2345 1.7 christos 2346 1.7 christos buf1 = evbuffer_new(); 2347 1.7 christos tt_assert(buf1); 2348 1.7 christos buf2 = evbuffer_new(); 2349 1.7 christos tt_assert(buf2); 2350 1.7 christos 2351 1.7 christos /** empty chain could leave invalid last_with_datap */ 2352 1.7 christos evbuffer_add_reference(buf1, "", 0, NULL, NULL); 2353 1.7 christos evbuffer_validate(buf1); 2354 1.7 christos evbuffer_add(buf2, "foo", 3); 2355 1.7 christos evbuffer_validate(buf2); 2356 1.7 christos evbuffer_prepend_buffer(buf2, buf1); 2357 1.7 christos evbuffer_validate(buf2); 2358 1.7 christos 2359 1.7 christos tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), "foo", 3)); 2360 1.7 christos evbuffer_validate(buf2); 2361 1.7 christos 2362 1.7 christos tt_assert(evbuffer_pullup(buf1, -1) == NULL); 2363 1.7 christos evbuffer_validate(buf2); 2364 1.7 christos 2365 1.7 christos end: 2366 1.7 christos if (buf1) 2367 1.7 christos evbuffer_free(buf1); 2368 1.7 christos if (buf2) 2369 1.7 christos evbuffer_free(buf2); 2370 1.7 christos } 2371 1.7 christos 2372 1.7 christos static void 2373 1.3 christos test_evbuffer_peek_first_gt(void *info) 2374 1.3 christos { 2375 1.3 christos struct evbuffer *buf = NULL, *tmp_buf = NULL; 2376 1.3 christos struct evbuffer_ptr ptr; 2377 1.3 christos struct evbuffer_iovec v[2]; 2378 1.3 christos 2379 1.3 christos buf = evbuffer_new(); 2380 1.3 christos tmp_buf = evbuffer_new(); 2381 1.3 christos evbuffer_add_printf(tmp_buf, "Contents of chunk 100\n"); 2382 1.3 christos evbuffer_add_buffer(buf, tmp_buf); 2383 1.3 christos evbuffer_add_printf(tmp_buf, "Contents of chunk 1\n"); 2384 1.3 christos evbuffer_add_buffer(buf, tmp_buf); 2385 1.3 christos 2386 1.3 christos evbuffer_ptr_set(buf, &ptr, 0, EVBUFFER_PTR_SET); 2387 1.3 christos 2388 1.3 christos /** The only case that matters*/ 2389 1.3 christos tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); 2390 1.3 christos /** Just in case */ 2391 1.3 christos tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); 2392 1.3 christos 2393 1.3 christos evbuffer_ptr_set(buf, &ptr, 20, EVBUFFER_PTR_ADD); 2394 1.3 christos tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); 2395 1.3 christos tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); 2396 1.3 christos tt_int_op(evbuffer_peek(buf, 2, &ptr, NULL, 0), ==, 1); 2397 1.3 christos tt_int_op(evbuffer_peek(buf, 2, &ptr, v, 2), ==, 1); 2398 1.3 christos tt_int_op(evbuffer_peek(buf, 3, &ptr, NULL, 0), ==, 2); 2399 1.3 christos tt_int_op(evbuffer_peek(buf, 3, &ptr, v, 2), ==, 2); 2400 1.3 christos 2401 1.3 christos end: 2402 1.3 christos if (buf) 2403 1.3 christos evbuffer_free(buf); 2404 1.3 christos if (tmp_buf) 2405 1.3 christos evbuffer_free(tmp_buf); 2406 1.3 christos } 2407 1.3 christos 2408 1.3 christos static void 2409 1.1 christos test_evbuffer_peek(void *info) 2410 1.1 christos { 2411 1.1 christos struct evbuffer *buf = NULL, *tmp_buf = NULL; 2412 1.1 christos int i; 2413 1.1 christos struct evbuffer_iovec v[20]; 2414 1.1 christos struct evbuffer_ptr ptr; 2415 1.1 christos 2416 1.1 christos #define tt_iov_eq(v, s) \ 2417 1.1 christos tt_int_op((v)->iov_len, ==, strlen(s)); \ 2418 1.1 christos tt_assert(!memcmp((v)->iov_base, (s), strlen(s))) 2419 1.1 christos 2420 1.1 christos /* Let's make a very fragmented buffer. */ 2421 1.1 christos buf = evbuffer_new(); 2422 1.1 christos tmp_buf = evbuffer_new(); 2423 1.1 christos for (i = 0; i < 16; ++i) { 2424 1.1 christos evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i); 2425 1.1 christos evbuffer_add_buffer(buf, tmp_buf); 2426 1.1 christos } 2427 1.1 christos 2428 1.1 christos /* How many chunks do we need for everything? */ 2429 1.1 christos i = evbuffer_peek(buf, -1, NULL, NULL, 0); 2430 1.1 christos tt_int_op(i, ==, 16); 2431 1.1 christos 2432 1.1 christos /* Simple peek: get everything. */ 2433 1.1 christos i = evbuffer_peek(buf, -1, NULL, v, 20); 2434 1.1 christos tt_int_op(i, ==, 16); /* we used only 16 chunks. */ 2435 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [0]\n"); 2436 1.1 christos tt_iov_eq(&v[3], "Contents of chunk [3]\n"); 2437 1.1 christos tt_iov_eq(&v[12], "Contents of chunk [12]\n"); 2438 1.1 christos tt_iov_eq(&v[15], "Contents of chunk [15]\n"); 2439 1.1 christos 2440 1.1 christos /* Just get one chunk worth. */ 2441 1.1 christos memset(v, 0, sizeof(v)); 2442 1.1 christos i = evbuffer_peek(buf, -1, NULL, v, 1); 2443 1.1 christos tt_int_op(i, ==, 1); 2444 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [0]\n"); 2445 1.1 christos tt_assert(v[1].iov_base == NULL); 2446 1.1 christos 2447 1.1 christos /* Suppose we want at least the first 40 bytes. */ 2448 1.1 christos memset(v, 0, sizeof(v)); 2449 1.1 christos i = evbuffer_peek(buf, 40, NULL, v, 16); 2450 1.1 christos tt_int_op(i, ==, 2); 2451 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [0]\n"); 2452 1.1 christos tt_iov_eq(&v[1], "Contents of chunk [1]\n"); 2453 1.1 christos tt_assert(v[2].iov_base == NULL); 2454 1.1 christos 2455 1.1 christos /* How many chunks do we need for 100 bytes? */ 2456 1.1 christos memset(v, 0, sizeof(v)); 2457 1.1 christos i = evbuffer_peek(buf, 100, NULL, NULL, 0); 2458 1.1 christos tt_int_op(i, ==, 5); 2459 1.1 christos tt_assert(v[0].iov_base == NULL); 2460 1.1 christos 2461 1.1 christos /* Now we ask for more bytes than we provide chunks for */ 2462 1.1 christos memset(v, 0, sizeof(v)); 2463 1.1 christos i = evbuffer_peek(buf, 60, NULL, v, 1); 2464 1.1 christos tt_int_op(i, ==, 3); 2465 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [0]\n"); 2466 1.1 christos tt_assert(v[1].iov_base == NULL); 2467 1.1 christos 2468 1.1 christos /* Now we ask for more bytes than the buffer has. */ 2469 1.1 christos memset(v, 0, sizeof(v)); 2470 1.1 christos i = evbuffer_peek(buf, 65536, NULL, v, 20); 2471 1.1 christos tt_int_op(i, ==, 16); /* we used only 16 chunks. */ 2472 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [0]\n"); 2473 1.1 christos tt_iov_eq(&v[3], "Contents of chunk [3]\n"); 2474 1.1 christos tt_iov_eq(&v[12], "Contents of chunk [12]\n"); 2475 1.1 christos tt_iov_eq(&v[15], "Contents of chunk [15]\n"); 2476 1.1 christos tt_assert(v[16].iov_base == NULL); 2477 1.1 christos 2478 1.1 christos /* What happens if we try an empty buffer? */ 2479 1.1 christos memset(v, 0, sizeof(v)); 2480 1.1 christos i = evbuffer_peek(tmp_buf, -1, NULL, v, 20); 2481 1.1 christos tt_int_op(i, ==, 0); 2482 1.1 christos tt_assert(v[0].iov_base == NULL); 2483 1.1 christos memset(v, 0, sizeof(v)); 2484 1.1 christos i = evbuffer_peek(tmp_buf, 50, NULL, v, 20); 2485 1.1 christos tt_int_op(i, ==, 0); 2486 1.1 christos tt_assert(v[0].iov_base == NULL); 2487 1.1 christos 2488 1.1 christos /* Okay, now time to have fun with pointers. */ 2489 1.1 christos memset(v, 0, sizeof(v)); 2490 1.1 christos evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET); 2491 1.1 christos i = evbuffer_peek(buf, 50, &ptr, v, 20); 2492 1.1 christos tt_int_op(i, ==, 3); 2493 1.1 christos tt_iov_eq(&v[0], " of chunk [1]\n"); 2494 1.1 christos tt_iov_eq(&v[1], "Contents of chunk [2]\n"); 2495 1.1 christos tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/ 2496 1.1 christos 2497 1.1 christos /* advance to the start of another chain. */ 2498 1.1 christos memset(v, 0, sizeof(v)); 2499 1.1 christos evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD); 2500 1.1 christos i = evbuffer_peek(buf, 44, &ptr, v, 20); 2501 1.1 christos tt_int_op(i, ==, 2); 2502 1.1 christos tt_iov_eq(&v[0], "Contents of chunk [2]\n"); 2503 1.1 christos tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/ 2504 1.1 christos 2505 1.1 christos /* peek at the end of the buffer */ 2506 1.1 christos memset(v, 0, sizeof(v)); 2507 1.1 christos tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); 2508 1.1 christos i = evbuffer_peek(buf, 44, &ptr, v, 20); 2509 1.1 christos tt_int_op(i, ==, 0); 2510 1.1 christos tt_assert(v[0].iov_base == NULL); 2511 1.1 christos 2512 1.1 christos end: 2513 1.1 christos if (buf) 2514 1.1 christos evbuffer_free(buf); 2515 1.1 christos if (tmp_buf) 2516 1.1 christos evbuffer_free(tmp_buf); 2517 1.1 christos } 2518 1.1 christos 2519 1.1 christos /* Check whether evbuffer freezing works right. This is called twice, 2520 1.1 christos once with the argument "start" and once with the argument "end". 2521 1.1 christos When we test "start", we freeze the start of an evbuffer and make sure 2522 1.1 christos that modifying the start of the buffer doesn't work. When we test 2523 1.1 christos "end", we freeze the end of an evbuffer and make sure that modifying 2524 1.1 christos the end of the buffer doesn't work. 2525 1.1 christos */ 2526 1.1 christos static void 2527 1.1 christos test_evbuffer_freeze(void *ptr) 2528 1.1 christos { 2529 1.7 christos struct basic_test_data *testdata = ptr; 2530 1.7 christos evutil_socket_t *pair = testdata->pair; 2531 1.7 christos struct evbuffer *buf = NULL, *buf_two = NULL, *tmp_buf = NULL; 2532 1.1 christos const char string[] = /* Year's End, Richard Wilbur */ 2533 1.1 christos "I've known the wind by water banks to shake\n" 2534 1.1 christos "The late leaves down, which frozen where they fell\n" 2535 1.1 christos "And held in ice as dancers in a spell\n" 2536 1.1 christos "Fluttered all winter long into a lake..."; 2537 1.7 christos const int start = !strcmp(testdata->setup_data, "start"); 2538 1.7 christos const char tmpfilecontent[] = "file_freeze_test_file"; 2539 1.1 christos char *cp; 2540 1.1 christos char charbuf[128]; 2541 1.7 christos char *tmpfilename = NULL; 2542 1.7 christos int fd = -1; 2543 1.1 christos int r; 2544 1.7 christos size_t orig_length, len; 2545 1.1 christos struct evbuffer_iovec v[1]; 2546 1.1 christos 2547 1.1 christos if (!start) 2548 1.7 christos tt_str_op(testdata->setup_data, ==, "end"); 2549 1.1 christos 2550 1.1 christos buf = evbuffer_new(); 2551 1.7 christos buf_two = evbuffer_new(); 2552 1.1 christos tmp_buf = evbuffer_new(); 2553 1.1 christos tt_assert(tmp_buf); 2554 1.1 christos 2555 1.1 christos evbuffer_add(buf, string, strlen(string)); 2556 1.7 christos evbuffer_add(buf_two, "abc", 3); 2557 1.7 christos evbuffer_add(tmp_buf, "xyz", 3); 2558 1.1 christos evbuffer_freeze(buf, start); /* Freeze the start or the end.*/ 2559 1.7 christos evbuffer_freeze(buf_two, start); 2560 1.1 christos 2561 1.1 christos #define FREEZE_EQ(a, startcase, endcase) \ 2562 1.1 christos do { \ 2563 1.1 christos if (start) { \ 2564 1.1 christos tt_int_op((a), ==, (startcase)); \ 2565 1.1 christos } else { \ 2566 1.1 christos tt_int_op((a), ==, (endcase)); \ 2567 1.1 christos } \ 2568 1.1 christos } while (0) 2569 1.1 christos 2570 1.1 christos 2571 1.1 christos orig_length = evbuffer_get_length(buf); 2572 1.1 christos 2573 1.1 christos /* These functions all manipulate the end of buf. */ 2574 1.1 christos r = evbuffer_add(buf, "abc", 0); 2575 1.1 christos FREEZE_EQ(r, 0, -1); 2576 1.1 christos r = evbuffer_reserve_space(buf, 10, v, 1); 2577 1.1 christos FREEZE_EQ(r, 1, -1); 2578 1.2 christos if (r == 1) { 2579 1.1 christos memset(v[0].iov_base, 'X', 10); 2580 1.1 christos v[0].iov_len = 10; 2581 1.1 christos } 2582 1.1 christos r = evbuffer_commit_space(buf, v, 1); 2583 1.1 christos FREEZE_EQ(r, 0, -1); 2584 1.1 christos r = evbuffer_add_reference(buf, string, 5, NULL, NULL); 2585 1.1 christos FREEZE_EQ(r, 0, -1); 2586 1.1 christos r = evbuffer_add_printf(buf, "Hello %s", "world"); 2587 1.1 christos FREEZE_EQ(r, 11, -1); 2588 1.7 christos 2589 1.7 christos r = evbuffer_add_buffer(buf, tmp_buf); 2590 1.7 christos FREEZE_EQ(r, 0, -1); 2591 1.7 christos len = strlen(tmpfilecontent); 2592 1.7 christos fd = regress_make_tmpfile(tmpfilecontent, len, &tmpfilename); 2593 1.7 christos r = evbuffer_add_file(buf, fd, 0, len); 2594 1.7 christos FREEZE_EQ(r, 0, -1); 2595 1.7 christos 2596 1.7 christos if (start) 2597 1.7 christos evbuffer_add(tmp_buf, "xyz", 3); 2598 1.7 christos 2599 1.7 christos tt_assert(evbuffer_get_length(tmp_buf)); 2600 1.7 christos len = evbuffer_get_length(tmp_buf); 2601 1.7 christos evbuffer_write(tmp_buf, pair[0]); 2602 1.7 christos r = evbuffer_read(buf, pair[1], -1); 2603 1.7 christos FREEZE_EQ(r, len, -1); 2604 1.1 christos 2605 1.1 christos if (!start) 2606 1.1 christos tt_int_op(orig_length, ==, evbuffer_get_length(buf)); 2607 1.1 christos 2608 1.1 christos orig_length = evbuffer_get_length(buf); 2609 1.1 christos 2610 1.1 christos /* These functions all manipulate the start of buf. */ 2611 1.1 christos r = evbuffer_remove(buf, charbuf, 1); 2612 1.1 christos FREEZE_EQ(r, -1, 1); 2613 1.1 christos r = evbuffer_drain(buf, 3); 2614 1.1 christos FREEZE_EQ(r, -1, 0); 2615 1.1 christos r = evbuffer_prepend(buf, "dummy", 5); 2616 1.1 christos FREEZE_EQ(r, -1, 0); 2617 1.1 christos cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF); 2618 1.1 christos FREEZE_EQ(cp==NULL, 1, 0); 2619 1.1 christos if (cp) 2620 1.1 christos free(cp); 2621 1.7 christos 2622 1.7 christos evbuffer_add(tmp_buf, "xyz", 3); 2623 1.7 christos tt_assert(evbuffer_get_length(tmp_buf)); 2624 1.7 christos r = evbuffer_remove_buffer(buf, tmp_buf, 3); 2625 1.7 christos FREEZE_EQ(r, -1, 3); 2626 1.7 christos r = evbuffer_drain(buf, 3); 2627 1.7 christos FREEZE_EQ(r, -1, 0); 2628 1.7 christos r = evbuffer_prepend_buffer(buf, tmp_buf); 2629 1.7 christos FREEZE_EQ(r, -1, 0); 2630 1.7 christos 2631 1.7 christos len = evbuffer_get_length(buf); 2632 1.7 christos r = evbuffer_write(buf, pair[0]); 2633 1.7 christos evbuffer_read(tmp_buf, pair[1], -1); 2634 1.7 christos FREEZE_EQ(r, -1, len); 2635 1.7 christos len = evbuffer_get_length(buf_two); 2636 1.7 christos r = evbuffer_write_atmost(buf_two, pair[0], -1); 2637 1.7 christos evbuffer_read(tmp_buf, pair[1], -1); 2638 1.7 christos FREEZE_EQ(r, -1, len); 2639 1.1 christos 2640 1.1 christos if (start) 2641 1.1 christos tt_int_op(orig_length, ==, evbuffer_get_length(buf)); 2642 1.1 christos 2643 1.1 christos end: 2644 1.1 christos if (buf) 2645 1.1 christos evbuffer_free(buf); 2646 1.1 christos 2647 1.7 christos if (buf_two) 2648 1.7 christos evbuffer_free(buf_two); 2649 1.7 christos 2650 1.1 christos if (tmp_buf) 2651 1.1 christos evbuffer_free(tmp_buf); 2652 1.7 christos 2653 1.7 christos if (tmpfilename) { 2654 1.7 christos unlink(tmpfilename); 2655 1.7 christos free(tmpfilename); 2656 1.7 christos } 2657 1.1 christos } 2658 1.1 christos 2659 1.1 christos static void 2660 1.1 christos test_evbuffer_add_iovec(void * ptr) 2661 1.1 christos { 2662 1.1 christos struct evbuffer * buf = NULL; 2663 1.1 christos struct evbuffer_iovec vec[4]; 2664 1.1 christos const char * data[] = { 2665 1.1 christos "Guilt resembles a sword with two edges.", 2666 1.1 christos "On the one hand, it cuts for Justice, imposing practical morality upon those who fear it.", 2667 1.1 christos "Conscience does not always adhere to rational judgment.", 2668 1.1 christos "Guilt is always a self-imposed burden, but it is not always rightly imposed." 2669 1.1 christos /* -- R.A. Salvatore, _Sojurn_ */ 2670 1.1 christos }; 2671 1.1 christos size_t expected_length = 0; 2672 1.1 christos size_t returned_length = 0; 2673 1.1 christos int i; 2674 1.1 christos 2675 1.1 christos buf = evbuffer_new(); 2676 1.1 christos 2677 1.1 christos tt_assert(buf); 2678 1.1 christos 2679 1.1 christos for (i = 0; i < 4; i++) { 2680 1.1 christos vec[i].iov_len = strlen(data[i]); 2681 1.1 christos vec[i].iov_base = (char*) data[i]; 2682 1.1 christos expected_length += vec[i].iov_len; 2683 1.1 christos } 2684 1.1 christos 2685 1.1 christos returned_length = evbuffer_add_iovec(buf, vec, 4); 2686 1.1 christos 2687 1.1 christos tt_int_op(returned_length, ==, evbuffer_get_length(buf)); 2688 1.1 christos tt_int_op(evbuffer_get_length(buf), ==, expected_length); 2689 1.1 christos 2690 1.1 christos for (i = 0; i < 4; i++) { 2691 1.1 christos char charbuf[1024]; 2692 1.1 christos 2693 1.1 christos memset(charbuf, 0, 1024); 2694 1.1 christos evbuffer_remove(buf, charbuf, strlen(data[i])); 2695 1.1 christos tt_assert(strcmp(charbuf, data[i]) == 0); 2696 1.1 christos } 2697 1.1 christos 2698 1.1 christos tt_assert(evbuffer_get_length(buf) == 0); 2699 1.1 christos end: 2700 1.1 christos if (buf) { 2701 1.1 christos evbuffer_free(buf); 2702 1.1 christos } 2703 1.1 christos } 2704 1.1 christos 2705 1.1 christos static void 2706 1.1 christos test_evbuffer_copyout(void *dummy) 2707 1.1 christos { 2708 1.1 christos const char string[] = 2709 1.1 christos "Still they skirmish to and fro, men my messmates on the snow " 2710 1.1 christos "When we headed off the aurochs turn for turn; " 2711 1.1 christos "When the rich Allobrogenses never kept amanuenses, " 2712 1.1 christos "And our only plots were piled in lakes at Berne."; 2713 1.1 christos /* -- Kipling, "In The Neolithic Age" */ 2714 1.3 christos char tmp[1024]; 2715 1.1 christos struct evbuffer_ptr ptr; 2716 1.1 christos struct evbuffer *buf; 2717 1.1 christos 2718 1.1 christos (void)dummy; 2719 1.1 christos 2720 1.1 christos buf = evbuffer_new(); 2721 1.1 christos tt_assert(buf); 2722 1.1 christos 2723 1.1 christos tt_int_op(strlen(string), ==, 206); 2724 1.1 christos 2725 1.1 christos /* Ensure separate chains */ 2726 1.1 christos evbuffer_add_reference(buf, string, 80, no_cleanup, NULL); 2727 1.1 christos evbuffer_add_reference(buf, string+80, 80, no_cleanup, NULL); 2728 1.1 christos evbuffer_add(buf, string+160, strlen(string)-160); 2729 1.1 christos 2730 1.1 christos tt_int_op(206, ==, evbuffer_get_length(buf)); 2731 1.1 christos 2732 1.1 christos /* First, let's test plain old copyout. */ 2733 1.1 christos 2734 1.1 christos /* Copy a little from the beginning. */ 2735 1.1 christos tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10)); 2736 1.1 christos tt_int_op(0, ==, memcmp(tmp, "Still they", 10)); 2737 1.1 christos 2738 1.1 christos /* Now copy more than a little from the beginning */ 2739 1.1 christos memset(tmp, 0, sizeof(tmp)); 2740 1.1 christos tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100)); 2741 1.1 christos tt_int_op(0, ==, memcmp(tmp, string, 100)); 2742 1.1 christos 2743 1.1 christos /* Copy too much; ensure truncation. */ 2744 1.1 christos memset(tmp, 0, sizeof(tmp)); 2745 1.1 christos tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230)); 2746 1.1 christos tt_int_op(0, ==, memcmp(tmp, string, 206)); 2747 1.1 christos 2748 1.1 christos /* That was supposed to be nondestructive, btw */ 2749 1.1 christos tt_int_op(206, ==, evbuffer_get_length(buf)); 2750 1.1 christos 2751 1.1 christos /* Now it's time to test copyout_from! First, let's start in the 2752 1.1 christos * first chain. */ 2753 1.1 christos evbuffer_ptr_set(buf, &ptr, 15, EVBUFFER_PTR_SET); 2754 1.1 christos memset(tmp, 0, sizeof(tmp)); 2755 1.1 christos tt_int_op(10, ==, evbuffer_copyout_from(buf, &ptr, tmp, 10)); 2756 1.1 christos tt_int_op(0, ==, memcmp(tmp, "mish to an", 10)); 2757 1.1 christos 2758 1.1 christos /* Right up to the end of the first chain */ 2759 1.1 christos memset(tmp, 0, sizeof(tmp)); 2760 1.1 christos tt_int_op(65, ==, evbuffer_copyout_from(buf, &ptr, tmp, 65)); 2761 1.1 christos tt_int_op(0, ==, memcmp(tmp, string+15, 65)); 2762 1.1 christos 2763 1.1 christos /* Span into the second chain */ 2764 1.1 christos memset(tmp, 0, sizeof(tmp)); 2765 1.1 christos tt_int_op(90, ==, evbuffer_copyout_from(buf, &ptr, tmp, 90)); 2766 1.1 christos tt_int_op(0, ==, memcmp(tmp, string+15, 90)); 2767 1.1 christos 2768 1.1 christos /* Span into the third chain */ 2769 1.1 christos memset(tmp, 0, sizeof(tmp)); 2770 1.1 christos tt_int_op(160, ==, evbuffer_copyout_from(buf, &ptr, tmp, 160)); 2771 1.1 christos tt_int_op(0, ==, memcmp(tmp, string+15, 160)); 2772 1.1 christos 2773 1.1 christos /* Overrun */ 2774 1.1 christos memset(tmp, 0, sizeof(tmp)); 2775 1.1 christos tt_int_op(206-15, ==, evbuffer_copyout_from(buf, &ptr, tmp, 999)); 2776 1.1 christos tt_int_op(0, ==, memcmp(tmp, string+15, 206-15)); 2777 1.1 christos 2778 1.1 christos /* That was supposed to be nondestructive, too */ 2779 1.1 christos tt_int_op(206, ==, evbuffer_get_length(buf)); 2780 1.1 christos 2781 1.1 christos end: 2782 1.1 christos if (buf) 2783 1.1 christos evbuffer_free(buf); 2784 1.1 christos } 2785 1.1 christos 2786 1.1 christos static void * 2787 1.1 christos setup_passthrough(const struct testcase_t *testcase) 2788 1.1 christos { 2789 1.1 christos return testcase->setup_data; 2790 1.1 christos } 2791 1.1 christos static int 2792 1.1 christos cleanup_passthrough(const struct testcase_t *testcase, void *ptr) 2793 1.1 christos { 2794 1.1 christos (void) ptr; 2795 1.1 christos return 1; 2796 1.1 christos } 2797 1.1 christos 2798 1.1 christos static const struct testcase_setup_t nil_setup = { 2799 1.1 christos setup_passthrough, 2800 1.1 christos cleanup_passthrough 2801 1.1 christos }; 2802 1.1 christos 2803 1.1 christos struct testcase_t evbuffer_testcases[] = { 2804 1.1 christos { "evbuffer", test_evbuffer, 0, NULL, NULL }, 2805 1.1 christos { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL }, 2806 1.7 christos { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL }, 2807 1.7 christos { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL }, 2808 1.7 christos { "remove_buffer_with_empty_front", test_evbuffer_remove_buffer_with_empty_front, 0, NULL, NULL }, 2809 1.7 christos { "remove_buffer_adjust_last_with_datap_with_empty", 2810 1.7 christos test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty, 0, NULL, NULL }, 2811 1.7 christos { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL }, 2812 1.7 christos { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL }, 2813 1.1 christos { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL }, 2814 1.1 christos { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL }, 2815 1.1 christos { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" }, 2816 1.1 christos { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" }, 2817 1.7 christos { "reserve_with_empty", test_evbuffer_reserve_with_empty, 0, NULL, NULL }, 2818 1.7 christos { "reserve_invalid_last_with_datap", test_evbuffer_reserve_invalid_last_with_datap, TT_FORK, NULL, NULL }, 2819 1.1 christos { "expand", test_evbuffer_expand, 0, NULL, NULL }, 2820 1.7 christos { "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL }, 2821 1.7 christos { "add1", test_evbuffer_add1, 0, NULL, NULL }, 2822 1.7 christos { "add2", test_evbuffer_add2, 0, NULL, NULL }, 2823 1.1 christos { "reference", test_evbuffer_reference, 0, NULL, NULL }, 2824 1.7 christos { "reference2", test_evbuffer_reference2, 0, NULL, NULL }, 2825 1.1 christos { "iterative", test_evbuffer_iterative, 0, NULL, NULL }, 2826 1.1 christos { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL }, 2827 1.1 christos { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL }, 2828 1.1 christos { "find", test_evbuffer_find, 0, NULL, NULL }, 2829 1.1 christos { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL }, 2830 1.1 christos { "search", test_evbuffer_search, 0, NULL, NULL }, 2831 1.1 christos { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL }, 2832 1.1 christos { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL }, 2833 1.1 christos { "multicast", test_evbuffer_multicast, 0, NULL, NULL }, 2834 1.1 christos { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL }, 2835 1.1 christos { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL }, 2836 1.7 christos { "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL }, 2837 1.7 christos { "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL }, 2838 1.1 christos { "peek", test_evbuffer_peek, 0, NULL, NULL }, 2839 1.3 christos { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL }, 2840 1.7 christos { "freeze_start", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"start" }, 2841 1.7 christos { "freeze_end", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"end" }, 2842 1.1 christos { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL}, 2843 1.1 christos { "copyout", test_evbuffer_copyout, 0, NULL, NULL}, 2844 1.1 christos { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL }, 2845 1.7 christos { "pullup_with_empty", test_evbuffer_pullup_with_empty, 0, NULL, NULL }, 2846 1.1 christos 2847 1.1 christos #define ADDFILE_TEST(name, parameters) \ 2848 1.1 christos { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \ 2849 1.1 christos &basic_setup, (void*)(parameters) } 2850 1.1 christos 2851 1.1 christos #define ADDFILE_TEST_GROUP(name, parameters) \ 2852 1.1 christos ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \ 2853 1.1 christos ADDFILE_TEST(name "_mmap", "mmap " parameters), \ 2854 1.1 christos ADDFILE_TEST(name "_linear", "linear " parameters) 2855 1.1 christos 2856 1.1 christos ADDFILE_TEST_GROUP("add_file", ""), 2857 1.1 christos ADDFILE_TEST("add_file_nosegment", "default nosegment"), 2858 1.1 christos 2859 1.1 christos ADDFILE_TEST_GROUP("add_big_file", "bigfile"), 2860 1.1 christos ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"), 2861 1.1 christos 2862 1.1 christos ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"), 2863 1.1 christos ADDFILE_TEST("add_file_offset_nosegment", 2864 1.1 christos "default nosegment bigfile map_offset"), 2865 1.1 christos 2866 1.1 christos ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"), 2867 1.1 christos 2868 1.1 christos ADDFILE_TEST_GROUP("add_file_offset3", 2869 1.1 christos "bigfile offset_in_segment map_offset"), 2870 1.1 christos 2871 1.1 christos END_OF_TESTCASES 2872 1.1 christos }; 2873