1290001Sglebius/* 2290001Sglebius * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> 3290001Sglebius * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4290001Sglebius * 5290001Sglebius * Redistribution and use in source and binary forms, with or without 6290001Sglebius * modification, are permitted provided that the following conditions 7290001Sglebius * are met: 8290001Sglebius * 1. Redistributions of source code must retain the above copyright 9290001Sglebius * notice, this list of conditions and the following disclaimer. 10290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 11290001Sglebius * notice, this list of conditions and the following disclaimer in the 12290001Sglebius * documentation and/or other materials provided with the distribution. 13290001Sglebius * 3. The name of the author may not be used to endorse or promote products 14290001Sglebius * derived from this software without specific prior written permission. 15290001Sglebius * 16290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26290001Sglebius */ 27290001Sglebius#include "util-internal.h" 28290001Sglebius 29290001Sglebius/* The old tests here need assertions to work. */ 30290001Sglebius#undef NDEBUG 31290001Sglebius 32290001Sglebius#ifdef _WIN32 33290001Sglebius#include <winsock2.h> 34290001Sglebius#include <windows.h> 35290001Sglebius#endif 36290001Sglebius 37290001Sglebius#include "event2/event-config.h" 38290001Sglebius 39290001Sglebius#include <sys/types.h> 40290001Sglebius#include <sys/stat.h> 41290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H 42290001Sglebius#include <sys/time.h> 43290001Sglebius#endif 44290001Sglebius#include <sys/queue.h> 45290001Sglebius#ifndef _WIN32 46290001Sglebius#include <sys/socket.h> 47290001Sglebius#include <sys/wait.h> 48290001Sglebius#include <signal.h> 49290001Sglebius#include <unistd.h> 50290001Sglebius#include <netdb.h> 51290001Sglebius#include <netinet/in.h> 52290001Sglebius#endif 53290001Sglebius#include <fcntl.h> 54290001Sglebius#include <signal.h> 55290001Sglebius#include <stdlib.h> 56290001Sglebius#include <stdio.h> 57290001Sglebius#include <string.h> 58290001Sglebius#include <errno.h> 59290001Sglebius#include <assert.h> 60290001Sglebius 61290001Sglebius#ifdef EVENT__HAVE_ARPA_INET_H 62290001Sglebius#include <arpa/inet.h> 63290001Sglebius#endif 64290001Sglebius 65290001Sglebius#include "event2/event-config.h" 66290001Sglebius#include "event2/event.h" 67290001Sglebius#include "event2/event_struct.h" 68290001Sglebius#include "event2/event_compat.h" 69290001Sglebius#include "event2/tag.h" 70290001Sglebius#include "event2/buffer.h" 71290001Sglebius#include "event2/bufferevent.h" 72290001Sglebius#include "event2/bufferevent_compat.h" 73290001Sglebius#include "event2/bufferevent_struct.h" 74290001Sglebius#include "event2/listener.h" 75290001Sglebius#include "event2/util.h" 76290001Sglebius 77290001Sglebius#include "bufferevent-internal.h" 78290001Sglebius#include "evthread-internal.h" 79290001Sglebius#include "util-internal.h" 80290001Sglebius#ifdef _WIN32 81290001Sglebius#include "iocp-internal.h" 82290001Sglebius#endif 83290001Sglebius 84290001Sglebius#include "regress.h" 85290001Sglebius#include "regress_testutils.h" 86290001Sglebius 87290001Sglebius/* 88290001Sglebius * simple bufferevent test 89290001Sglebius */ 90290001Sglebius 91290001Sglebiusstatic void 92290001Sglebiusreadcb(struct bufferevent *bev, void *arg) 93290001Sglebius{ 94290001Sglebius if (evbuffer_get_length(bev->input) == 8333) { 95290001Sglebius struct evbuffer *evbuf = evbuffer_new(); 96290001Sglebius assert(evbuf != NULL); 97290001Sglebius 98290001Sglebius /* gratuitous test of bufferevent_read_buffer */ 99290001Sglebius bufferevent_read_buffer(bev, evbuf); 100290001Sglebius 101290001Sglebius bufferevent_disable(bev, EV_READ); 102290001Sglebius 103290001Sglebius if (evbuffer_get_length(evbuf) == 8333) { 104290001Sglebius test_ok++; 105290001Sglebius } 106290001Sglebius 107290001Sglebius evbuffer_free(evbuf); 108290001Sglebius } 109290001Sglebius} 110290001Sglebius 111290001Sglebiusstatic void 112290001Sglebiuswritecb(struct bufferevent *bev, void *arg) 113290001Sglebius{ 114290001Sglebius if (evbuffer_get_length(bev->output) == 0) { 115290001Sglebius test_ok++; 116290001Sglebius } 117290001Sglebius} 118290001Sglebius 119290001Sglebiusstatic void 120290001Sglebiuserrorcb(struct bufferevent *bev, short what, void *arg) 121290001Sglebius{ 122290001Sglebius test_ok = -2; 123290001Sglebius} 124290001Sglebius 125290001Sglebiusstatic void 126290001Sglebiustest_bufferevent_impl(int use_pair) 127290001Sglebius{ 128290001Sglebius struct bufferevent *bev1 = NULL, *bev2 = NULL; 129290001Sglebius char buffer[8333]; 130290001Sglebius int i; 131290001Sglebius 132290001Sglebius if (use_pair) { 133290001Sglebius struct bufferevent *pair[2]; 134290001Sglebius tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 135290001Sglebius bev1 = pair[0]; 136290001Sglebius bev2 = pair[1]; 137290001Sglebius bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1); 138290001Sglebius bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); 139290001Sglebius tt_int_op(bufferevent_getfd(bev1), ==, -1); 140290001Sglebius tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 141290001Sglebius tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2); 142290001Sglebius tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1); 143290001Sglebius } else { 144290001Sglebius bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); 145290001Sglebius bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); 146290001Sglebius tt_int_op(bufferevent_getfd(bev1), ==, pair[0]); 147290001Sglebius tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 148290001Sglebius tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 149290001Sglebius tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 150290001Sglebius } 151290001Sglebius 152290001Sglebius { 153290001Sglebius /* Test getcb. */ 154290001Sglebius bufferevent_data_cb r, w; 155290001Sglebius bufferevent_event_cb e; 156290001Sglebius void *a; 157290001Sglebius bufferevent_getcb(bev1, &r, &w, &e, &a); 158290001Sglebius tt_ptr_op(r, ==, readcb); 159290001Sglebius tt_ptr_op(w, ==, writecb); 160290001Sglebius tt_ptr_op(e, ==, errorcb); 161290001Sglebius tt_ptr_op(a, ==, use_pair ? bev1 : NULL); 162290001Sglebius } 163290001Sglebius 164290001Sglebius bufferevent_disable(bev1, EV_READ); 165290001Sglebius bufferevent_enable(bev2, EV_READ); 166290001Sglebius 167290001Sglebius tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE); 168290001Sglebius tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ); 169290001Sglebius 170290001Sglebius for (i = 0; i < (int)sizeof(buffer); i++) 171290001Sglebius buffer[i] = i; 172290001Sglebius 173290001Sglebius bufferevent_write(bev1, buffer, sizeof(buffer)); 174290001Sglebius 175290001Sglebius event_dispatch(); 176290001Sglebius 177290001Sglebius bufferevent_free(bev2); 178290001Sglebius tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 179290001Sglebius bufferevent_free(bev1); 180290001Sglebius 181290001Sglebius if (test_ok != 2) 182290001Sglebius test_ok = 0; 183290001Sglebiusend: 184290001Sglebius ; 185290001Sglebius} 186290001Sglebius 187290001Sglebiusstatic void 188290001Sglebiustest_bufferevent(void) 189290001Sglebius{ 190290001Sglebius test_bufferevent_impl(0); 191290001Sglebius} 192290001Sglebius 193290001Sglebiusstatic void 194290001Sglebiustest_bufferevent_pair(void) 195290001Sglebius{ 196290001Sglebius test_bufferevent_impl(1); 197290001Sglebius} 198290001Sglebius 199290001Sglebius#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) 200290001Sglebius/** 201290001Sglebius * Trace lock/unlock/alloc/free for locks. 202290001Sglebius * (More heavier then evthread_debug*) 203290001Sglebius */ 204290001Sglebiustypedef struct 205290001Sglebius{ 206290001Sglebius void *lock; 207290001Sglebius enum { 208290001Sglebius ALLOC, FREE, 209290001Sglebius } status; 210290001Sglebius size_t locked /** allow recursive locking */; 211290001Sglebius} lock_wrapper; 212290001Sglebiusstruct lock_unlock_base 213290001Sglebius{ 214290001Sglebius /* Original callbacks */ 215290001Sglebius struct evthread_lock_callbacks cbs; 216290001Sglebius /* Map of locks */ 217290001Sglebius lock_wrapper *locks; 218290001Sglebius size_t nr_locks; 219290001Sglebius} lu_base = { 220290001Sglebius .locks = NULL, 221290001Sglebius}; 222290001Sglebius 223290001Sglebiusstatic lock_wrapper *lu_find(void *lock_) 224290001Sglebius{ 225290001Sglebius size_t i; 226290001Sglebius for (i = 0; i < lu_base.nr_locks; ++i) { 227290001Sglebius lock_wrapper *lock = &lu_base.locks[i]; 228290001Sglebius if (lock->lock == lock_) 229290001Sglebius return lock; 230290001Sglebius } 231290001Sglebius return NULL; 232290001Sglebius} 233290001Sglebius 234290001Sglebiusstatic void *trace_lock_alloc(unsigned locktype) 235290001Sglebius{ 236290001Sglebius ++lu_base.nr_locks; 237290001Sglebius lu_base.locks = realloc(lu_base.locks, 238290001Sglebius sizeof(lock_wrapper) * lu_base.nr_locks); 239290001Sglebius void *lock = lu_base.cbs.alloc(locktype); 240290001Sglebius lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 }; 241290001Sglebius return lock; 242290001Sglebius} 243290001Sglebiusstatic void trace_lock_free(void *lock_, unsigned locktype) 244290001Sglebius{ 245290001Sglebius lock_wrapper *lock = lu_find(lock_); 246290001Sglebius if (!lock || lock->status == FREE || lock->locked) { 247290001Sglebius __asm__("int3"); 248290001Sglebius TT_FAIL(("lock: free error")); 249290001Sglebius } else { 250290001Sglebius lock->status = FREE; 251290001Sglebius lu_base.cbs.free(lock_, locktype); 252290001Sglebius } 253290001Sglebius} 254290001Sglebiusstatic int trace_lock_lock(unsigned mode, void *lock_) 255290001Sglebius{ 256290001Sglebius lock_wrapper *lock = lu_find(lock_); 257290001Sglebius if (!lock || lock->status == FREE) { 258290001Sglebius TT_FAIL(("lock: lock error")); 259290001Sglebius return -1; 260290001Sglebius } else { 261290001Sglebius ++lock->locked; 262290001Sglebius return lu_base.cbs.lock(mode, lock_); 263290001Sglebius } 264290001Sglebius} 265290001Sglebiusstatic int trace_lock_unlock(unsigned mode, void *lock_) 266290001Sglebius{ 267290001Sglebius lock_wrapper *lock = lu_find(lock_); 268290001Sglebius if (!lock || lock->status == FREE || !lock->locked) { 269290001Sglebius TT_FAIL(("lock: unlock error")); 270290001Sglebius return -1; 271290001Sglebius } else { 272290001Sglebius --lock->locked; 273290001Sglebius return lu_base.cbs.unlock(mode, lock_); 274290001Sglebius } 275290001Sglebius} 276290001Sglebiusstatic void lock_unlock_free_thread_cbs() 277290001Sglebius{ 278290001Sglebius event_base_free(NULL); 279290001Sglebius 280290001Sglebius /** drop immutable flag */ 281290001Sglebius evthread_set_lock_callbacks(NULL); 282290001Sglebius /** avoid calling of event_global_setup_locks_() for new cbs */ 283290001Sglebius libevent_global_shutdown(); 284290001Sglebius /** drop immutable flag for non-debug ops (since called after shutdown) */ 285290001Sglebius evthread_set_lock_callbacks(NULL); 286290001Sglebius} 287290001Sglebius 288290001Sglebiusstatic int use_lock_unlock_profiler(void) 289290001Sglebius{ 290290001Sglebius struct evthread_lock_callbacks cbs = { 291290001Sglebius EVTHREAD_LOCK_API_VERSION, 292290001Sglebius EVTHREAD_LOCKTYPE_RECURSIVE, 293290001Sglebius trace_lock_alloc, 294290001Sglebius trace_lock_free, 295290001Sglebius trace_lock_lock, 296290001Sglebius trace_lock_unlock, 297290001Sglebius }; 298290001Sglebius memcpy(&lu_base.cbs, evthread_get_lock_callbacks(), 299290001Sglebius sizeof(lu_base.cbs)); 300290001Sglebius { 301290001Sglebius lock_unlock_free_thread_cbs(); 302290001Sglebius 303290001Sglebius evthread_set_lock_callbacks(&cbs); 304290001Sglebius /** re-create debug locks correctly */ 305290001Sglebius evthread_enable_lock_debugging(); 306290001Sglebius 307290001Sglebius event_init(); 308290001Sglebius } 309290001Sglebius return 0; 310290001Sglebius} 311290001Sglebiusstatic void free_lock_unlock_profiler(struct basic_test_data *data) 312290001Sglebius{ 313290001Sglebius lock_unlock_free_thread_cbs(); 314290001Sglebius free(lu_base.locks); 315290001Sglebius data->base = NULL; 316290001Sglebius} 317290001Sglebius 318290001Sglebiusstatic void test_bufferevent_pair_release_lock(void *arg) 319290001Sglebius{ 320290001Sglebius struct basic_test_data *data = arg; 321290001Sglebius use_lock_unlock_profiler(); 322290001Sglebius { 323290001Sglebius struct bufferevent *pair[2]; 324290001Sglebius if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) { 325290001Sglebius bufferevent_free(pair[0]); 326290001Sglebius bufferevent_free(pair[1]); 327290001Sglebius } else 328290001Sglebius tt_abort_perror("bufferevent_pair_new"); 329290001Sglebius } 330290001Sglebius free_lock_unlock_profiler(data); 331290001Sglebiusend: 332290001Sglebius ; 333290001Sglebius} 334290001Sglebius#endif 335290001Sglebius 336290001Sglebius/* 337290001Sglebius * test watermarks and bufferevent 338290001Sglebius */ 339290001Sglebius 340290001Sglebiusstatic void 341290001Sglebiuswm_readcb(struct bufferevent *bev, void *arg) 342290001Sglebius{ 343290001Sglebius struct evbuffer *evbuf = evbuffer_new(); 344290001Sglebius int len = (int)evbuffer_get_length(bev->input); 345290001Sglebius static int nread; 346290001Sglebius 347290001Sglebius assert(len >= 10 && len <= 20); 348290001Sglebius 349290001Sglebius assert(evbuf != NULL); 350290001Sglebius 351290001Sglebius /* gratuitous test of bufferevent_read_buffer */ 352290001Sglebius bufferevent_read_buffer(bev, evbuf); 353290001Sglebius 354290001Sglebius nread += len; 355290001Sglebius if (nread == 65000) { 356290001Sglebius bufferevent_disable(bev, EV_READ); 357290001Sglebius test_ok++; 358290001Sglebius } 359290001Sglebius 360290001Sglebius evbuffer_free(evbuf); 361290001Sglebius} 362290001Sglebius 363290001Sglebiusstatic void 364290001Sglebiuswm_writecb(struct bufferevent *bev, void *arg) 365290001Sglebius{ 366290001Sglebius assert(evbuffer_get_length(bev->output) <= 100); 367290001Sglebius if (evbuffer_get_length(bev->output) == 0) { 368290001Sglebius evbuffer_drain(bev->output, evbuffer_get_length(bev->output)); 369290001Sglebius test_ok++; 370290001Sglebius } 371290001Sglebius} 372290001Sglebius 373290001Sglebiusstatic void 374290001Sglebiuswm_errorcb(struct bufferevent *bev, short what, void *arg) 375290001Sglebius{ 376290001Sglebius test_ok = -2; 377290001Sglebius} 378290001Sglebius 379290001Sglebiusstatic void 380290001Sglebiustest_bufferevent_watermarks_impl(int use_pair) 381290001Sglebius{ 382290001Sglebius struct bufferevent *bev1 = NULL, *bev2 = NULL; 383290001Sglebius char buffer[65000]; 384290001Sglebius size_t low, high; 385290001Sglebius int i; 386290001Sglebius test_ok = 0; 387290001Sglebius 388290001Sglebius if (use_pair) { 389290001Sglebius struct bufferevent *pair[2]; 390290001Sglebius tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 391290001Sglebius bev1 = pair[0]; 392290001Sglebius bev2 = pair[1]; 393290001Sglebius bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL); 394290001Sglebius bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL); 395290001Sglebius } else { 396290001Sglebius bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL); 397290001Sglebius bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL); 398290001Sglebius } 399290001Sglebius tt_assert(bev1); 400290001Sglebius tt_assert(bev2); 401290001Sglebius bufferevent_disable(bev1, EV_READ); 402290001Sglebius bufferevent_enable(bev2, EV_READ); 403290001Sglebius 404290001Sglebius /* By default, low watermarks are set to 0 */ 405290001Sglebius bufferevent_getwatermark(bev1, EV_READ, &low, NULL); 406290001Sglebius tt_int_op(low, ==, 0); 407290001Sglebius bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL); 408290001Sglebius tt_int_op(low, ==, 0); 409290001Sglebius 410290001Sglebius for (i = 0; i < (int)sizeof(buffer); i++) 411290001Sglebius buffer[i] = (char)i; 412290001Sglebius 413290001Sglebius /* limit the reading on the receiving bufferevent */ 414290001Sglebius bufferevent_setwatermark(bev2, EV_READ, 10, 20); 415290001Sglebius 416290001Sglebius bufferevent_getwatermark(bev2, EV_READ, &low, &high); 417290001Sglebius tt_int_op(low, ==, 10); 418290001Sglebius tt_int_op(high, ==, 20); 419290001Sglebius 420290001Sglebius /* Tell the sending bufferevent not to notify us till it's down to 421290001Sglebius 100 bytes. */ 422290001Sglebius bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); 423290001Sglebius 424290001Sglebius bufferevent_getwatermark(bev1, EV_WRITE, &low, &high); 425290001Sglebius tt_int_op(low, ==, 100); 426290001Sglebius tt_int_op(high, ==, 2000); 427290001Sglebius 428290001Sglebius { 429290001Sglebius int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high); 430290001Sglebius tt_int_op(r, !=, 0); 431290001Sglebius } 432290001Sglebius 433290001Sglebius bufferevent_write(bev1, buffer, sizeof(buffer)); 434290001Sglebius 435290001Sglebius event_dispatch(); 436290001Sglebius 437290001Sglebius tt_int_op(test_ok, ==, 2); 438290001Sglebius 439290001Sglebius /* The write callback drained all the data from outbuf, so we 440290001Sglebius * should have removed the write event... */ 441290001Sglebius tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL)); 442290001Sglebius 443290001Sglebiusend: 444290001Sglebius if (bev1) 445290001Sglebius bufferevent_free(bev1); 446290001Sglebius if (bev2) 447290001Sglebius bufferevent_free(bev2); 448290001Sglebius} 449290001Sglebius 450290001Sglebiusstatic void 451290001Sglebiustest_bufferevent_watermarks(void) 452290001Sglebius{ 453290001Sglebius test_bufferevent_watermarks_impl(0); 454290001Sglebius} 455290001Sglebius 456290001Sglebiusstatic void 457290001Sglebiustest_bufferevent_pair_watermarks(void) 458290001Sglebius{ 459290001Sglebius test_bufferevent_watermarks_impl(1); 460290001Sglebius} 461290001Sglebius 462290001Sglebius/* 463290001Sglebius * Test bufferevent filters 464290001Sglebius */ 465290001Sglebius 466290001Sglebius/* strip an 'x' from each byte */ 467290001Sglebius 468290001Sglebiusstatic enum bufferevent_filter_result 469290001Sglebiusbufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst, 470290001Sglebius ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 471290001Sglebius{ 472290001Sglebius const unsigned char *buffer; 473290001Sglebius unsigned i; 474290001Sglebius 475290001Sglebius buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 476290001Sglebius for (i = 0; i < evbuffer_get_length(src); i += 2) { 477290001Sglebius assert(buffer[i] == 'x'); 478290001Sglebius evbuffer_add(dst, buffer + i + 1, 1); 479290001Sglebius 480290001Sglebius if (i + 2 > evbuffer_get_length(src)) 481290001Sglebius break; 482290001Sglebius } 483290001Sglebius 484290001Sglebius evbuffer_drain(src, i); 485290001Sglebius return (BEV_OK); 486290001Sglebius} 487290001Sglebius 488290001Sglebius/* add an 'x' before each byte */ 489290001Sglebius 490290001Sglebiusstatic enum bufferevent_filter_result 491290001Sglebiusbufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst, 492290001Sglebius ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 493290001Sglebius{ 494290001Sglebius const unsigned char *buffer; 495290001Sglebius unsigned i; 496290001Sglebius 497290001Sglebius buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 498290001Sglebius for (i = 0; i < evbuffer_get_length(src); ++i) { 499290001Sglebius evbuffer_add(dst, "x", 1); 500290001Sglebius evbuffer_add(dst, buffer + i, 1); 501290001Sglebius } 502290001Sglebius 503290001Sglebius evbuffer_drain(src, evbuffer_get_length(src)); 504290001Sglebius return (BEV_OK); 505290001Sglebius} 506290001Sglebius 507290001Sglebiusstatic void 508290001Sglebiustest_bufferevent_filters_impl(int use_pair) 509290001Sglebius{ 510290001Sglebius struct bufferevent *bev1 = NULL, *bev2 = NULL; 511290001Sglebius struct bufferevent *bev1_base = NULL, *bev2_base = NULL; 512290001Sglebius char buffer[8333]; 513290001Sglebius int i; 514290001Sglebius 515290001Sglebius test_ok = 0; 516290001Sglebius 517290001Sglebius if (use_pair) { 518290001Sglebius struct bufferevent *pair[2]; 519290001Sglebius tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 520290001Sglebius bev1 = pair[0]; 521290001Sglebius bev2 = pair[1]; 522290001Sglebius } else { 523290001Sglebius bev1 = bufferevent_socket_new(NULL, pair[0], 0); 524290001Sglebius bev2 = bufferevent_socket_new(NULL, pair[1], 0); 525290001Sglebius } 526290001Sglebius bev1_base = bev1; 527290001Sglebius bev2_base = bev2; 528290001Sglebius 529290001Sglebius for (i = 0; i < (int)sizeof(buffer); i++) 530290001Sglebius buffer[i] = i; 531290001Sglebius 532290001Sglebius bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter, 533290001Sglebius BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 534290001Sglebius 535290001Sglebius bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter, 536290001Sglebius NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 537290001Sglebius bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL); 538290001Sglebius bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL); 539290001Sglebius 540290001Sglebius tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base); 541290001Sglebius tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base); 542290001Sglebius tt_int_op(bufferevent_getfd(bev1), ==, -1); 543290001Sglebius tt_int_op(bufferevent_getfd(bev2), ==, -1); 544290001Sglebius 545290001Sglebius bufferevent_disable(bev1, EV_READ); 546290001Sglebius bufferevent_enable(bev2, EV_READ); 547290001Sglebius /* insert some filters */ 548290001Sglebius bufferevent_write(bev1, buffer, sizeof(buffer)); 549290001Sglebius 550290001Sglebius event_dispatch(); 551290001Sglebius 552290001Sglebius if (test_ok != 2) 553290001Sglebius test_ok = 0; 554290001Sglebius 555290001Sglebiusend: 556290001Sglebius if (bev1) 557290001Sglebius bufferevent_free(bev1); 558290001Sglebius if (bev2) 559290001Sglebius bufferevent_free(bev2); 560290001Sglebius 561290001Sglebius} 562290001Sglebius 563290001Sglebiusstatic void 564290001Sglebiustest_bufferevent_filters(void) 565290001Sglebius{ 566290001Sglebius test_bufferevent_filters_impl(0); 567290001Sglebius} 568290001Sglebius 569290001Sglebiusstatic void 570290001Sglebiustest_bufferevent_pair_filters(void) 571290001Sglebius{ 572290001Sglebius test_bufferevent_filters_impl(1); 573290001Sglebius} 574290001Sglebius 575290001Sglebius 576290001Sglebiusstatic void 577290001Sglebiussender_writecb(struct bufferevent *bev, void *ctx) 578290001Sglebius{ 579290001Sglebius if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { 580290001Sglebius bufferevent_disable(bev,EV_READ|EV_WRITE); 581290001Sglebius TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev))); 582290001Sglebius bufferevent_free(bev); 583290001Sglebius } 584290001Sglebius} 585290001Sglebius 586290001Sglebiusstatic void 587290001Sglebiussender_errorcb(struct bufferevent *bev, short what, void *ctx) 588290001Sglebius{ 589290001Sglebius TT_FAIL(("Got sender error %d",(int)what)); 590290001Sglebius} 591290001Sglebius 592290001Sglebiusstatic int bufferevent_connect_test_flags = 0; 593290001Sglebiusstatic int bufferevent_trigger_test_flags = 0; 594290001Sglebiusstatic int n_strings_read = 0; 595290001Sglebiusstatic int n_reads_invoked = 0; 596290001Sglebius 597290001Sglebius#define TEST_STR "Now is the time for all good events to signal for " \ 598290001Sglebius "the good of their protocol" 599290001Sglebiusstatic void 600290001Sglebiuslisten_cb(struct evconnlistener *listener, evutil_socket_t fd, 601290001Sglebius struct sockaddr *sa, int socklen, void *arg) 602290001Sglebius{ 603290001Sglebius struct event_base *base = arg; 604290001Sglebius struct bufferevent *bev; 605290001Sglebius const char s[] = TEST_STR; 606290001Sglebius TT_BLATHER(("Got a request on socket %d", (int)fd )); 607290001Sglebius bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags); 608290001Sglebius tt_assert(bev); 609290001Sglebius bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL); 610290001Sglebius bufferevent_write(bev, s, sizeof(s)); 611290001Sglebiusend: 612290001Sglebius ; 613290001Sglebius} 614290001Sglebius 615290001Sglebiusstatic void 616290001Sglebiusreader_eventcb(struct bufferevent *bev, short what, void *ctx) 617290001Sglebius{ 618290001Sglebius struct event_base *base = ctx; 619290001Sglebius if (what & BEV_EVENT_ERROR) { 620290001Sglebius perror("foobar"); 621290001Sglebius TT_FAIL(("got connector error %d", (int)what)); 622290001Sglebius return; 623290001Sglebius } 624290001Sglebius if (what & BEV_EVENT_CONNECTED) { 625290001Sglebius TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev))); 626290001Sglebius bufferevent_enable(bev, EV_READ); 627290001Sglebius } 628290001Sglebius if (what & BEV_EVENT_EOF) { 629290001Sglebius char buf[512]; 630290001Sglebius size_t n; 631290001Sglebius n = bufferevent_read(bev, buf, sizeof(buf)-1); 632290001Sglebius tt_int_op(n, >=, 0); 633290001Sglebius buf[n] = '\0'; 634290001Sglebius tt_str_op(buf, ==, TEST_STR); 635290001Sglebius if (++n_strings_read == 2) 636290001Sglebius event_base_loopexit(base, NULL); 637290001Sglebius TT_BLATHER(("EOF on %d: %d strings read.", 638290001Sglebius (int)bufferevent_getfd(bev), n_strings_read)); 639290001Sglebius } 640290001Sglebiusend: 641290001Sglebius ; 642290001Sglebius} 643290001Sglebius 644290001Sglebiusstatic void 645290001Sglebiusreader_readcb(struct bufferevent *bev, void *ctx) 646290001Sglebius{ 647290001Sglebius TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 648290001Sglebius n_reads_invoked++; 649290001Sglebius} 650290001Sglebius 651290001Sglebiusstatic void 652290001Sglebiustest_bufferevent_connect(void *arg) 653290001Sglebius{ 654290001Sglebius struct basic_test_data *data = arg; 655290001Sglebius struct evconnlistener *lev=NULL; 656290001Sglebius struct bufferevent *bev1=NULL, *bev2=NULL; 657290001Sglebius struct sockaddr_in localhost; 658290001Sglebius struct sockaddr_storage ss; 659290001Sglebius struct sockaddr *sa; 660290001Sglebius ev_socklen_t slen; 661290001Sglebius 662290001Sglebius int be_flags=BEV_OPT_CLOSE_ON_FREE; 663290001Sglebius 664290001Sglebius if (strstr((char*)data->setup_data, "defer")) { 665290001Sglebius be_flags |= BEV_OPT_DEFER_CALLBACKS; 666290001Sglebius } 667290001Sglebius if (strstr((char*)data->setup_data, "unlocked")) { 668290001Sglebius be_flags |= BEV_OPT_UNLOCK_CALLBACKS; 669290001Sglebius } 670290001Sglebius if (strstr((char*)data->setup_data, "lock")) { 671290001Sglebius be_flags |= BEV_OPT_THREADSAFE; 672290001Sglebius } 673290001Sglebius bufferevent_connect_test_flags = be_flags; 674290001Sglebius#ifdef _WIN32 675290001Sglebius if (!strcmp((char*)data->setup_data, "unset_connectex")) { 676290001Sglebius struct win32_extension_fns *ext = 677290001Sglebius (struct win32_extension_fns *) 678290001Sglebius event_get_win32_extension_fns_(); 679290001Sglebius ext->ConnectEx = NULL; 680290001Sglebius } 681290001Sglebius#endif 682290001Sglebius 683290001Sglebius memset(&localhost, 0, sizeof(localhost)); 684290001Sglebius 685290001Sglebius localhost.sin_port = 0; /* pick-a-port */ 686290001Sglebius localhost.sin_addr.s_addr = htonl(0x7f000001L); 687290001Sglebius localhost.sin_family = AF_INET; 688290001Sglebius sa = (struct sockaddr *)&localhost; 689290001Sglebius lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 690290001Sglebius LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 691290001Sglebius 16, sa, sizeof(localhost)); 692290001Sglebius tt_assert(lev); 693290001Sglebius 694290001Sglebius sa = (struct sockaddr *)&ss; 695290001Sglebius slen = sizeof(ss); 696290001Sglebius if (regress_get_listener_addr(lev, sa, &slen) < 0) { 697290001Sglebius tt_abort_perror("getsockname"); 698290001Sglebius } 699290001Sglebius 700290001Sglebius tt_assert(!evconnlistener_enable(lev)); 701290001Sglebius bev1 = bufferevent_socket_new(data->base, -1, be_flags); 702290001Sglebius bev2 = bufferevent_socket_new(data->base, -1, be_flags); 703290001Sglebius tt_assert(bev1); 704290001Sglebius tt_assert(bev2); 705290001Sglebius bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base); 706290001Sglebius bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base); 707290001Sglebius 708290001Sglebius bufferevent_enable(bev1, EV_READ); 709290001Sglebius bufferevent_enable(bev2, EV_READ); 710290001Sglebius 711290001Sglebius tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost))); 712290001Sglebius tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost))); 713290001Sglebius 714290001Sglebius event_base_dispatch(data->base); 715290001Sglebius 716290001Sglebius tt_int_op(n_strings_read, ==, 2); 717290001Sglebius tt_int_op(n_reads_invoked, >=, 2); 718290001Sglebiusend: 719290001Sglebius if (lev) 720290001Sglebius evconnlistener_free(lev); 721290001Sglebius 722290001Sglebius if (bev1) 723290001Sglebius bufferevent_free(bev1); 724290001Sglebius 725290001Sglebius if (bev2) 726290001Sglebius bufferevent_free(bev2); 727290001Sglebius} 728290001Sglebius 729290001Sglebiusstatic void 730290001Sglebiuswant_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 731290001Sglebius{ 732290001Sglebius struct event_base *base = ctx; 733290001Sglebius const char *err; 734290001Sglebius evutil_socket_t s; 735290001Sglebius 736290001Sglebius if (what & BEV_EVENT_ERROR) { 737290001Sglebius s = bufferevent_getfd(bev); 738290001Sglebius err = evutil_socket_error_to_string(evutil_socket_geterror(s)); 739290001Sglebius TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s", 740290001Sglebius EV_SOCK_ARG(s), err)); 741290001Sglebius test_ok = 1; 742290001Sglebius } else { 743290001Sglebius TT_FAIL(("didn't fail? what %hd", what)); 744290001Sglebius } 745290001Sglebius 746290001Sglebius event_base_loopexit(base, NULL); 747290001Sglebius} 748290001Sglebius 749290001Sglebiusstatic void 750290001Sglebiusclose_socket_cb(evutil_socket_t fd, short what, void *arg) 751290001Sglebius{ 752290001Sglebius evutil_socket_t *fdp = arg; 753290001Sglebius if (*fdp >= 0) { 754290001Sglebius evutil_closesocket(*fdp); 755290001Sglebius *fdp = -1; 756290001Sglebius } 757290001Sglebius} 758290001Sglebius 759290001Sglebiusstatic void 760290001Sglebiustest_bufferevent_connect_fail(void *arg) 761290001Sglebius{ 762290001Sglebius struct basic_test_data *data = (struct basic_test_data *)arg; 763290001Sglebius struct bufferevent *bev=NULL; 764290001Sglebius struct sockaddr_in localhost; 765290001Sglebius struct sockaddr *sa = (struct sockaddr*)&localhost; 766290001Sglebius evutil_socket_t fake_listener = -1; 767290001Sglebius ev_socklen_t slen = sizeof(localhost); 768290001Sglebius struct event close_listener_event; 769290001Sglebius int close_listener_event_added = 0; 770290001Sglebius struct timeval one_second = { 1, 0 }; 771290001Sglebius int r; 772290001Sglebius 773290001Sglebius test_ok = 0; 774290001Sglebius 775290001Sglebius memset(&localhost, 0, sizeof(localhost)); 776290001Sglebius localhost.sin_port = 0; /* have the kernel pick a port */ 777290001Sglebius localhost.sin_addr.s_addr = htonl(0x7f000001L); 778290001Sglebius localhost.sin_family = AF_INET; 779290001Sglebius 780290001Sglebius /* bind, but don't listen or accept. should trigger 781290001Sglebius "Connection refused" reliably on most platforms. */ 782290001Sglebius fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0); 783290001Sglebius tt_assert(fake_listener >= 0); 784290001Sglebius tt_assert(bind(fake_listener, sa, slen) == 0); 785290001Sglebius tt_assert(getsockname(fake_listener, sa, &slen) == 0); 786290001Sglebius bev = bufferevent_socket_new(data->base, -1, 787290001Sglebius BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 788290001Sglebius tt_assert(bev); 789290001Sglebius bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 790290001Sglebius 791290001Sglebius r = bufferevent_socket_connect(bev, sa, slen); 792290001Sglebius /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 793290001Sglebius * detects the error immediately, which is not really wrong of it. */ 794290001Sglebius tt_want(r == 0 || r == -1); 795290001Sglebius 796290001Sglebius /* Close the listener socket after a second. This should trigger 797290001Sglebius "connection refused" on some other platforms, including OSX. */ 798290001Sglebius evtimer_assign(&close_listener_event, data->base, close_socket_cb, 799290001Sglebius &fake_listener); 800290001Sglebius event_add(&close_listener_event, &one_second); 801290001Sglebius close_listener_event_added = 1; 802290001Sglebius 803290001Sglebius event_base_dispatch(data->base); 804290001Sglebius 805290001Sglebius tt_int_op(test_ok, ==, 1); 806290001Sglebius 807290001Sglebiusend: 808290001Sglebius if (fake_listener >= 0) 809290001Sglebius evutil_closesocket(fake_listener); 810290001Sglebius 811290001Sglebius if (bev) 812290001Sglebius bufferevent_free(bev); 813290001Sglebius 814290001Sglebius if (close_listener_event_added) 815290001Sglebius event_del(&close_listener_event); 816290001Sglebius} 817290001Sglebius 818290001Sglebiusstruct timeout_cb_result { 819290001Sglebius struct timeval read_timeout_at; 820290001Sglebius struct timeval write_timeout_at; 821290001Sglebius struct timeval last_wrote_at; 822290001Sglebius int n_read_timeouts; 823290001Sglebius int n_write_timeouts; 824290001Sglebius int total_calls; 825290001Sglebius}; 826290001Sglebius 827290001Sglebiusstatic void 828290001Sglebiusbev_timeout_write_cb(struct bufferevent *bev, void *arg) 829290001Sglebius{ 830290001Sglebius struct timeout_cb_result *res = arg; 831290001Sglebius evutil_gettimeofday(&res->last_wrote_at, NULL); 832290001Sglebius} 833290001Sglebius 834290001Sglebiusstatic void 835290001Sglebiusbev_timeout_event_cb(struct bufferevent *bev, short what, void *arg) 836290001Sglebius{ 837290001Sglebius struct timeout_cb_result *res = arg; 838290001Sglebius ++res->total_calls; 839290001Sglebius 840290001Sglebius if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) 841290001Sglebius == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) { 842290001Sglebius evutil_gettimeofday(&res->read_timeout_at, NULL); 843290001Sglebius ++res->n_read_timeouts; 844290001Sglebius } 845290001Sglebius if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) 846290001Sglebius == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) { 847290001Sglebius evutil_gettimeofday(&res->write_timeout_at, NULL); 848290001Sglebius ++res->n_write_timeouts; 849290001Sglebius } 850290001Sglebius} 851290001Sglebius 852290001Sglebiusstatic void 853290001Sglebiustest_bufferevent_timeouts(void *arg) 854290001Sglebius{ 855290001Sglebius /* "arg" is a string containing "pair" and/or "filter". */ 856290001Sglebius struct bufferevent *bev1 = NULL, *bev2 = NULL; 857290001Sglebius struct basic_test_data *data = arg; 858290001Sglebius int use_pair = 0, use_filter = 0; 859290001Sglebius struct timeval tv_w, tv_r, started_at; 860290001Sglebius struct timeout_cb_result res1, res2; 861290001Sglebius char buf[1024]; 862290001Sglebius 863290001Sglebius memset(&res1, 0, sizeof(res1)); 864290001Sglebius memset(&res2, 0, sizeof(res2)); 865290001Sglebius 866290001Sglebius if (strstr((char*)data->setup_data, "pair")) 867290001Sglebius use_pair = 1; 868290001Sglebius if (strstr((char*)data->setup_data, "filter")) 869290001Sglebius use_filter = 1; 870290001Sglebius 871290001Sglebius if (use_pair) { 872290001Sglebius struct bufferevent *p[2]; 873290001Sglebius tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p)); 874290001Sglebius bev1 = p[0]; 875290001Sglebius bev2 = p[1]; 876290001Sglebius } else { 877290001Sglebius bev1 = bufferevent_socket_new(data->base, data->pair[0], 0); 878290001Sglebius bev2 = bufferevent_socket_new(data->base, data->pair[1], 0); 879290001Sglebius } 880290001Sglebius 881290001Sglebius tt_assert(bev1); 882290001Sglebius tt_assert(bev2); 883290001Sglebius 884290001Sglebius if (use_filter) { 885290001Sglebius struct bufferevent *bevf1, *bevf2; 886290001Sglebius bevf1 = bufferevent_filter_new(bev1, NULL, NULL, 887290001Sglebius BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 888290001Sglebius bevf2 = bufferevent_filter_new(bev2, NULL, NULL, 889290001Sglebius BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 890290001Sglebius tt_assert(bevf1); 891290001Sglebius tt_assert(bevf2); 892290001Sglebius bev1 = bevf1; 893290001Sglebius bev2 = bevf2; 894290001Sglebius } 895290001Sglebius 896290001Sglebius /* Do this nice and early. */ 897290001Sglebius bufferevent_disable(bev2, EV_READ); 898290001Sglebius 899290001Sglebius /* bev1 will try to write and read. Both will time out. */ 900290001Sglebius evutil_gettimeofday(&started_at, NULL); 901290001Sglebius tv_w.tv_sec = tv_r.tv_sec = 0; 902290001Sglebius tv_w.tv_usec = 100*1000; 903290001Sglebius tv_r.tv_usec = 150*1000; 904290001Sglebius bufferevent_setcb(bev1, NULL, bev_timeout_write_cb, 905290001Sglebius bev_timeout_event_cb, &res1); 906290001Sglebius bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0); 907290001Sglebius bufferevent_set_timeouts(bev1, &tv_r, &tv_w); 908290001Sglebius if (use_pair) { 909290001Sglebius /* For a pair, the fact that the other side isn't reading 910290001Sglebius * makes the writer stall */ 911290001Sglebius bufferevent_write(bev1, "ABCDEFG", 7); 912290001Sglebius } else { 913290001Sglebius /* For a real socket, the kernel's TCP buffers can eat a 914290001Sglebius * fair number of bytes; make sure that at some point we 915290001Sglebius * have some bytes that will stall. */ 916290001Sglebius struct evbuffer *output = bufferevent_get_output(bev1); 917290001Sglebius int i; 918290001Sglebius memset(buf, 0xbb, sizeof(buf)); 919290001Sglebius for (i=0;i<1024;++i) { 920290001Sglebius evbuffer_add_reference(output, buf, sizeof(buf), 921290001Sglebius NULL, NULL); 922290001Sglebius } 923290001Sglebius } 924290001Sglebius bufferevent_enable(bev1, EV_READ|EV_WRITE); 925290001Sglebius 926290001Sglebius /* bev2 has nothing to say, and isn't listening. */ 927290001Sglebius bufferevent_setcb(bev2, NULL, bev_timeout_write_cb, 928290001Sglebius bev_timeout_event_cb, &res2); 929290001Sglebius tv_w.tv_sec = tv_r.tv_sec = 0; 930290001Sglebius tv_w.tv_usec = 200*1000; 931290001Sglebius tv_r.tv_usec = 100*1000; 932290001Sglebius bufferevent_set_timeouts(bev2, &tv_r, &tv_w); 933290001Sglebius bufferevent_enable(bev2, EV_WRITE); 934290001Sglebius 935290001Sglebius tv_r.tv_sec = 0; 936290001Sglebius tv_r.tv_usec = 350000; 937290001Sglebius 938290001Sglebius event_base_loopexit(data->base, &tv_r); 939290001Sglebius event_base_dispatch(data->base); 940290001Sglebius 941290001Sglebius /* XXXX Test that actually reading or writing a little resets the 942290001Sglebius * timeouts. */ 943290001Sglebius 944290001Sglebius /* Each buf1 timeout happens, and happens only once. */ 945290001Sglebius tt_want(res1.n_read_timeouts); 946290001Sglebius tt_want(res1.n_write_timeouts); 947290001Sglebius tt_want(res1.n_read_timeouts == 1); 948290001Sglebius tt_want(res1.n_write_timeouts == 1); 949290001Sglebius 950290001Sglebius test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150); 951290001Sglebius test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100); 952290001Sglebius 953290001Sglebiusend: 954290001Sglebius if (bev1) 955290001Sglebius bufferevent_free(bev1); 956290001Sglebius if (bev2) 957290001Sglebius bufferevent_free(bev2); 958290001Sglebius} 959290001Sglebius 960290001Sglebiusstatic void 961290001Sglebiustrigger_failure_cb(evutil_socket_t fd, short what, void *ctx) 962290001Sglebius{ 963290001Sglebius TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout).")); 964290001Sglebius} 965290001Sglebius 966290001Sglebiusstatic void 967290001Sglebiustrigger_eventcb(struct bufferevent *bev, short what, void *ctx) 968290001Sglebius{ 969290001Sglebius struct event_base *base = ctx; 970290001Sglebius if (what == ~0) { 971290001Sglebius TT_BLATHER(("Event successfully triggered.")); 972290001Sglebius event_base_loopexit(base, NULL); 973290001Sglebius return; 974290001Sglebius } 975290001Sglebius reader_eventcb(bev, what, ctx); 976290001Sglebius} 977290001Sglebius 978290001Sglebiusstatic void 979290001Sglebiustrigger_readcb_triggered(struct bufferevent *bev, void *ctx) 980290001Sglebius{ 981290001Sglebius TT_BLATHER(("Read successfully triggered.")); 982290001Sglebius n_reads_invoked++; 983290001Sglebius bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags); 984290001Sglebius} 985290001Sglebius 986290001Sglebiusstatic void 987290001Sglebiustrigger_readcb(struct bufferevent *bev, void *ctx) 988290001Sglebius{ 989290001Sglebius struct timeval timeout = { 30, 0 }; 990290001Sglebius struct event_base *base = ctx; 991290001Sglebius size_t low, high, len; 992290001Sglebius int expected_reads; 993290001Sglebius 994290001Sglebius TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 995290001Sglebius expected_reads = ++n_reads_invoked; 996290001Sglebius 997290001Sglebius bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx); 998290001Sglebius 999290001Sglebius bufferevent_getwatermark(bev, EV_READ, &low, &high); 1000290001Sglebius len = evbuffer_get_length(bufferevent_get_input(bev)); 1001290001Sglebius 1002290001Sglebius bufferevent_setwatermark(bev, EV_READ, len + 1, 0); 1003290001Sglebius bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags); 1004290001Sglebius /* no callback expected */ 1005290001Sglebius tt_int_op(n_reads_invoked, ==, expected_reads); 1006290001Sglebius 1007290001Sglebius if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) || 1008290001Sglebius (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) { 1009290001Sglebius /* will be deferred */ 1010290001Sglebius } else { 1011290001Sglebius expected_reads++; 1012290001Sglebius } 1013290001Sglebius 1014290001Sglebius event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout); 1015290001Sglebius 1016290001Sglebius bufferevent_trigger(bev, EV_READ, 1017290001Sglebius bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS); 1018290001Sglebius tt_int_op(n_reads_invoked, ==, expected_reads); 1019290001Sglebius 1020290001Sglebius bufferevent_setwatermark(bev, EV_READ, low, high); 1021290001Sglebiusend: 1022290001Sglebius ; 1023290001Sglebius} 1024290001Sglebius 1025290001Sglebiusstatic void 1026290001Sglebiustest_bufferevent_trigger(void *arg) 1027290001Sglebius{ 1028290001Sglebius struct basic_test_data *data = arg; 1029290001Sglebius struct evconnlistener *lev=NULL; 1030290001Sglebius struct bufferevent *bev=NULL; 1031290001Sglebius struct sockaddr_in localhost; 1032290001Sglebius struct sockaddr_storage ss; 1033290001Sglebius struct sockaddr *sa; 1034290001Sglebius ev_socklen_t slen; 1035290001Sglebius 1036290001Sglebius int be_flags=BEV_OPT_CLOSE_ON_FREE; 1037290001Sglebius int trig_flags=0; 1038290001Sglebius 1039290001Sglebius if (strstr((char*)data->setup_data, "defer")) { 1040290001Sglebius be_flags |= BEV_OPT_DEFER_CALLBACKS; 1041290001Sglebius } 1042290001Sglebius bufferevent_connect_test_flags = be_flags; 1043290001Sglebius 1044290001Sglebius if (strstr((char*)data->setup_data, "postpone")) { 1045290001Sglebius trig_flags |= BEV_TRIG_DEFER_CALLBACKS; 1046290001Sglebius } 1047290001Sglebius bufferevent_trigger_test_flags = trig_flags; 1048290001Sglebius 1049290001Sglebius memset(&localhost, 0, sizeof(localhost)); 1050290001Sglebius 1051290001Sglebius localhost.sin_port = 0; /* pick-a-port */ 1052290001Sglebius localhost.sin_addr.s_addr = htonl(0x7f000001L); 1053290001Sglebius localhost.sin_family = AF_INET; 1054290001Sglebius sa = (struct sockaddr *)&localhost; 1055290001Sglebius lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 1056290001Sglebius LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 1057290001Sglebius 16, sa, sizeof(localhost)); 1058290001Sglebius tt_assert(lev); 1059290001Sglebius 1060290001Sglebius sa = (struct sockaddr *)&ss; 1061290001Sglebius slen = sizeof(ss); 1062290001Sglebius if (regress_get_listener_addr(lev, sa, &slen) < 0) { 1063290001Sglebius tt_abort_perror("getsockname"); 1064290001Sglebius } 1065290001Sglebius 1066290001Sglebius tt_assert(!evconnlistener_enable(lev)); 1067290001Sglebius bev = bufferevent_socket_new(data->base, -1, be_flags); 1068290001Sglebius tt_assert(bev); 1069290001Sglebius bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base); 1070290001Sglebius 1071290001Sglebius bufferevent_enable(bev, EV_READ); 1072290001Sglebius 1073290001Sglebius tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost))); 1074290001Sglebius 1075290001Sglebius event_base_dispatch(data->base); 1076290001Sglebius 1077290001Sglebius tt_int_op(n_reads_invoked, ==, 2); 1078290001Sglebiusend: 1079290001Sglebius if (lev) 1080290001Sglebius evconnlistener_free(lev); 1081290001Sglebius 1082290001Sglebius if (bev) 1083290001Sglebius bufferevent_free(bev); 1084290001Sglebius} 1085290001Sglebius 1086290001Sglebiusstruct testcase_t bufferevent_testcases[] = { 1087290001Sglebius 1088290001Sglebius LEGACY(bufferevent, TT_ISOLATED), 1089290001Sglebius LEGACY(bufferevent_pair, TT_ISOLATED), 1090290001Sglebius#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) 1091290001Sglebius { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, 1092290001Sglebius TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY, 1093290001Sglebius &basic_setup, NULL }, 1094290001Sglebius#endif 1095290001Sglebius LEGACY(bufferevent_watermarks, TT_ISOLATED), 1096290001Sglebius LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), 1097290001Sglebius LEGACY(bufferevent_filters, TT_ISOLATED), 1098290001Sglebius LEGACY(bufferevent_pair_filters, TT_ISOLATED), 1099290001Sglebius { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE, 1100290001Sglebius &basic_setup, (void*)"" }, 1101290001Sglebius { "bufferevent_connect_defer", test_bufferevent_connect, 1102290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 1103290001Sglebius { "bufferevent_connect_lock", test_bufferevent_connect, 1104290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" }, 1105290001Sglebius { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1106290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1107290001Sglebius (void*)"defer lock" }, 1108290001Sglebius { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect, 1109290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1110290001Sglebius (void*)"lock defer unlocked" }, 1111290001Sglebius { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1112290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1113290001Sglebius { "bufferevent_timeout", test_bufferevent_timeouts, 1114290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" }, 1115290001Sglebius { "bufferevent_timeout_pair", test_bufferevent_timeouts, 1116290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" }, 1117290001Sglebius { "bufferevent_timeout_filter", test_bufferevent_timeouts, 1118290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" }, 1119290001Sglebius { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts, 1120290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" }, 1121290001Sglebius { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE, 1122290001Sglebius &basic_setup, (void*)"" }, 1123290001Sglebius { "bufferevent_trigger_defer", test_bufferevent_trigger, 1124290001Sglebius TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 1125290001Sglebius { "bufferevent_trigger_postpone", test_bufferevent_trigger, 1126290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1127290001Sglebius (void*)"postpone" }, 1128290001Sglebius { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger, 1129290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1130290001Sglebius (void*)"defer postpone" }, 1131290001Sglebius#ifdef EVENT__HAVE_LIBZ 1132290001Sglebius LEGACY(bufferevent_zlib, TT_ISOLATED), 1133290001Sglebius#else 1134290001Sglebius { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, 1135290001Sglebius#endif 1136290001Sglebius 1137290001Sglebius END_OF_TESTCASES, 1138290001Sglebius}; 1139290001Sglebius 1140290001Sglebiusstruct testcase_t bufferevent_iocp_testcases[] = { 1141290001Sglebius 1142290001Sglebius LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP), 1143290001Sglebius LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP), 1144290001Sglebius LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP), 1145290001Sglebius { "bufferevent_connect", test_bufferevent_connect, 1146290001Sglebius TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" }, 1147290001Sglebius { "bufferevent_connect_defer", test_bufferevent_connect, 1148290001Sglebius TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" }, 1149290001Sglebius { "bufferevent_connect_lock", test_bufferevent_connect, 1150290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 1151290001Sglebius (void*)"lock" }, 1152290001Sglebius { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1153290001Sglebius TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup, 1154290001Sglebius (void*)"defer lock" }, 1155290001Sglebius { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1156290001Sglebius TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL }, 1157290001Sglebius { "bufferevent_connect_nonblocking", test_bufferevent_connect, 1158290001Sglebius TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, 1159290001Sglebius (void*)"unset_connectex" }, 1160290001Sglebius 1161290001Sglebius END_OF_TESTCASES, 1162290001Sglebius}; 1163