root/opal/mca/event/libevent2022/libevent/test/regress_bufferevent.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. readcb
  2. writecb
  3. errorcb
  4. test_bufferevent_impl
  5. test_bufferevent
  6. test_bufferevent_pair
  7. wm_readcb
  8. wm_writecb
  9. wm_errorcb
  10. test_bufferevent_watermarks_impl
  11. test_bufferevent_watermarks
  12. test_bufferevent_pair_watermarks
  13. bufferevent_input_filter
  14. bufferevent_output_filter
  15. test_bufferevent_filters_impl
  16. test_bufferevent_filters
  17. test_bufferevent_pair_filters
  18. sender_writecb
  19. sender_errorcb
  20. listen_cb
  21. reader_eventcb
  22. reader_readcb
  23. test_bufferevent_connect
  24. want_fail_eventcb
  25. close_socket_cb
  26. test_bufferevent_connect_fail
  27. bev_timeout_write_cb
  28. bev_timeout_event_cb
  29. test_bufferevent_timeouts

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

/* [<][>][^][v][top][bottom][index][help] */