1275970Scy/* 2275970Scy * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> 3275970Scy * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4275970Scy * 5275970Scy * Redistribution and use in source and binary forms, with or without 6275970Scy * modification, are permitted provided that the following conditions 7275970Scy * are met: 8275970Scy * 1. Redistributions of source code must retain the above copyright 9275970Scy * notice, this list of conditions and the following disclaimer. 10275970Scy * 2. Redistributions in binary form must reproduce the above copyright 11275970Scy * notice, this list of conditions and the following disclaimer in the 12275970Scy * documentation and/or other materials provided with the distribution. 13275970Scy * 3. The name of the author may not be used to endorse or promote products 14275970Scy * derived from this software without specific prior written permission. 15275970Scy * 16275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26275970Scy */ 27275970Scy#include "util-internal.h" 28275970Scy 29275970Scy/* The old tests here need assertions to work. */ 30275970Scy#undef NDEBUG 31275970Scy 32275970Scy#ifdef _WIN32 33275970Scy#include <winsock2.h> 34275970Scy#include <windows.h> 35275970Scy#endif 36275970Scy 37275970Scy#include "event2/event-config.h" 38275970Scy 39275970Scy#include <sys/types.h> 40275970Scy#include <sys/stat.h> 41275970Scy#ifdef EVENT__HAVE_SYS_TIME_H 42275970Scy#include <sys/time.h> 43275970Scy#endif 44275970Scy#include <sys/queue.h> 45275970Scy#ifndef _WIN32 46275970Scy#include <sys/socket.h> 47275970Scy#include <sys/wait.h> 48275970Scy#include <signal.h> 49275970Scy#include <unistd.h> 50275970Scy#include <netdb.h> 51275970Scy#include <netinet/in.h> 52275970Scy#endif 53275970Scy#include <fcntl.h> 54275970Scy#include <signal.h> 55275970Scy#include <stdlib.h> 56275970Scy#include <stdio.h> 57275970Scy#include <string.h> 58275970Scy#include <errno.h> 59275970Scy#include <assert.h> 60275970Scy 61275970Scy#ifdef EVENT__HAVE_ARPA_INET_H 62275970Scy#include <arpa/inet.h> 63275970Scy#endif 64275970Scy 65275970Scy#include "event2/event-config.h" 66275970Scy#include "event2/event.h" 67275970Scy#include "event2/event_struct.h" 68275970Scy#include "event2/event_compat.h" 69275970Scy#include "event2/tag.h" 70275970Scy#include "event2/buffer.h" 71275970Scy#include "event2/bufferevent.h" 72275970Scy#include "event2/bufferevent_compat.h" 73275970Scy#include "event2/bufferevent_struct.h" 74275970Scy#include "event2/listener.h" 75275970Scy#include "event2/util.h" 76275970Scy 77275970Scy#include "bufferevent-internal.h" 78282408Scy#include "evthread-internal.h" 79275970Scy#include "util-internal.h" 80275970Scy#ifdef _WIN32 81275970Scy#include "iocp-internal.h" 82275970Scy#endif 83275970Scy 84275970Scy#include "regress.h" 85275970Scy#include "regress_testutils.h" 86275970Scy 87275970Scy/* 88275970Scy * simple bufferevent test 89275970Scy */ 90275970Scy 91275970Scystatic void 92275970Scyreadcb(struct bufferevent *bev, void *arg) 93275970Scy{ 94275970Scy if (evbuffer_get_length(bev->input) == 8333) { 95275970Scy struct evbuffer *evbuf = evbuffer_new(); 96275970Scy assert(evbuf != NULL); 97275970Scy 98275970Scy /* gratuitous test of bufferevent_read_buffer */ 99275970Scy bufferevent_read_buffer(bev, evbuf); 100275970Scy 101275970Scy bufferevent_disable(bev, EV_READ); 102275970Scy 103275970Scy if (evbuffer_get_length(evbuf) == 8333) { 104275970Scy test_ok++; 105275970Scy } 106275970Scy 107275970Scy evbuffer_free(evbuf); 108275970Scy } 109275970Scy} 110275970Scy 111275970Scystatic void 112275970Scywritecb(struct bufferevent *bev, void *arg) 113275970Scy{ 114275970Scy if (evbuffer_get_length(bev->output) == 0) { 115275970Scy test_ok++; 116275970Scy } 117275970Scy} 118275970Scy 119275970Scystatic void 120275970Scyerrorcb(struct bufferevent *bev, short what, void *arg) 121275970Scy{ 122275970Scy test_ok = -2; 123275970Scy} 124275970Scy 125275970Scystatic void 126275970Scytest_bufferevent_impl(int use_pair) 127275970Scy{ 128275970Scy struct bufferevent *bev1 = NULL, *bev2 = NULL; 129275970Scy char buffer[8333]; 130275970Scy int i; 131275970Scy 132275970Scy if (use_pair) { 133275970Scy struct bufferevent *pair[2]; 134275970Scy tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 135275970Scy bev1 = pair[0]; 136275970Scy bev2 = pair[1]; 137275970Scy bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1); 138275970Scy bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); 139275970Scy tt_int_op(bufferevent_getfd(bev1), ==, -1); 140275970Scy tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 141275970Scy tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2); 142275970Scy tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1); 143275970Scy } else { 144275970Scy bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); 145275970Scy bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); 146275970Scy tt_int_op(bufferevent_getfd(bev1), ==, pair[0]); 147275970Scy tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 148275970Scy tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 149275970Scy tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 150275970Scy } 151275970Scy 152275970Scy { 153275970Scy /* Test getcb. */ 154275970Scy bufferevent_data_cb r, w; 155275970Scy bufferevent_event_cb e; 156275970Scy void *a; 157275970Scy bufferevent_getcb(bev1, &r, &w, &e, &a); 158275970Scy tt_ptr_op(r, ==, readcb); 159275970Scy tt_ptr_op(w, ==, writecb); 160275970Scy tt_ptr_op(e, ==, errorcb); 161275970Scy tt_ptr_op(a, ==, use_pair ? bev1 : NULL); 162275970Scy } 163275970Scy 164275970Scy bufferevent_disable(bev1, EV_READ); 165275970Scy bufferevent_enable(bev2, EV_READ); 166275970Scy 167275970Scy tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE); 168275970Scy tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ); 169275970Scy 170275970Scy for (i = 0; i < (int)sizeof(buffer); i++) 171275970Scy buffer[i] = i; 172275970Scy 173275970Scy bufferevent_write(bev1, buffer, sizeof(buffer)); 174275970Scy 175275970Scy event_dispatch(); 176275970Scy 177282408Scy bufferevent_free(bev2); 178282408Scy tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 179275970Scy bufferevent_free(bev1); 180275970Scy 181275970Scy if (test_ok != 2) 182275970Scy test_ok = 0; 183275970Scyend: 184275970Scy ; 185275970Scy} 186275970Scy 187275970Scystatic void 188275970Scytest_bufferevent(void) 189275970Scy{ 190275970Scy test_bufferevent_impl(0); 191275970Scy} 192275970Scy 193275970Scystatic void 194275970Scytest_bufferevent_pair(void) 195275970Scy{ 196275970Scy test_bufferevent_impl(1); 197275970Scy} 198275970Scy 199282408Scy#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) 200282408Scy/** 201282408Scy * Trace lock/unlock/alloc/free for locks. 202282408Scy * (More heavier then evthread_debug*) 203282408Scy */ 204282408Scytypedef struct 205282408Scy{ 206282408Scy void *lock; 207282408Scy enum { 208282408Scy ALLOC, FREE, 209282408Scy } status; 210282408Scy size_t locked /** allow recursive locking */; 211282408Scy} lock_wrapper; 212282408Scystruct lock_unlock_base 213282408Scy{ 214282408Scy /* Original callbacks */ 215282408Scy struct evthread_lock_callbacks cbs; 216282408Scy /* Map of locks */ 217282408Scy lock_wrapper *locks; 218282408Scy size_t nr_locks; 219282408Scy} lu_base = { 220282408Scy .locks = NULL, 221282408Scy}; 222282408Scy 223282408Scystatic lock_wrapper *lu_find(void *lock_) 224282408Scy{ 225282408Scy size_t i; 226282408Scy for (i = 0; i < lu_base.nr_locks; ++i) { 227282408Scy lock_wrapper *lock = &lu_base.locks[i]; 228282408Scy if (lock->lock == lock_) 229282408Scy return lock; 230282408Scy } 231282408Scy return NULL; 232282408Scy} 233282408Scy 234282408Scystatic void *trace_lock_alloc(unsigned locktype) 235282408Scy{ 236282408Scy ++lu_base.nr_locks; 237282408Scy lu_base.locks = realloc(lu_base.locks, 238282408Scy sizeof(lock_wrapper) * lu_base.nr_locks); 239282408Scy void *lock = lu_base.cbs.alloc(locktype); 240282408Scy lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 }; 241282408Scy return lock; 242282408Scy} 243282408Scystatic void trace_lock_free(void *lock_, unsigned locktype) 244282408Scy{ 245282408Scy lock_wrapper *lock = lu_find(lock_); 246282408Scy if (!lock || lock->status == FREE || lock->locked) { 247282408Scy __asm__("int3"); 248282408Scy TT_FAIL(("lock: free error")); 249282408Scy } else { 250282408Scy lock->status = FREE; 251282408Scy lu_base.cbs.free(lock_, locktype); 252282408Scy } 253282408Scy} 254282408Scystatic int trace_lock_lock(unsigned mode, void *lock_) 255282408Scy{ 256282408Scy lock_wrapper *lock = lu_find(lock_); 257282408Scy if (!lock || lock->status == FREE) { 258282408Scy TT_FAIL(("lock: lock error")); 259282408Scy return -1; 260282408Scy } else { 261282408Scy ++lock->locked; 262282408Scy return lu_base.cbs.lock(mode, lock_); 263282408Scy } 264282408Scy} 265282408Scystatic int trace_lock_unlock(unsigned mode, void *lock_) 266282408Scy{ 267282408Scy lock_wrapper *lock = lu_find(lock_); 268282408Scy if (!lock || lock->status == FREE || !lock->locked) { 269282408Scy TT_FAIL(("lock: unlock error")); 270282408Scy return -1; 271282408Scy } else { 272282408Scy --lock->locked; 273282408Scy return lu_base.cbs.unlock(mode, lock_); 274282408Scy } 275282408Scy} 276282408Scystatic void lock_unlock_free_thread_cbs() 277282408Scy{ 278282408Scy event_base_free(NULL); 279282408Scy 280282408Scy /** drop immutable flag */ 281282408Scy evthread_set_lock_callbacks(NULL); 282282408Scy /** avoid calling of event_global_setup_locks_() for new cbs */ 283282408Scy libevent_global_shutdown(); 284282408Scy /** drop immutable flag for non-debug ops (since called after shutdown) */ 285282408Scy evthread_set_lock_callbacks(NULL); 286282408Scy} 287282408Scy 288282408Scystatic int use_lock_unlock_profiler(void) 289282408Scy{ 290282408Scy struct evthread_lock_callbacks cbs = { 291282408Scy EVTHREAD_LOCK_API_VERSION, 292282408Scy EVTHREAD_LOCKTYPE_RECURSIVE, 293282408Scy trace_lock_alloc, 294282408Scy trace_lock_free, 295282408Scy trace_lock_lock, 296282408Scy trace_lock_unlock, 297282408Scy }; 298282408Scy memcpy(&lu_base.cbs, evthread_get_lock_callbacks(), 299282408Scy sizeof(lu_base.cbs)); 300282408Scy { 301282408Scy lock_unlock_free_thread_cbs(); 302282408Scy 303282408Scy evthread_set_lock_callbacks(&cbs); 304282408Scy /** re-create debug locks correctly */ 305282408Scy evthread_enable_lock_debugging(); 306282408Scy 307282408Scy event_init(); 308282408Scy } 309282408Scy return 0; 310282408Scy} 311282408Scystatic void free_lock_unlock_profiler(struct basic_test_data *data) 312282408Scy{ 313282408Scy lock_unlock_free_thread_cbs(); 314282408Scy free(lu_base.locks); 315282408Scy data->base = NULL; 316282408Scy} 317282408Scy 318282408Scystatic void test_bufferevent_pair_release_lock(void *arg) 319282408Scy{ 320282408Scy struct basic_test_data *data = arg; 321282408Scy use_lock_unlock_profiler(); 322282408Scy { 323282408Scy struct bufferevent *pair[2]; 324282408Scy if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) { 325282408Scy bufferevent_free(pair[0]); 326282408Scy bufferevent_free(pair[1]); 327282408Scy } else 328282408Scy tt_abort_perror("bufferevent_pair_new"); 329282408Scy } 330282408Scy free_lock_unlock_profiler(data); 331282408Scyend: 332282408Scy ; 333282408Scy} 334282408Scy#endif 335282408Scy 336275970Scy/* 337275970Scy * test watermarks and bufferevent 338275970Scy */ 339275970Scy 340275970Scystatic void 341275970Scywm_readcb(struct bufferevent *bev, void *arg) 342275970Scy{ 343275970Scy struct evbuffer *evbuf = evbuffer_new(); 344275970Scy int len = (int)evbuffer_get_length(bev->input); 345275970Scy static int nread; 346275970Scy 347275970Scy assert(len >= 10 && len <= 20); 348275970Scy 349275970Scy assert(evbuf != NULL); 350275970Scy 351275970Scy /* gratuitous test of bufferevent_read_buffer */ 352275970Scy bufferevent_read_buffer(bev, evbuf); 353275970Scy 354275970Scy nread += len; 355275970Scy if (nread == 65000) { 356275970Scy bufferevent_disable(bev, EV_READ); 357275970Scy test_ok++; 358275970Scy } 359275970Scy 360275970Scy evbuffer_free(evbuf); 361275970Scy} 362275970Scy 363275970Scystatic void 364275970Scywm_writecb(struct bufferevent *bev, void *arg) 365275970Scy{ 366275970Scy assert(evbuffer_get_length(bev->output) <= 100); 367275970Scy if (evbuffer_get_length(bev->output) == 0) { 368275970Scy evbuffer_drain(bev->output, evbuffer_get_length(bev->output)); 369275970Scy test_ok++; 370275970Scy } 371275970Scy} 372275970Scy 373275970Scystatic void 374275970Scywm_errorcb(struct bufferevent *bev, short what, void *arg) 375275970Scy{ 376275970Scy test_ok = -2; 377275970Scy} 378275970Scy 379275970Scystatic void 380275970Scytest_bufferevent_watermarks_impl(int use_pair) 381275970Scy{ 382275970Scy struct bufferevent *bev1 = NULL, *bev2 = NULL; 383275970Scy char buffer[65000]; 384275970Scy size_t low, high; 385275970Scy int i; 386275970Scy test_ok = 0; 387275970Scy 388275970Scy if (use_pair) { 389275970Scy struct bufferevent *pair[2]; 390275970Scy tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 391275970Scy bev1 = pair[0]; 392275970Scy bev2 = pair[1]; 393275970Scy bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL); 394275970Scy bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL); 395275970Scy } else { 396275970Scy bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL); 397275970Scy bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL); 398275970Scy } 399275970Scy tt_assert(bev1); 400275970Scy tt_assert(bev2); 401275970Scy bufferevent_disable(bev1, EV_READ); 402275970Scy bufferevent_enable(bev2, EV_READ); 403275970Scy 404275970Scy /* By default, low watermarks are set to 0 */ 405275970Scy bufferevent_getwatermark(bev1, EV_READ, &low, NULL); 406275970Scy tt_int_op(low, ==, 0); 407275970Scy bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL); 408275970Scy tt_int_op(low, ==, 0); 409275970Scy 410275970Scy for (i = 0; i < (int)sizeof(buffer); i++) 411275970Scy buffer[i] = (char)i; 412275970Scy 413275970Scy /* limit the reading on the receiving bufferevent */ 414275970Scy bufferevent_setwatermark(bev2, EV_READ, 10, 20); 415275970Scy 416275970Scy bufferevent_getwatermark(bev2, EV_READ, &low, &high); 417275970Scy tt_int_op(low, ==, 10); 418275970Scy tt_int_op(high, ==, 20); 419275970Scy 420275970Scy /* Tell the sending bufferevent not to notify us till it's down to 421275970Scy 100 bytes. */ 422275970Scy bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); 423275970Scy 424275970Scy bufferevent_getwatermark(bev1, EV_WRITE, &low, &high); 425275970Scy tt_int_op(low, ==, 100); 426275970Scy tt_int_op(high, ==, 2000); 427275970Scy 428282408Scy { 429282408Scy int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high); 430282408Scy tt_int_op(r, !=, 0); 431282408Scy } 432282408Scy 433275970Scy bufferevent_write(bev1, buffer, sizeof(buffer)); 434275970Scy 435275970Scy event_dispatch(); 436275970Scy 437275970Scy tt_int_op(test_ok, ==, 2); 438275970Scy 439275970Scy /* The write callback drained all the data from outbuf, so we 440275970Scy * should have removed the write event... */ 441275970Scy tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL)); 442275970Scy 443275970Scyend: 444275970Scy if (bev1) 445275970Scy bufferevent_free(bev1); 446275970Scy if (bev2) 447275970Scy bufferevent_free(bev2); 448275970Scy} 449275970Scy 450275970Scystatic void 451275970Scytest_bufferevent_watermarks(void) 452275970Scy{ 453275970Scy test_bufferevent_watermarks_impl(0); 454275970Scy} 455275970Scy 456275970Scystatic void 457275970Scytest_bufferevent_pair_watermarks(void) 458275970Scy{ 459275970Scy test_bufferevent_watermarks_impl(1); 460275970Scy} 461275970Scy 462275970Scy/* 463275970Scy * Test bufferevent filters 464275970Scy */ 465275970Scy 466275970Scy/* strip an 'x' from each byte */ 467275970Scy 468275970Scystatic enum bufferevent_filter_result 469275970Scybufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst, 470275970Scy ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 471275970Scy{ 472275970Scy const unsigned char *buffer; 473275970Scy unsigned i; 474275970Scy 475275970Scy buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 476275970Scy for (i = 0; i < evbuffer_get_length(src); i += 2) { 477275970Scy assert(buffer[i] == 'x'); 478275970Scy evbuffer_add(dst, buffer + i + 1, 1); 479275970Scy 480275970Scy if (i + 2 > evbuffer_get_length(src)) 481275970Scy break; 482275970Scy } 483275970Scy 484275970Scy evbuffer_drain(src, i); 485275970Scy return (BEV_OK); 486275970Scy} 487275970Scy 488275970Scy/* add an 'x' before each byte */ 489275970Scy 490275970Scystatic enum bufferevent_filter_result 491275970Scybufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst, 492275970Scy ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 493275970Scy{ 494275970Scy const unsigned char *buffer; 495275970Scy unsigned i; 496275970Scy 497275970Scy buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 498275970Scy for (i = 0; i < evbuffer_get_length(src); ++i) { 499275970Scy evbuffer_add(dst, "x", 1); 500275970Scy evbuffer_add(dst, buffer + i, 1); 501275970Scy } 502275970Scy 503275970Scy evbuffer_drain(src, evbuffer_get_length(src)); 504275970Scy return (BEV_OK); 505275970Scy} 506275970Scy 507275970Scystatic void 508275970Scytest_bufferevent_filters_impl(int use_pair) 509275970Scy{ 510275970Scy struct bufferevent *bev1 = NULL, *bev2 = NULL; 511275970Scy struct bufferevent *bev1_base = NULL, *bev2_base = NULL; 512275970Scy char buffer[8333]; 513275970Scy int i; 514275970Scy 515275970Scy test_ok = 0; 516275970Scy 517275970Scy if (use_pair) { 518275970Scy struct bufferevent *pair[2]; 519275970Scy tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 520275970Scy bev1 = pair[0]; 521275970Scy bev2 = pair[1]; 522275970Scy } else { 523275970Scy bev1 = bufferevent_socket_new(NULL, pair[0], 0); 524275970Scy bev2 = bufferevent_socket_new(NULL, pair[1], 0); 525275970Scy } 526275970Scy bev1_base = bev1; 527275970Scy bev2_base = bev2; 528275970Scy 529275970Scy for (i = 0; i < (int)sizeof(buffer); i++) 530275970Scy buffer[i] = i; 531275970Scy 532275970Scy bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter, 533275970Scy BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 534275970Scy 535275970Scy bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter, 536275970Scy NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 537275970Scy bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL); 538275970Scy bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL); 539275970Scy 540275970Scy tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base); 541275970Scy tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base); 542275970Scy tt_int_op(bufferevent_getfd(bev1), ==, -1); 543275970Scy tt_int_op(bufferevent_getfd(bev2), ==, -1); 544275970Scy 545275970Scy bufferevent_disable(bev1, EV_READ); 546275970Scy bufferevent_enable(bev2, EV_READ); 547275970Scy /* insert some filters */ 548275970Scy bufferevent_write(bev1, buffer, sizeof(buffer)); 549275970Scy 550275970Scy event_dispatch(); 551275970Scy 552275970Scy if (test_ok != 2) 553275970Scy test_ok = 0; 554275970Scy 555275970Scyend: 556275970Scy if (bev1) 557275970Scy bufferevent_free(bev1); 558275970Scy if (bev2) 559275970Scy bufferevent_free(bev2); 560275970Scy 561275970Scy} 562275970Scy 563275970Scystatic void 564275970Scytest_bufferevent_filters(void) 565275970Scy{ 566275970Scy test_bufferevent_filters_impl(0); 567275970Scy} 568275970Scy 569275970Scystatic void 570275970Scytest_bufferevent_pair_filters(void) 571275970Scy{ 572275970Scy test_bufferevent_filters_impl(1); 573275970Scy} 574275970Scy 575275970Scy 576275970Scystatic void 577275970Scysender_writecb(struct bufferevent *bev, void *ctx) 578275970Scy{ 579275970Scy if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { 580275970Scy bufferevent_disable(bev,EV_READ|EV_WRITE); 581275970Scy TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev))); 582275970Scy bufferevent_free(bev); 583275970Scy } 584275970Scy} 585275970Scy 586275970Scystatic void 587275970Scysender_errorcb(struct bufferevent *bev, short what, void *ctx) 588275970Scy{ 589275970Scy TT_FAIL(("Got sender error %d",(int)what)); 590275970Scy} 591275970Scy 592275970Scystatic int bufferevent_connect_test_flags = 0; 593275970Scystatic int bufferevent_trigger_test_flags = 0; 594275970Scystatic int n_strings_read = 0; 595275970Scystatic int n_reads_invoked = 0; 596275970Scy 597275970Scy#define TEST_STR "Now is the time for all good events to signal for " \ 598275970Scy "the good of their protocol" 599275970Scystatic void 600275970Scylisten_cb(struct evconnlistener *listener, evutil_socket_t fd, 601275970Scy struct sockaddr *sa, int socklen, void *arg) 602275970Scy{ 603275970Scy struct event_base *base = arg; 604275970Scy struct bufferevent *bev; 605275970Scy const char s[] = TEST_STR; 606275970Scy TT_BLATHER(("Got a request on socket %d", (int)fd )); 607275970Scy bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags); 608275970Scy tt_assert(bev); 609275970Scy bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL); 610275970Scy bufferevent_write(bev, s, sizeof(s)); 611275970Scyend: 612275970Scy ; 613275970Scy} 614275970Scy 615275970Scystatic void 616275970Scyreader_eventcb(struct bufferevent *bev, short what, void *ctx) 617275970Scy{ 618275970Scy struct event_base *base = ctx; 619275970Scy if (what & BEV_EVENT_ERROR) { 620275970Scy perror("foobar"); 621275970Scy TT_FAIL(("got connector error %d", (int)what)); 622275970Scy return; 623275970Scy } 624275970Scy if (what & BEV_EVENT_CONNECTED) { 625275970Scy TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev))); 626275970Scy bufferevent_enable(bev, EV_READ); 627275970Scy } 628275970Scy if (what & BEV_EVENT_EOF) { 629275970Scy char buf[512]; 630275970Scy size_t n; 631275970Scy n = bufferevent_read(bev, buf, sizeof(buf)-1); 632275970Scy tt_int_op(n, >=, 0); 633275970Scy buf[n] = '\0'; 634275970Scy tt_str_op(buf, ==, TEST_STR); 635275970Scy if (++n_strings_read == 2) 636275970Scy event_base_loopexit(base, NULL); 637275970Scy TT_BLATHER(("EOF on %d: %d strings read.", 638275970Scy (int)bufferevent_getfd(bev), n_strings_read)); 639275970Scy } 640275970Scyend: 641275970Scy ; 642275970Scy} 643275970Scy 644275970Scystatic void 645275970Scyreader_readcb(struct bufferevent *bev, void *ctx) 646275970Scy{ 647275970Scy TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 648275970Scy n_reads_invoked++; 649275970Scy} 650275970Scy 651275970Scystatic void 652275970Scytest_bufferevent_connect(void *arg) 653275970Scy{ 654275970Scy struct basic_test_data *data = arg; 655275970Scy struct evconnlistener *lev=NULL; 656275970Scy struct bufferevent *bev1=NULL, *bev2=NULL; 657275970Scy struct sockaddr_in localhost; 658275970Scy struct sockaddr_storage ss; 659275970Scy struct sockaddr *sa; 660275970Scy ev_socklen_t slen; 661275970Scy 662275970Scy int be_flags=BEV_OPT_CLOSE_ON_FREE; 663275970Scy 664275970Scy if (strstr((char*)data->setup_data, "defer")) { 665275970Scy be_flags |= BEV_OPT_DEFER_CALLBACKS; 666275970Scy } 667275970Scy if (strstr((char*)data->setup_data, "unlocked")) { 668275970Scy be_flags |= BEV_OPT_UNLOCK_CALLBACKS; 669275970Scy } 670275970Scy if (strstr((char*)data->setup_data, "lock")) { 671275970Scy be_flags |= BEV_OPT_THREADSAFE; 672275970Scy } 673275970Scy bufferevent_connect_test_flags = be_flags; 674275970Scy#ifdef _WIN32 675275970Scy if (!strcmp((char*)data->setup_data, "unset_connectex")) { 676275970Scy struct win32_extension_fns *ext = 677275970Scy (struct win32_extension_fns *) 678275970Scy event_get_win32_extension_fns_(); 679275970Scy ext->ConnectEx = NULL; 680275970Scy } 681275970Scy#endif 682275970Scy 683275970Scy memset(&localhost, 0, sizeof(localhost)); 684275970Scy 685275970Scy localhost.sin_port = 0; /* pick-a-port */ 686275970Scy localhost.sin_addr.s_addr = htonl(0x7f000001L); 687275970Scy localhost.sin_family = AF_INET; 688275970Scy sa = (struct sockaddr *)&localhost; 689275970Scy lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 690275970Scy LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 691275970Scy 16, sa, sizeof(localhost)); 692275970Scy tt_assert(lev); 693275970Scy 694275970Scy sa = (struct sockaddr *)&ss; 695275970Scy slen = sizeof(ss); 696275970Scy if (regress_get_listener_addr(lev, sa, &slen) < 0) { 697275970Scy tt_abort_perror("getsockname"); 698275970Scy } 699275970Scy 700275970Scy tt_assert(!evconnlistener_enable(lev)); 701275970Scy bev1 = bufferevent_socket_new(data->base, -1, be_flags); 702275970Scy bev2 = bufferevent_socket_new(data->base, -1, be_flags); 703275970Scy tt_assert(bev1); 704275970Scy tt_assert(bev2); 705275970Scy bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base); 706275970Scy bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base); 707275970Scy 708275970Scy bufferevent_enable(bev1, EV_READ); 709275970Scy bufferevent_enable(bev2, EV_READ); 710275970Scy 711275970Scy tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost))); 712275970Scy tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost))); 713275970Scy 714275970Scy event_base_dispatch(data->base); 715275970Scy 716275970Scy tt_int_op(n_strings_read, ==, 2); 717275970Scy tt_int_op(n_reads_invoked, >=, 2); 718275970Scyend: 719275970Scy if (lev) 720275970Scy evconnlistener_free(lev); 721275970Scy 722275970Scy if (bev1) 723275970Scy bufferevent_free(bev1); 724275970Scy 725275970Scy if (bev2) 726275970Scy bufferevent_free(bev2); 727275970Scy} 728275970Scy 729275970Scystatic void 730275970Scywant_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 731275970Scy{ 732275970Scy struct event_base *base = ctx; 733275970Scy const char *err; 734275970Scy evutil_socket_t s; 735275970Scy 736275970Scy if (what & BEV_EVENT_ERROR) { 737275970Scy s = bufferevent_getfd(bev); 738275970Scy err = evutil_socket_error_to_string(evutil_socket_geterror(s)); 739275970Scy TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s", 740275970Scy EV_SOCK_ARG(s), err)); 741275970Scy test_ok = 1; 742275970Scy } else { 743275970Scy TT_FAIL(("didn't fail? what %hd", what)); 744275970Scy } 745275970Scy 746275970Scy event_base_loopexit(base, NULL); 747275970Scy} 748275970Scy 749275970Scystatic void 750275970Scyclose_socket_cb(evutil_socket_t fd, short what, void *arg) 751275970Scy{ 752275970Scy evutil_socket_t *fdp = arg; 753275970Scy if (*fdp >= 0) { 754275970Scy evutil_closesocket(*fdp); 755275970Scy *fdp = -1; 756275970Scy } 757275970Scy} 758275970Scy 759275970Scystatic void 760275970Scytest_bufferevent_connect_fail(void *arg) 761275970Scy{ 762275970Scy struct basic_test_data *data = (struct basic_test_data *)arg; 763275970Scy struct bufferevent *bev=NULL; 764275970Scy struct sockaddr_in localhost; 765275970Scy struct sockaddr *sa = (struct sockaddr*)&localhost; 766275970Scy evutil_socket_t fake_listener = -1; 767275970Scy ev_socklen_t slen = sizeof(localhost); 768275970Scy struct event close_listener_event; 769275970Scy int close_listener_event_added = 0; 770275970Scy struct timeval one_second = { 1, 0 }; 771275970Scy int r; 772275970Scy 773275970Scy test_ok = 0; 774275970Scy 775275970Scy memset(&localhost, 0, sizeof(localhost)); 776275970Scy localhost.sin_port = 0; /* have the kernel pick a port */ 777275970Scy localhost.sin_addr.s_addr = htonl(0x7f000001L); 778275970Scy localhost.sin_family = AF_INET; 779275970Scy 780275970Scy /* bind, but don't listen or accept. should trigger 781275970Scy "Connection refused" reliably on most platforms. */ 782275970Scy fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0); 783275970Scy tt_assert(fake_listener >= 0); 784275970Scy tt_assert(bind(fake_listener, sa, slen) == 0); 785275970Scy tt_assert(getsockname(fake_listener, sa, &slen) == 0); 786275970Scy bev = bufferevent_socket_new(data->base, -1, 787275970Scy BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 788275970Scy tt_assert(bev); 789275970Scy bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 790275970Scy 791275970Scy r = bufferevent_socket_connect(bev, sa, slen); 792275970Scy /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 793275970Scy * detects the error immediately, which is not really wrong of it. */ 794275970Scy tt_want(r == 0 || r == -1); 795275970Scy 796275970Scy /* Close the listener socket after a second. This should trigger 797275970Scy "connection refused" on some other platforms, including OSX. */ 798275970Scy evtimer_assign(&close_listener_event, data->base, close_socket_cb, 799275970Scy &fake_listener); 800275970Scy event_add(&close_listener_event, &one_second); 801275970Scy close_listener_event_added = 1; 802275970Scy 803275970Scy event_base_dispatch(data->base); 804275970Scy 805275970Scy tt_int_op(test_ok, ==, 1); 806275970Scy 807275970Scyend: 808275970Scy if (fake_listener >= 0) 809275970Scy evutil_closesocket(fake_listener); 810275970Scy 811275970Scy if (bev) 812275970Scy bufferevent_free(bev); 813275970Scy 814275970Scy if (close_listener_event_added) 815275970Scy event_del(&close_listener_event); 816275970Scy} 817275970Scy 818275970Scystruct timeout_cb_result { 819275970Scy struct timeval read_timeout_at; 820275970Scy struct timeval write_timeout_at; 821275970Scy struct timeval last_wrote_at; 822275970Scy int n_read_timeouts; 823275970Scy int n_write_timeouts; 824275970Scy int total_calls; 825275970Scy}; 826275970Scy 827275970Scystatic void 828275970Scybev_timeout_write_cb(struct bufferevent *bev, void *arg) 829275970Scy{ 830275970Scy struct timeout_cb_result *res = arg; 831275970Scy evutil_gettimeofday(&res->last_wrote_at, NULL); 832275970Scy} 833275970Scy 834275970Scystatic void 835275970Scybev_timeout_event_cb(struct bufferevent *bev, short what, void *arg) 836275970Scy{ 837275970Scy struct timeout_cb_result *res = arg; 838275970Scy ++res->total_calls; 839275970Scy 840275970Scy if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) 841275970Scy == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) { 842275970Scy evutil_gettimeofday(&res->read_timeout_at, NULL); 843275970Scy ++res->n_read_timeouts; 844275970Scy } 845275970Scy if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) 846275970Scy == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) { 847275970Scy evutil_gettimeofday(&res->write_timeout_at, NULL); 848275970Scy ++res->n_write_timeouts; 849275970Scy } 850275970Scy} 851275970Scy 852275970Scystatic void 853275970Scytest_bufferevent_timeouts(void *arg) 854275970Scy{ 855275970Scy /* "arg" is a string containing "pair" and/or "filter". */ 856275970Scy struct bufferevent *bev1 = NULL, *bev2 = NULL; 857275970Scy struct basic_test_data *data = arg; 858275970Scy int use_pair = 0, use_filter = 0; 859275970Scy struct timeval tv_w, tv_r, started_at; 860275970Scy struct timeout_cb_result res1, res2; 861275970Scy char buf[1024]; 862275970Scy 863275970Scy memset(&res1, 0, sizeof(res1)); 864275970Scy memset(&res2, 0, sizeof(res2)); 865275970Scy 866275970Scy if (strstr((char*)data->setup_data, "pair")) 867275970Scy use_pair = 1; 868275970Scy if (strstr((char*)data->setup_data, "filter")) 869275970Scy use_filter = 1; 870275970Scy 871275970Scy if (use_pair) { 872275970Scy struct bufferevent *p[2]; 873275970Scy tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p)); 874275970Scy bev1 = p[0]; 875275970Scy bev2 = p[1]; 876275970Scy } else { 877275970Scy bev1 = bufferevent_socket_new(data->base, data->pair[0], 0); 878275970Scy bev2 = bufferevent_socket_new(data->base, data->pair[1], 0); 879275970Scy } 880275970Scy 881275970Scy tt_assert(bev1); 882275970Scy tt_assert(bev2); 883275970Scy 884275970Scy if (use_filter) { 885275970Scy struct bufferevent *bevf1, *bevf2; 886275970Scy bevf1 = bufferevent_filter_new(bev1, NULL, NULL, 887275970Scy BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 888275970Scy bevf2 = bufferevent_filter_new(bev2, NULL, NULL, 889275970Scy BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 890275970Scy tt_assert(bevf1); 891275970Scy tt_assert(bevf2); 892275970Scy bev1 = bevf1; 893275970Scy bev2 = bevf2; 894275970Scy } 895275970Scy 896275970Scy /* Do this nice and early. */ 897275970Scy bufferevent_disable(bev2, EV_READ); 898275970Scy 899275970Scy /* bev1 will try to write and read. Both will time out. */ 900275970Scy evutil_gettimeofday(&started_at, NULL); 901275970Scy tv_w.tv_sec = tv_r.tv_sec = 0; 902275970Scy tv_w.tv_usec = 100*1000; 903275970Scy tv_r.tv_usec = 150*1000; 904275970Scy bufferevent_setcb(bev1, NULL, bev_timeout_write_cb, 905275970Scy bev_timeout_event_cb, &res1); 906275970Scy bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0); 907275970Scy bufferevent_set_timeouts(bev1, &tv_r, &tv_w); 908275970Scy if (use_pair) { 909275970Scy /* For a pair, the fact that the other side isn't reading 910275970Scy * makes the writer stall */ 911275970Scy bufferevent_write(bev1, "ABCDEFG", 7); 912275970Scy } else { 913275970Scy /* For a real socket, the kernel's TCP buffers can eat a 914275970Scy * fair number of bytes; make sure that at some point we 915275970Scy * have some bytes that will stall. */ 916275970Scy struct evbuffer *output = bufferevent_get_output(bev1); 917275970Scy int i; 918275970Scy memset(buf, 0xbb, sizeof(buf)); 919275970Scy for (i=0;i<1024;++i) { 920275970Scy evbuffer_add_reference(output, buf, sizeof(buf), 921275970Scy NULL, NULL); 922275970Scy } 923275970Scy } 924275970Scy bufferevent_enable(bev1, EV_READ|EV_WRITE); 925275970Scy 926275970Scy /* bev2 has nothing to say, and isn't listening. */ 927275970Scy bufferevent_setcb(bev2, NULL, bev_timeout_write_cb, 928275970Scy bev_timeout_event_cb, &res2); 929275970Scy tv_w.tv_sec = tv_r.tv_sec = 0; 930275970Scy tv_w.tv_usec = 200*1000; 931275970Scy tv_r.tv_usec = 100*1000; 932275970Scy bufferevent_set_timeouts(bev2, &tv_r, &tv_w); 933275970Scy bufferevent_enable(bev2, EV_WRITE); 934275970Scy 935275970Scy tv_r.tv_sec = 0; 936275970Scy tv_r.tv_usec = 350000; 937275970Scy 938275970Scy event_base_loopexit(data->base, &tv_r); 939275970Scy event_base_dispatch(data->base); 940275970Scy 941275970Scy /* XXXX Test that actually reading or writing a little resets the 942275970Scy * timeouts. */ 943275970Scy 944275970Scy /* Each buf1 timeout happens, and happens only once. */ 945275970Scy tt_want(res1.n_read_timeouts); 946275970Scy tt_want(res1.n_write_timeouts); 947275970Scy tt_want(res1.n_read_timeouts == 1); 948275970Scy tt_want(res1.n_write_timeouts == 1); 949275970Scy 950275970Scy test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150); 951275970Scy test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100); 952275970Scy 953275970Scyend: 954275970Scy if (bev1) 955275970Scy bufferevent_free(bev1); 956275970Scy if (bev2) 957275970Scy bufferevent_free(bev2); 958275970Scy} 959275970Scy 960275970Scystatic void 961275970Scytrigger_failure_cb(evutil_socket_t fd, short what, void *ctx) 962275970Scy{ 963275970Scy TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout).")); 964275970Scy} 965275970Scy 966275970Scystatic void 967275970Scytrigger_eventcb(struct bufferevent *bev, short what, void *ctx) 968275970Scy{ 969275970Scy struct event_base *base = ctx; 970275970Scy if (what == ~0) { 971275970Scy TT_BLATHER(("Event successfully triggered.")); 972275970Scy event_base_loopexit(base, NULL); 973275970Scy return; 974275970Scy } 975275970Scy reader_eventcb(bev, what, ctx); 976275970Scy} 977275970Scy 978275970Scystatic void 979275970Scytrigger_readcb_triggered(struct bufferevent *bev, void *ctx) 980275970Scy{ 981275970Scy TT_BLATHER(("Read successfully triggered.")); 982275970Scy n_reads_invoked++; 983275970Scy bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags); 984275970Scy} 985275970Scy 986275970Scystatic void 987275970Scytrigger_readcb(struct bufferevent *bev, void *ctx) 988275970Scy{ 989275970Scy struct timeval timeout = { 30, 0 }; 990275970Scy struct event_base *base = ctx; 991275970Scy size_t low, high, len; 992275970Scy int expected_reads; 993275970Scy 994275970Scy TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 995275970Scy expected_reads = ++n_reads_invoked; 996275970Scy 997275970Scy bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx); 998275970Scy 999275970Scy bufferevent_getwatermark(bev, EV_READ, &low, &high); 1000275970Scy len = evbuffer_get_length(bufferevent_get_input(bev)); 1001275970Scy 1002275970Scy bufferevent_setwatermark(bev, EV_READ, len + 1, 0); 1003275970Scy bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags); 1004275970Scy /* no callback expected */ 1005275970Scy tt_int_op(n_reads_invoked, ==, expected_reads); 1006275970Scy 1007275970Scy if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) || 1008275970Scy (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) { 1009275970Scy /* will be deferred */ 1010275970Scy } else { 1011275970Scy expected_reads++; 1012275970Scy } 1013275970Scy 1014275970Scy event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout); 1015275970Scy 1016275970Scy bufferevent_trigger(bev, EV_READ, 1017275970Scy bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS); 1018275970Scy tt_int_op(n_reads_invoked, ==, expected_reads); 1019275970Scy 1020275970Scy bufferevent_setwatermark(bev, EV_READ, low, high); 1021275970Scyend: 1022275970Scy ; 1023275970Scy} 1024275970Scy 1025275970Scystatic void 1026275970Scytest_bufferevent_trigger(void *arg) 1027275970Scy{ 1028275970Scy struct basic_test_data *data = arg; 1029275970Scy struct evconnlistener *lev=NULL; 1030275970Scy struct bufferevent *bev=NULL; 1031275970Scy struct sockaddr_in localhost; 1032275970Scy struct sockaddr_storage ss; 1033275970Scy struct sockaddr *sa; 1034275970Scy ev_socklen_t slen; 1035275970Scy 1036275970Scy int be_flags=BEV_OPT_CLOSE_ON_FREE; 1037275970Scy int trig_flags=0; 1038275970Scy 1039275970Scy if (strstr((char*)data->setup_data, "defer")) { 1040275970Scy be_flags |= BEV_OPT_DEFER_CALLBACKS; 1041275970Scy } 1042275970Scy bufferevent_connect_test_flags = be_flags; 1043275970Scy 1044275970Scy if (strstr((char*)data->setup_data, "postpone")) { 1045275970Scy trig_flags |= BEV_TRIG_DEFER_CALLBACKS; 1046275970Scy } 1047275970Scy bufferevent_trigger_test_flags = trig_flags; 1048275970Scy 1049275970Scy memset(&localhost, 0, sizeof(localhost)); 1050275970Scy 1051275970Scy localhost.sin_port = 0; /* pick-a-port */ 1052275970Scy localhost.sin_addr.s_addr = htonl(0x7f000001L); 1053275970Scy localhost.sin_family = AF_INET; 1054275970Scy sa = (struct sockaddr *)&localhost; 1055275970Scy lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 1056275970Scy LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 1057275970Scy 16, sa, sizeof(localhost)); 1058275970Scy tt_assert(lev); 1059275970Scy 1060275970Scy sa = (struct sockaddr *)&ss; 1061275970Scy slen = sizeof(ss); 1062275970Scy if (regress_get_listener_addr(lev, sa, &slen) < 0) { 1063275970Scy tt_abort_perror("getsockname"); 1064275970Scy } 1065275970Scy 1066275970Scy tt_assert(!evconnlistener_enable(lev)); 1067275970Scy bev = bufferevent_socket_new(data->base, -1, be_flags); 1068275970Scy tt_assert(bev); 1069275970Scy bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base); 1070275970Scy 1071275970Scy bufferevent_enable(bev, EV_READ); 1072275970Scy 1073275970Scy tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost))); 1074275970Scy 1075275970Scy event_base_dispatch(data->base); 1076275970Scy 1077275970Scy tt_int_op(n_reads_invoked, ==, 2); 1078275970Scyend: 1079275970Scy if (lev) 1080275970Scy evconnlistener_free(lev); 1081275970Scy 1082275970Scy if (bev) 1083275970Scy bufferevent_free(bev); 1084275970Scy} 1085275970Scy 1086275970Scystruct testcase_t bufferevent_testcases[] = { 1087275970Scy 1088275970Scy LEGACY(bufferevent, TT_ISOLATED), 1089275970Scy LEGACY(bufferevent_pair, TT_ISOLATED), 1090282408Scy#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) 1091282408Scy { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, 1092282408Scy TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY, 1093282408Scy &basic_setup, NULL }, 1094282408Scy#endif 1095275970Scy LEGACY(bufferevent_watermarks, TT_ISOLATED), 1096275970Scy LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), 1097275970Scy LEGACY(bufferevent_filters, TT_ISOLATED), 1098275970Scy LEGACY(bufferevent_pair_filters, TT_ISOLATED), 1099275970Scy { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE, 1100275970Scy &basic_setup, (void*)"" }, 1101275970Scy { "bufferevent_connect_defer", test_bufferevent_connect, 1102275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 1103275970Scy { "bufferevent_connect_lock", test_bufferevent_connect, 1104275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" }, 1105275970Scy { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1106275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1107275970Scy (void*)"defer lock" }, 1108275970Scy { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect, 1109275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1110275970Scy (void*)"lock defer unlocked" }, 1111275970Scy { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1112275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1113275970Scy { "bufferevent_timeout", test_bufferevent_timeouts, 1114275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" }, 1115275970Scy { "bufferevent_timeout_pair", test_bufferevent_timeouts, 1116275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" }, 1117275970Scy { "bufferevent_timeout_filter", test_bufferevent_timeouts, 1118275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" }, 1119275970Scy { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts, 1120275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" }, 1121275970Scy { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE, 1122275970Scy &basic_setup, (void*)"" }, 1123275970Scy { "bufferevent_trigger_defer", test_bufferevent_trigger, 1124275970Scy TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 1125275970Scy { "bufferevent_trigger_postpone", test_bufferevent_trigger, 1126275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1127275970Scy (void*)"postpone" }, 1128275970Scy { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger, 1129275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1130275970Scy (void*)"defer postpone" }, 1131275970Scy#ifdef EVENT__HAVE_LIBZ 1132275970Scy LEGACY(bufferevent_zlib, TT_ISOLATED), 1133275970Scy#else 1134275970Scy { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, 1135275970Scy#endif 1136275970Scy 1137275970Scy END_OF_TESTCASES, 1138275970Scy}; 1139275970Scy 1140275970Scystruct testcase_t bufferevent_iocp_testcases[] = { 1141275970Scy 1142275970Scy LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP), 1143275970Scy LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP), 1144275970Scy LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP), 1145275970Scy { "bufferevent_connect", test_bufferevent_connect, 1146275970Scy TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" }, 1147275970Scy { "bufferevent_connect_defer", test_bufferevent_connect, 1148275970Scy TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" }, 1149275970Scy { "bufferevent_connect_lock", test_bufferevent_connect, 1150275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 1151275970Scy (void*)"lock" }, 1152275970Scy { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1153275970Scy TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 1154275970Scy (void*)"defer lock" }, 1155275970Scy { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1156275970Scy TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL }, 1157275970Scy { "bufferevent_connect_nonblocking", test_bufferevent_connect, 1158275970Scy TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, 1159275970Scy (void*)"unset_connectex" }, 1160275970Scy 1161275970Scy END_OF_TESTCASES, 1162275970Scy}; 1163