1 /* $NetBSD: regress_bufferevent.c,v 1.2 2013/04/11 16:56:42 christos Exp $ */ 2 /* 3 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> 4 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* The old tests here need assertions to work. */ 30 #undef NDEBUG 31 32 #ifdef WIN32 33 #include <winsock2.h> 34 #include <windows.h> 35 #endif 36 37 #include "event2/event-config.h" 38 #include <sys/cdefs.h> 39 __RCSID("$NetBSD: regress_bufferevent.c,v 1.2 2013/04/11 16:56:42 christos Exp $"); 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #ifdef _EVENT_HAVE_SYS_TIME_H 44 #include <sys/time.h> 45 #endif 46 #include <sys/queue.h> 47 #ifndef WIN32 48 #include <sys/socket.h> 49 #include <sys/wait.h> 50 #include <signal.h> 51 #include <unistd.h> 52 #include <netdb.h> 53 #include <netinet/in.h> 54 #endif 55 #include <fcntl.h> 56 #include <signal.h> 57 #include <stdlib.h> 58 #include <stdio.h> 59 #include <string.h> 60 #include <errno.h> 61 #include <assert.h> 62 63 #ifdef _EVENT_HAVE_ARPA_INET_H 64 #include <arpa/inet.h> 65 #endif 66 67 #include "event2/event-config.h" 68 #include <sys/cdefs.h> 69 __RCSID("$NetBSD: regress_bufferevent.c,v 1.2 2013/04/11 16:56:42 christos Exp $"); 70 #include "event2/event.h" 71 #include "event2/event_struct.h" 72 #include "event2/event_compat.h" 73 #include "event2/tag.h" 74 #include "event2/buffer.h" 75 #include "event2/bufferevent.h" 76 #include "event2/bufferevent_compat.h" 77 #include "event2/bufferevent_struct.h" 78 #include "event2/listener.h" 79 #include "event2/util.h" 80 81 #include "bufferevent-internal.h" 82 #include "util-internal.h" 83 #ifdef WIN32 84 #include "iocp-internal.h" 85 #endif 86 87 #include "regress.h" 88 #include "regress_testutils.h" 89 90 /* 91 * simple bufferevent test 92 */ 93 94 static void 95 readcb(struct bufferevent *bev, void *arg) 96 { 97 if (evbuffer_get_length(bev->input) == 8333) { 98 struct evbuffer *evbuf = evbuffer_new(); 99 assert(evbuf != NULL); 100 101 /* gratuitous test of bufferevent_read_buffer */ 102 bufferevent_read_buffer(bev, evbuf); 103 104 bufferevent_disable(bev, EV_READ); 105 106 if (evbuffer_get_length(evbuf) == 8333) { 107 test_ok++; 108 } 109 110 evbuffer_free(evbuf); 111 } 112 } 113 114 static void 115 writecb(struct bufferevent *bev, void *arg) 116 { 117 if (evbuffer_get_length(bev->output) == 0) { 118 test_ok++; 119 } 120 } 121 122 static void 123 errorcb(struct bufferevent *bev, short what, void *arg) 124 { 125 test_ok = -2; 126 } 127 128 static void 129 test_bufferevent_impl(int use_pair) 130 { 131 struct bufferevent *bev1 = NULL, *bev2 = NULL; 132 char buffer[8333]; 133 int i; 134 135 if (use_pair) { 136 struct bufferevent *xpair[2]; 137 tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 138 bev1 = xpair[0]; 139 bev2 = xpair[1]; 140 bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL); 141 bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); 142 tt_int_op(bufferevent_getfd(bev1), ==, -1); 143 tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 144 tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2); 145 tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1); 146 } else { 147 bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); 148 bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); 149 tt_int_op(bufferevent_getfd(bev1), ==, pair[0]); 150 tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 151 tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 152 tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 153 } 154 155 bufferevent_disable(bev1, EV_READ); 156 bufferevent_enable(bev2, EV_READ); 157 158 tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE); 159 tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ); 160 161 for (i = 0; i < (int)sizeof(buffer); i++) 162 buffer[i] = i; 163 164 bufferevent_write(bev1, buffer, sizeof(buffer)); 165 166 event_dispatch(); 167 168 bufferevent_free(bev1); 169 tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 170 bufferevent_free(bev2); 171 172 if (test_ok != 2) 173 test_ok = 0; 174 end: 175 ; 176 } 177 178 static void 179 test_bufferevent(void) 180 { 181 test_bufferevent_impl(0); 182 } 183 184 static void 185 test_bufferevent_pair(void) 186 { 187 test_bufferevent_impl(1); 188 } 189 190 /* 191 * test watermarks and bufferevent 192 */ 193 194 static void 195 wm_readcb(struct bufferevent *bev, void *arg) 196 { 197 struct evbuffer *evbuf = evbuffer_new(); 198 int len = (int)evbuffer_get_length(bev->input); 199 static int nread; 200 201 assert(len >= 10 && len <= 20); 202 203 assert(evbuf != NULL); 204 205 /* gratuitous test of bufferevent_read_buffer */ 206 bufferevent_read_buffer(bev, evbuf); 207 208 nread += len; 209 if (nread == 65000) { 210 bufferevent_disable(bev, EV_READ); 211 test_ok++; 212 } 213 214 evbuffer_free(evbuf); 215 } 216 217 static void 218 wm_writecb(struct bufferevent *bev, void *arg) 219 { 220 assert(evbuffer_get_length(bev->output) <= 100); 221 if (evbuffer_get_length(bev->output) == 0) { 222 evbuffer_drain(bev->output, evbuffer_get_length(bev->output)); 223 test_ok++; 224 } 225 } 226 227 static void 228 wm_errorcb(struct bufferevent *bev, short what, void *arg) 229 { 230 test_ok = -2; 231 } 232 233 static void 234 test_bufferevent_watermarks_impl(int use_pair) 235 { 236 struct bufferevent *bev1 = NULL, *bev2 = NULL; 237 char buffer[65000]; 238 int i; 239 test_ok = 0; 240 241 if (use_pair) { 242 struct bufferevent *xpair[2]; 243 tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 244 bev1 = xpair[0]; 245 bev2 = xpair[1]; 246 bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL); 247 bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL); 248 } else { 249 bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL); 250 bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL); 251 } 252 tt_assert(bev1); 253 tt_assert(bev2); 254 bufferevent_disable(bev1, EV_READ); 255 bufferevent_enable(bev2, EV_READ); 256 257 for (i = 0; i < (int)sizeof(buffer); i++) 258 buffer[i] = (char)i; 259 260 /* limit the reading on the receiving bufferevent */ 261 bufferevent_setwatermark(bev2, EV_READ, 10, 20); 262 263 /* Tell the sending bufferevent not to notify us till it's down to 264 100 bytes. */ 265 bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); 266 267 bufferevent_write(bev1, buffer, sizeof(buffer)); 268 269 event_dispatch(); 270 271 tt_int_op(test_ok, ==, 2); 272 273 /* The write callback drained all the data from outbuf, so we 274 * should have removed the write event... */ 275 tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL)); 276 277 end: 278 if (bev1) 279 bufferevent_free(bev1); 280 if (bev2) 281 bufferevent_free(bev2); 282 } 283 284 static void 285 test_bufferevent_watermarks(void) 286 { 287 test_bufferevent_watermarks_impl(0); 288 } 289 290 static void 291 test_bufferevent_pair_watermarks(void) 292 { 293 test_bufferevent_watermarks_impl(1); 294 } 295 296 /* 297 * Test bufferevent filters 298 */ 299 300 /* strip an 'x' from each byte */ 301 302 static enum bufferevent_filter_result 303 bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst, 304 ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 305 { 306 const unsigned char *buffer; 307 unsigned i; 308 309 buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 310 for (i = 0; i < evbuffer_get_length(src); i += 2) { 311 assert(buffer[i] == 'x'); 312 evbuffer_add(dst, buffer + i + 1, 1); 313 314 if (i + 2 > evbuffer_get_length(src)) 315 break; 316 } 317 318 evbuffer_drain(src, i); 319 return (BEV_OK); 320 } 321 322 /* add an 'x' before each byte */ 323 324 static enum bufferevent_filter_result 325 bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst, 326 ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 327 { 328 const unsigned char *buffer; 329 unsigned i; 330 331 buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 332 for (i = 0; i < evbuffer_get_length(src); ++i) { 333 evbuffer_add(dst, "x", 1); 334 evbuffer_add(dst, buffer + i, 1); 335 } 336 337 evbuffer_drain(src, evbuffer_get_length(src)); 338 return (BEV_OK); 339 } 340 341 static void 342 test_bufferevent_filters_impl(int use_pair) 343 { 344 struct bufferevent *bev1 = NULL, *bev2 = NULL; 345 struct bufferevent *bev1_base = NULL, *bev2_base = NULL; 346 char buffer[8333]; 347 int i; 348 349 test_ok = 0; 350 351 if (use_pair) { 352 struct bufferevent *xpair[2]; 353 tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 354 bev1 = xpair[0]; 355 bev2 = xpair[1]; 356 } else { 357 bev1 = bufferevent_socket_new(NULL, pair[0], 0); 358 bev2 = bufferevent_socket_new(NULL, pair[1], 0); 359 } 360 bev1_base = bev1; 361 bev2_base = bev2; 362 363 for (i = 0; i < (int)sizeof(buffer); i++) 364 buffer[i] = i; 365 366 bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter, 367 BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 368 369 bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter, 370 NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 371 bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL); 372 bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL); 373 374 tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base); 375 tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base); 376 tt_int_op(bufferevent_getfd(bev1), ==, -1); 377 tt_int_op(bufferevent_getfd(bev2), ==, -1); 378 379 bufferevent_disable(bev1, EV_READ); 380 bufferevent_enable(bev2, EV_READ); 381 /* insert some filters */ 382 bufferevent_write(bev1, buffer, sizeof(buffer)); 383 384 event_dispatch(); 385 386 if (test_ok != 2) 387 test_ok = 0; 388 389 end: 390 if (bev1) 391 bufferevent_free(bev1); 392 if (bev2) 393 bufferevent_free(bev2); 394 395 } 396 397 static void 398 test_bufferevent_filters(void) 399 { 400 test_bufferevent_filters_impl(0); 401 } 402 403 static void 404 test_bufferevent_pair_filters(void) 405 { 406 test_bufferevent_filters_impl(1); 407 } 408 409 410 static void 411 sender_writecb(struct bufferevent *bev, void *ctx) 412 { 413 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { 414 bufferevent_disable(bev,EV_READ|EV_WRITE); 415 bufferevent_free(bev); 416 } 417 } 418 419 static void 420 sender_errorcb(struct bufferevent *bev, short what, void *ctx) 421 { 422 TT_FAIL(("Got sender error %d",(int)what)); 423 } 424 425 static int bufferevent_connect_test_flags = 0; 426 static int n_strings_read = 0; 427 static int n_reads_invoked = 0; 428 429 #define TEST_STR "Now is the time for all good events to signal for " \ 430 "the good of their protocol" 431 static void 432 listen_cb(struct evconnlistener *listener, evutil_socket_t fd, 433 struct sockaddr *sa, int socklen, void *arg) 434 { 435 struct event_base *base = arg; 436 struct bufferevent *bev; 437 const char s[] = TEST_STR; 438 TT_BLATHER(("Got a request on socket %d", (int)fd )); 439 bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags); 440 tt_assert(bev); 441 bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL); 442 bufferevent_write(bev, s, sizeof(s)); 443 end: 444 ; 445 } 446 447 static void 448 reader_eventcb(struct bufferevent *bev, short what, void *ctx) 449 { 450 struct event_base *base = ctx; 451 if (what & BEV_EVENT_ERROR) { 452 perror("foobar"); 453 TT_FAIL(("got connector error %d", (int)what)); 454 return; 455 } 456 if (what & BEV_EVENT_CONNECTED) { 457 bufferevent_enable(bev, EV_READ); 458 } 459 if (what & BEV_EVENT_EOF) { 460 char buf[512]; 461 size_t n; 462 n = bufferevent_read(bev, buf, sizeof(buf)-1); 463 buf[n] = '\0'; 464 tt_str_op(buf, ==, TEST_STR); 465 if (++n_strings_read == 2) 466 event_base_loopexit(base, NULL); 467 } 468 end: 469 ; 470 } 471 472 static void 473 reader_readcb(struct bufferevent *bev, void *ctx) 474 { 475 n_reads_invoked++; 476 } 477 478 static void 479 test_bufferevent_connect(void *arg) 480 { 481 struct basic_test_data *data = arg; 482 struct evconnlistener *lev=NULL; 483 struct bufferevent *bev1=NULL, *bev2=NULL; 484 struct sockaddr_in localhost; 485 struct sockaddr_storage ss; 486 struct sockaddr *sa; 487 ev_socklen_t slen; 488 489 int be_flags=BEV_OPT_CLOSE_ON_FREE; 490 491 if (strstr((char*)data->setup_data, "defer")) { 492 be_flags |= BEV_OPT_DEFER_CALLBACKS; 493 } 494 if (strstr((char*)data->setup_data, "unlocked")) { 495 be_flags |= BEV_OPT_UNLOCK_CALLBACKS; 496 } 497 if (strstr((char*)data->setup_data, "lock")) { 498 be_flags |= BEV_OPT_THREADSAFE; 499 } 500 bufferevent_connect_test_flags = be_flags; 501 #ifdef WIN32 502 if (!strcmp((char*)data->setup_data, "unset_connectex")) { 503 struct win32_extension_fns *ext = 504 (struct win32_extension_fns *) 505 event_get_win32_extension_fns(); 506 ext->ConnectEx = NULL; 507 } 508 #endif 509 510 memset(&localhost, 0, sizeof(localhost)); 511 512 localhost.sin_port = 0; /* pick-a-port */ 513 localhost.sin_addr.s_addr = htonl(0x7f000001L); 514 localhost.sin_family = AF_INET; 515 sa = (struct sockaddr *)&localhost; 516 lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 517 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 518 16, sa, sizeof(localhost)); 519 tt_assert(lev); 520 521 sa = (struct sockaddr *)&ss; 522 slen = sizeof(ss); 523 if (regress_get_listener_addr(lev, sa, &slen) < 0) { 524 tt_abort_perror("getsockname"); 525 } 526 527 tt_assert(!evconnlistener_enable(lev)); 528 bev1 = bufferevent_socket_new(data->base, -1, be_flags); 529 bev2 = bufferevent_socket_new(data->base, -1, be_flags); 530 tt_assert(bev1); 531 tt_assert(bev2); 532 bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base); 533 bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base); 534 535 bufferevent_enable(bev1, EV_READ); 536 bufferevent_enable(bev2, EV_READ); 537 538 tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost))); 539 tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost))); 540 541 event_base_dispatch(data->base); 542 543 tt_int_op(n_strings_read, ==, 2); 544 tt_int_op(n_reads_invoked, >=, 2); 545 end: 546 if (lev) 547 evconnlistener_free(lev); 548 549 if (bev1) 550 bufferevent_free(bev1); 551 552 if (bev2) 553 bufferevent_free(bev2); 554 } 555 556 static void 557 want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 558 { 559 struct event_base *base = ctx; 560 const char *err; 561 evutil_socket_t s; 562 563 if (what & BEV_EVENT_ERROR) { 564 s = bufferevent_getfd(bev); 565 err = evutil_socket_error_to_string(evutil_socket_geterror(s)); 566 TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s", 567 EV_SOCK_ARG(s), err)); 568 test_ok = 1; 569 } else { 570 TT_FAIL(("didn't fail? what %hd", what)); 571 } 572 573 event_base_loopexit(base, NULL); 574 } 575 576 static void 577 close_socket_cb(evutil_socket_t fd, short what, void *arg) 578 { 579 evutil_socket_t *fdp = arg; 580 if (*fdp >= 0) { 581 evutil_closesocket(*fdp); 582 *fdp = -1; 583 } 584 } 585 586 static void 587 test_bufferevent_connect_fail(void *arg) 588 { 589 struct basic_test_data *data = arg; 590 struct bufferevent *bev=NULL; 591 struct sockaddr_in localhost; 592 struct sockaddr *sa = (struct sockaddr*)&localhost; 593 evutil_socket_t fake_listener = -1; 594 ev_socklen_t slen = sizeof(localhost); 595 struct event close_listener_event; 596 int close_listener_event_added = 0; 597 struct timeval one_second = { 1, 0 }; 598 int r; 599 600 test_ok = 0; 601 602 memset(&localhost, 0, sizeof(localhost)); 603 localhost.sin_port = 0; /* have the kernel pick a port */ 604 localhost.sin_addr.s_addr = htonl(0x7f000001L); 605 localhost.sin_family = AF_INET; 606 607 /* bind, but don't listen or accept. should trigger 608 "Connection refused" reliably on most platforms. */ 609 fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0); 610 tt_assert(fake_listener >= 0); 611 tt_assert(bind(fake_listener, sa, slen) == 0); 612 tt_assert(getsockname(fake_listener, sa, &slen) == 0); 613 bev = bufferevent_socket_new(data->base, -1, 614 BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 615 tt_assert(bev); 616 bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 617 618 r = bufferevent_socket_connect(bev, sa, slen); 619 /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 620 * detects the error immediately, which is not really wrong of it. */ 621 tt_want(r == 0 || r == -1); 622 623 /* Close the listener socket after a second. This should trigger 624 "connection refused" on some other platforms, including OSX. */ 625 evtimer_assign(&close_listener_event, data->base, close_socket_cb, 626 &fake_listener); 627 event_add(&close_listener_event, &one_second); 628 close_listener_event_added = 1; 629 630 event_base_dispatch(data->base); 631 632 tt_int_op(test_ok, ==, 1); 633 634 end: 635 if (fake_listener >= 0) 636 evutil_closesocket(fake_listener); 637 638 if (bev) 639 bufferevent_free(bev); 640 641 if (close_listener_event_added) 642 event_del(&close_listener_event); 643 } 644 645 struct timeout_cb_result { 646 struct timeval read_timeout_at; 647 struct timeval write_timeout_at; 648 struct timeval last_wrote_at; 649 int n_read_timeouts; 650 int n_write_timeouts; 651 int total_calls; 652 }; 653 654 static void 655 bev_timeout_write_cb(struct bufferevent *bev, void *arg) 656 { 657 struct timeout_cb_result *res = arg; 658 evutil_gettimeofday(&res->last_wrote_at, NULL); 659 } 660 661 static void 662 bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg) 663 { 664 struct timeout_cb_result *res = arg; 665 ++res->total_calls; 666 667 if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) 668 == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) { 669 evutil_gettimeofday(&res->read_timeout_at, NULL); 670 ++res->n_read_timeouts; 671 } 672 if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) 673 == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) { 674 evutil_gettimeofday(&res->write_timeout_at, NULL); 675 ++res->n_write_timeouts; 676 } 677 } 678 679 static void 680 test_bufferevent_timeouts(void *arg) 681 { 682 /* "arg" is a string containing "pair" and/or "filter". */ 683 struct bufferevent *bev1 = NULL, *bev2 = NULL; 684 struct basic_test_data *data = arg; 685 int use_pair = 0, use_filter = 0; 686 struct timeval tv_w, tv_r, started_at; 687 struct timeout_cb_result res1, res2; 688 char buf[1024]; 689 690 memset(&res1, 0, sizeof(res1)); 691 memset(&res2, 0, sizeof(res2)); 692 693 if (strstr((char*)data->setup_data, "pair")) 694 use_pair = 1; 695 if (strstr((char*)data->setup_data, "filter")) 696 use_filter = 1; 697 698 if (use_pair) { 699 struct bufferevent *p[2]; 700 tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p)); 701 bev1 = p[0]; 702 bev2 = p[1]; 703 } else { 704 bev1 = bufferevent_socket_new(data->base, data->pair[0], 0); 705 bev2 = bufferevent_socket_new(data->base, data->pair[1], 0); 706 } 707 708 tt_assert(bev1); 709 tt_assert(bev2); 710 711 if (use_filter) { 712 struct bufferevent *bevf1, *bevf2; 713 bevf1 = bufferevent_filter_new(bev1, NULL, NULL, 714 BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 715 bevf2 = bufferevent_filter_new(bev2, NULL, NULL, 716 BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 717 tt_assert(bevf1); 718 tt_assert(bevf2); 719 bev1 = bevf1; 720 bev2 = bevf2; 721 } 722 723 /* Do this nice and early. */ 724 bufferevent_disable(bev2, EV_READ); 725 726 /* bev1 will try to write and read. Both will time out. */ 727 evutil_gettimeofday(&started_at, NULL); 728 tv_w.tv_sec = tv_r.tv_sec = 0; 729 tv_w.tv_usec = 100*1000; 730 tv_r.tv_usec = 150*1000; 731 bufferevent_setcb(bev1, NULL, bev_timeout_write_cb, 732 bev_timeout_event_cb, &res1); 733 bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0); 734 bufferevent_set_timeouts(bev1, &tv_r, &tv_w); 735 if (use_pair) { 736 /* For a pair, the fact that the other side isn't reading 737 * makes the writer stall */ 738 bufferevent_write(bev1, "ABCDEFG", 7); 739 } else { 740 /* For a real socket, the kernel's TCP buffers can eat a 741 * fair number of bytes; make sure that at some point we 742 * have some bytes that will stall. */ 743 struct evbuffer *output = bufferevent_get_output(bev1); 744 int i; 745 memset(buf, 0xbb, sizeof(buf)); 746 for (i=0;i<1024;++i) { 747 evbuffer_add_reference(output, buf, sizeof(buf), 748 NULL, NULL); 749 } 750 } 751 bufferevent_enable(bev1, EV_READ|EV_WRITE); 752 753 /* bev2 has nothing to say, and isn't listening. */ 754 bufferevent_setcb(bev2, NULL, bev_timeout_write_cb, 755 bev_timeout_event_cb, &res2); 756 tv_w.tv_sec = tv_r.tv_sec = 0; 757 tv_w.tv_usec = 200*1000; 758 tv_r.tv_usec = 100*1000; 759 bufferevent_set_timeouts(bev2, &tv_r, &tv_w); 760 bufferevent_enable(bev2, EV_WRITE); 761 762 tv_r.tv_sec = 1; 763 tv_r.tv_usec = 0; 764 765 event_base_loopexit(data->base, &tv_r); 766 event_base_dispatch(data->base); 767 768 /* XXXX Test that actually reading or writing a little resets the 769 * timeouts. */ 770 771 /* Each buf1 timeout happens, and happens only once. */ 772 tt_want(res1.n_read_timeouts); 773 tt_want(res1.n_write_timeouts); 774 tt_want(res1.n_read_timeouts == 1); 775 tt_want(res1.n_write_timeouts == 1); 776 777 test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150); 778 test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100); 779 780 end: 781 if (bev1) 782 bufferevent_free(bev1); 783 if (bev2) 784 bufferevent_free(bev2); 785 } 786 787 struct testcase_t bufferevent_testcases[] = { 788 789 LEGACY(bufferevent, TT_ISOLATED), 790 LEGACY(bufferevent_pair, TT_ISOLATED), 791 LEGACY(bufferevent_watermarks, TT_ISOLATED), 792 LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), 793 LEGACY(bufferevent_filters, TT_ISOLATED), 794 LEGACY(bufferevent_pair_filters, TT_ISOLATED), 795 { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE, 796 &basic_setup, __UNCONST("") }, 797 { "bufferevent_connect_defer", test_bufferevent_connect, 798 TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("defer") }, 799 { "bufferevent_connect_lock", test_bufferevent_connect, 800 TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, __UNCONST("lock") }, 801 { "bufferevent_connect_lock_defer", test_bufferevent_connect, 802 TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 803 __UNCONST("defer lock") }, 804 { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect, 805 TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 806 __UNCONST("lock defer unlocked") }, 807 { "bufferevent_connect_fail", test_bufferevent_connect_fail, 808 TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 809 { "bufferevent_timeout", test_bufferevent_timeouts, 810 TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, __UNCONST("") }, 811 { "bufferevent_timeout_pair", test_bufferevent_timeouts, 812 TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("pair") }, 813 { "bufferevent_timeout_filter", test_bufferevent_timeouts, 814 TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("filter") }, 815 { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts, 816 TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("filter pair") }, 817 #ifdef _EVENT_HAVE_LIBZ 818 LEGACY(bufferevent_zlib, TT_ISOLATED), 819 #else 820 { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, 821 #endif 822 823 END_OF_TESTCASES, 824 }; 825 826 struct testcase_t bufferevent_iocp_testcases[] = { 827 828 LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP), 829 LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP), 830 LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP), 831 { "bufferevent_connect", test_bufferevent_connect, 832 TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, __UNCONST("") }, 833 { "bufferevent_connect_defer", test_bufferevent_connect, 834 TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, __UNCONST("defer") }, 835 { "bufferevent_connect_lock", test_bufferevent_connect, 836 TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 837 __UNCONST("lock") }, 838 { "bufferevent_connect_lock_defer", test_bufferevent_connect, 839 TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 840 __UNCONST("defer lock") }, 841 { "bufferevent_connect_fail", test_bufferevent_connect_fail, 842 TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL }, 843 { "bufferevent_connect_nonblocking", test_bufferevent_connect, 844 TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, 845 __UNCONST("unset_connectex") }, 846 847 END_OF_TESTCASES, 848 }; 849