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