1 1.4 christos /* $NetBSD: regress_bufferevent.c,v 1.4 2021/04/07 03:36:48 christos Exp $ */ 2 1.4 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 2003-2007 Niels Provos <provos (at) citi.umich.edu> 5 1.1 christos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 6 1.1 christos * 7 1.1 christos * Redistribution and use in source and binary forms, with or without 8 1.1 christos * modification, are permitted provided that the following conditions 9 1.1 christos * are met: 10 1.1 christos * 1. Redistributions of source code must retain the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer. 12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 christos * notice, this list of conditions and the following disclaimer in the 14 1.1 christos * documentation and/or other materials provided with the distribution. 15 1.1 christos * 3. The name of the author may not be used to endorse or promote products 16 1.1 christos * derived from this software without specific prior written permission. 17 1.1 christos * 18 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 christos */ 29 1.3 christos #include "util-internal.h" 30 1.1 christos 31 1.1 christos /* The old tests here need assertions to work. */ 32 1.1 christos #undef NDEBUG 33 1.1 christos 34 1.4 christos /** 35 1.4 christos * - clang supports __has_feature 36 1.4 christos * - gcc supports __SANITIZE_ADDRESS__ 37 1.4 christos * 38 1.4 christos * Let's set __SANITIZE_ADDRESS__ if __has_feature(address_sanitizer) 39 1.4 christos */ 40 1.4 christos #ifndef __has_feature 41 1.4 christos #define __has_feature(x) 0 42 1.4 christos #endif 43 1.4 christos #if !defined(__SANITIZE_ADDRESS__) && __has_feature(address_sanitizer) 44 1.4 christos #define __SANITIZE_ADDRESS__ 45 1.4 christos #endif 46 1.4 christos 47 1.3 christos #ifdef _WIN32 48 1.1 christos #include <winsock2.h> 49 1.1 christos #include <windows.h> 50 1.1 christos #endif 51 1.1 christos 52 1.1 christos #include "event2/event-config.h" 53 1.1 christos #include <sys/cdefs.h> 54 1.4 christos __RCSID("$NetBSD: regress_bufferevent.c,v 1.4 2021/04/07 03:36:48 christos Exp $"); 55 1.1 christos 56 1.1 christos #include <sys/types.h> 57 1.1 christos #include <sys/stat.h> 58 1.3 christos #ifdef EVENT__HAVE_SYS_TIME_H 59 1.1 christos #include <sys/time.h> 60 1.1 christos #endif 61 1.1 christos #include <sys/queue.h> 62 1.3 christos #ifndef _WIN32 63 1.1 christos #include <sys/socket.h> 64 1.1 christos #include <sys/wait.h> 65 1.1 christos #include <signal.h> 66 1.1 christos #include <unistd.h> 67 1.1 christos #include <netdb.h> 68 1.1 christos #include <netinet/in.h> 69 1.1 christos #endif 70 1.1 christos #include <fcntl.h> 71 1.1 christos #include <signal.h> 72 1.1 christos #include <stdlib.h> 73 1.1 christos #include <stdio.h> 74 1.1 christos #include <string.h> 75 1.1 christos #include <errno.h> 76 1.1 christos #include <assert.h> 77 1.1 christos 78 1.3 christos #ifdef EVENT__HAVE_ARPA_INET_H 79 1.1 christos #include <arpa/inet.h> 80 1.1 christos #endif 81 1.1 christos 82 1.1 christos #include "event2/event-config.h" 83 1.1 christos #include "event2/event.h" 84 1.1 christos #include "event2/event_struct.h" 85 1.1 christos #include "event2/event_compat.h" 86 1.1 christos #include "event2/tag.h" 87 1.1 christos #include "event2/buffer.h" 88 1.1 christos #include "event2/bufferevent.h" 89 1.1 christos #include "event2/bufferevent_compat.h" 90 1.1 christos #include "event2/bufferevent_struct.h" 91 1.1 christos #include "event2/listener.h" 92 1.1 christos #include "event2/util.h" 93 1.1 christos 94 1.1 christos #include "bufferevent-internal.h" 95 1.3 christos #include "evthread-internal.h" 96 1.1 christos #include "util-internal.h" 97 1.3 christos #ifdef _WIN32 98 1.1 christos #include "iocp-internal.h" 99 1.1 christos #endif 100 1.1 christos 101 1.1 christos #include "regress.h" 102 1.1 christos #include "regress_testutils.h" 103 1.1 christos 104 1.1 christos /* 105 1.1 christos * simple bufferevent test 106 1.1 christos */ 107 1.1 christos 108 1.1 christos static void 109 1.1 christos readcb(struct bufferevent *bev, void *arg) 110 1.1 christos { 111 1.1 christos if (evbuffer_get_length(bev->input) == 8333) { 112 1.1 christos struct evbuffer *evbuf = evbuffer_new(); 113 1.1 christos assert(evbuf != NULL); 114 1.1 christos 115 1.1 christos /* gratuitous test of bufferevent_read_buffer */ 116 1.1 christos bufferevent_read_buffer(bev, evbuf); 117 1.1 christos 118 1.1 christos bufferevent_disable(bev, EV_READ); 119 1.1 christos 120 1.1 christos if (evbuffer_get_length(evbuf) == 8333) { 121 1.1 christos test_ok++; 122 1.1 christos } 123 1.1 christos 124 1.1 christos evbuffer_free(evbuf); 125 1.1 christos } 126 1.1 christos } 127 1.1 christos 128 1.1 christos static void 129 1.1 christos writecb(struct bufferevent *bev, void *arg) 130 1.1 christos { 131 1.1 christos if (evbuffer_get_length(bev->output) == 0) { 132 1.1 christos test_ok++; 133 1.1 christos } 134 1.1 christos } 135 1.1 christos 136 1.1 christos static void 137 1.1 christos errorcb(struct bufferevent *bev, short what, void *arg) 138 1.1 christos { 139 1.1 christos test_ok = -2; 140 1.1 christos } 141 1.1 christos 142 1.1 christos static void 143 1.3 christos test_bufferevent_impl(int use_pair, int flush) 144 1.1 christos { 145 1.1 christos struct bufferevent *bev1 = NULL, *bev2 = NULL; 146 1.1 christos char buffer[8333]; 147 1.1 christos int i; 148 1.3 christos int expected = 2; 149 1.1 christos 150 1.1 christos if (use_pair) { 151 1.2 christos struct bufferevent *xpair[2]; 152 1.2 christos tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 153 1.2 christos bev1 = xpair[0]; 154 1.2 christos bev2 = xpair[1]; 155 1.3 christos bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1); 156 1.1 christos bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); 157 1.4 christos tt_fd_op(bufferevent_getfd(bev1), ==, EVUTIL_INVALID_SOCKET); 158 1.1 christos tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 159 1.1 christos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2); 160 1.1 christos tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1); 161 1.1 christos } else { 162 1.1 christos bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); 163 1.1 christos bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); 164 1.4 christos tt_fd_op(bufferevent_getfd(bev1), ==, pair[0]); 165 1.1 christos tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 166 1.1 christos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 167 1.1 christos tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 168 1.1 christos } 169 1.1 christos 170 1.3 christos { 171 1.3 christos /* Test getcb. */ 172 1.3 christos bufferevent_data_cb r, w; 173 1.3 christos bufferevent_event_cb e; 174 1.3 christos void *a; 175 1.3 christos bufferevent_getcb(bev1, &r, &w, &e, &a); 176 1.3 christos tt_ptr_op(r, ==, readcb); 177 1.3 christos tt_ptr_op(w, ==, writecb); 178 1.3 christos tt_ptr_op(e, ==, errorcb); 179 1.3 christos tt_ptr_op(a, ==, use_pair ? bev1 : NULL); 180 1.3 christos } 181 1.3 christos 182 1.1 christos bufferevent_disable(bev1, EV_READ); 183 1.1 christos bufferevent_enable(bev2, EV_READ); 184 1.1 christos 185 1.1 christos tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE); 186 1.1 christos tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ); 187 1.1 christos 188 1.1 christos for (i = 0; i < (int)sizeof(buffer); i++) 189 1.1 christos buffer[i] = i; 190 1.1 christos 191 1.1 christos bufferevent_write(bev1, buffer, sizeof(buffer)); 192 1.3 christos if (flush >= 0) { 193 1.3 christos tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0); 194 1.3 christos } 195 1.1 christos 196 1.1 christos event_dispatch(); 197 1.1 christos 198 1.3 christos bufferevent_free(bev2); 199 1.3 christos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 200 1.1 christos bufferevent_free(bev1); 201 1.1 christos 202 1.3 christos /** Only pair call errorcb for BEV_FINISHED */ 203 1.3 christos if (use_pair && flush == BEV_FINISHED) { 204 1.3 christos expected = -1; 205 1.3 christos } 206 1.3 christos if (test_ok != expected) 207 1.1 christos test_ok = 0; 208 1.1 christos end: 209 1.1 christos ; 210 1.1 christos } 211 1.1 christos 212 1.3 christos static void test_bufferevent(void) { test_bufferevent_impl(0, -1); } 213 1.3 christos static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); } 214 1.3 christos 215 1.3 christos static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); } 216 1.3 christos static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); } 217 1.3 christos static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); } 218 1.3 christos 219 1.3 christos static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); } 220 1.3 christos static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); } 221 1.3 christos static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); } 222 1.3 christos 223 1.4 christos #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__) 224 1.3 christos /** 225 1.3 christos * Trace lock/unlock/alloc/free for locks. 226 1.3 christos * (More heavier then evthread_debug*) 227 1.3 christos */ 228 1.3 christos typedef struct 229 1.3 christos { 230 1.3 christos void *lock; 231 1.3 christos enum { 232 1.3 christos ALLOC, FREE, 233 1.3 christos } status; 234 1.3 christos size_t locked /** allow recursive locking */; 235 1.3 christos } lock_wrapper; 236 1.3 christos struct lock_unlock_base 237 1.3 christos { 238 1.3 christos /* Original callbacks */ 239 1.3 christos struct evthread_lock_callbacks cbs; 240 1.3 christos /* Map of locks */ 241 1.3 christos lock_wrapper *locks; 242 1.3 christos size_t nr_locks; 243 1.3 christos } lu_base = { 244 1.3 christos .locks = NULL, 245 1.3 christos }; 246 1.3 christos 247 1.3 christos static lock_wrapper *lu_find(void *lock_) 248 1.3 christos { 249 1.3 christos size_t i; 250 1.3 christos for (i = 0; i < lu_base.nr_locks; ++i) { 251 1.3 christos lock_wrapper *lock = &lu_base.locks[i]; 252 1.3 christos if (lock->lock == lock_) 253 1.3 christos return lock; 254 1.3 christos } 255 1.3 christos return NULL; 256 1.3 christos } 257 1.3 christos 258 1.3 christos static void *trace_lock_alloc(unsigned locktype) 259 1.3 christos { 260 1.3 christos void *lock; 261 1.3 christos ++lu_base.nr_locks; 262 1.3 christos lu_base.locks = realloc(lu_base.locks, 263 1.3 christos sizeof(lock_wrapper) * lu_base.nr_locks); 264 1.3 christos lock = lu_base.cbs.alloc(locktype); 265 1.3 christos lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 }; 266 1.3 christos return lock; 267 1.3 christos } 268 1.3 christos static void trace_lock_free(void *lock_, unsigned locktype) 269 1.3 christos { 270 1.3 christos lock_wrapper *lock = lu_find(lock_); 271 1.3 christos if (!lock || lock->status == FREE || lock->locked) { 272 1.3 christos TT_FAIL(("lock: free error")); 273 1.3 christos } else { 274 1.3 christos lock->status = FREE; 275 1.3 christos lu_base.cbs.free(lock_, locktype); 276 1.3 christos } 277 1.3 christos } 278 1.3 christos static int trace_lock_lock(unsigned mode, void *lock_) 279 1.3 christos { 280 1.3 christos lock_wrapper *lock = lu_find(lock_); 281 1.3 christos if (!lock || lock->status == FREE) { 282 1.3 christos TT_FAIL(("lock: lock error")); 283 1.3 christos return -1; 284 1.3 christos } else { 285 1.3 christos ++lock->locked; 286 1.3 christos return lu_base.cbs.lock(mode, lock_); 287 1.3 christos } 288 1.3 christos } 289 1.3 christos static int trace_lock_unlock(unsigned mode, void *lock_) 290 1.3 christos { 291 1.3 christos lock_wrapper *lock = lu_find(lock_); 292 1.3 christos if (!lock || lock->status == FREE || !lock->locked) { 293 1.3 christos TT_FAIL(("lock: unlock error")); 294 1.3 christos return -1; 295 1.3 christos } else { 296 1.3 christos --lock->locked; 297 1.3 christos return lu_base.cbs.unlock(mode, lock_); 298 1.3 christos } 299 1.3 christos } 300 1.3 christos static void lock_unlock_free_thread_cbs(void) 301 1.3 christos { 302 1.3 christos event_base_free(NULL); 303 1.3 christos 304 1.3 christos if (libevent_tests_running_in_debug_mode) 305 1.3 christos libevent_global_shutdown(); 306 1.3 christos 307 1.3 christos /** drop immutable flag */ 308 1.3 christos evthread_set_lock_callbacks(NULL); 309 1.3 christos /** avoid calling of event_global_setup_locks_() for new cbs */ 310 1.3 christos libevent_global_shutdown(); 311 1.3 christos /** drop immutable flag for non-debug ops (since called after shutdown) */ 312 1.3 christos evthread_set_lock_callbacks(NULL); 313 1.3 christos } 314 1.3 christos 315 1.3 christos static int use_lock_unlock_profiler(void) 316 1.3 christos { 317 1.3 christos struct evthread_lock_callbacks cbs = { 318 1.3 christos EVTHREAD_LOCK_API_VERSION, 319 1.3 christos EVTHREAD_LOCKTYPE_RECURSIVE, 320 1.3 christos trace_lock_alloc, 321 1.3 christos trace_lock_free, 322 1.3 christos trace_lock_lock, 323 1.3 christos trace_lock_unlock, 324 1.3 christos }; 325 1.3 christos memcpy(&lu_base.cbs, evthread_get_lock_callbacks(), 326 1.3 christos sizeof(lu_base.cbs)); 327 1.3 christos { 328 1.3 christos lock_unlock_free_thread_cbs(); 329 1.3 christos 330 1.3 christos evthread_set_lock_callbacks(&cbs); 331 1.3 christos /** re-create debug locks correctly */ 332 1.3 christos evthread_enable_lock_debugging(); 333 1.3 christos 334 1.3 christos event_init(); 335 1.3 christos } 336 1.3 christos return 0; 337 1.3 christos } 338 1.3 christos static void free_lock_unlock_profiler(struct basic_test_data *data) 339 1.1 christos { 340 1.3 christos /** fix "held_by" for kqueue */ 341 1.3 christos evthread_set_lock_callbacks(NULL); 342 1.3 christos 343 1.3 christos lock_unlock_free_thread_cbs(); 344 1.3 christos free(lu_base.locks); 345 1.3 christos data->base = NULL; 346 1.1 christos } 347 1.1 christos 348 1.3 christos static void test_bufferevent_pair_release_lock(void *arg) 349 1.1 christos { 350 1.3 christos struct basic_test_data *data = arg; 351 1.3 christos use_lock_unlock_profiler(); 352 1.3 christos { 353 1.3 christos struct bufferevent *xpair[2]; 354 1.3 christos if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, xpair)) { 355 1.3 christos bufferevent_free(xpair[0]); 356 1.3 christos bufferevent_free(xpair[1]); 357 1.3 christos } else 358 1.3 christos tt_abort_perror("bufferevent_pair_new"); 359 1.3 christos } 360 1.3 christos free_lock_unlock_profiler(data); 361 1.3 christos end: 362 1.3 christos ; 363 1.1 christos } 364 1.3 christos #endif 365 1.1 christos 366 1.1 christos /* 367 1.1 christos * test watermarks and bufferevent 368 1.1 christos */ 369 1.1 christos 370 1.1 christos static void 371 1.1 christos wm_readcb(struct bufferevent *bev, void *arg) 372 1.1 christos { 373 1.1 christos struct evbuffer *evbuf = evbuffer_new(); 374 1.1 christos int len = (int)evbuffer_get_length(bev->input); 375 1.1 christos static int nread; 376 1.1 christos 377 1.1 christos assert(len >= 10 && len <= 20); 378 1.1 christos 379 1.1 christos assert(evbuf != NULL); 380 1.1 christos 381 1.1 christos /* gratuitous test of bufferevent_read_buffer */ 382 1.1 christos bufferevent_read_buffer(bev, evbuf); 383 1.1 christos 384 1.1 christos nread += len; 385 1.1 christos if (nread == 65000) { 386 1.1 christos bufferevent_disable(bev, EV_READ); 387 1.1 christos test_ok++; 388 1.1 christos } 389 1.1 christos 390 1.1 christos evbuffer_free(evbuf); 391 1.1 christos } 392 1.1 christos 393 1.1 christos static void 394 1.1 christos wm_writecb(struct bufferevent *bev, void *arg) 395 1.1 christos { 396 1.1 christos assert(evbuffer_get_length(bev->output) <= 100); 397 1.1 christos if (evbuffer_get_length(bev->output) == 0) { 398 1.1 christos evbuffer_drain(bev->output, evbuffer_get_length(bev->output)); 399 1.1 christos test_ok++; 400 1.1 christos } 401 1.1 christos } 402 1.1 christos 403 1.1 christos static void 404 1.1 christos wm_errorcb(struct bufferevent *bev, short what, void *arg) 405 1.1 christos { 406 1.1 christos test_ok = -2; 407 1.1 christos } 408 1.1 christos 409 1.1 christos static void 410 1.1 christos test_bufferevent_watermarks_impl(int use_pair) 411 1.1 christos { 412 1.1 christos struct bufferevent *bev1 = NULL, *bev2 = NULL; 413 1.1 christos char buffer[65000]; 414 1.3 christos size_t low, high; 415 1.1 christos int i; 416 1.1 christos test_ok = 0; 417 1.1 christos 418 1.1 christos if (use_pair) { 419 1.2 christos struct bufferevent *xpair[2]; 420 1.2 christos tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 421 1.2 christos bev1 = xpair[0]; 422 1.2 christos bev2 = xpair[1]; 423 1.1 christos bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL); 424 1.1 christos bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL); 425 1.1 christos } else { 426 1.1 christos bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL); 427 1.1 christos bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL); 428 1.1 christos } 429 1.1 christos tt_assert(bev1); 430 1.1 christos tt_assert(bev2); 431 1.1 christos bufferevent_disable(bev1, EV_READ); 432 1.1 christos bufferevent_enable(bev2, EV_READ); 433 1.1 christos 434 1.3 christos /* By default, low watermarks are set to 0 */ 435 1.3 christos bufferevent_getwatermark(bev1, EV_READ, &low, NULL); 436 1.3 christos tt_int_op(low, ==, 0); 437 1.3 christos bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL); 438 1.3 christos tt_int_op(low, ==, 0); 439 1.3 christos 440 1.1 christos for (i = 0; i < (int)sizeof(buffer); i++) 441 1.1 christos buffer[i] = (char)i; 442 1.1 christos 443 1.1 christos /* limit the reading on the receiving bufferevent */ 444 1.1 christos bufferevent_setwatermark(bev2, EV_READ, 10, 20); 445 1.1 christos 446 1.3 christos bufferevent_getwatermark(bev2, EV_READ, &low, &high); 447 1.3 christos tt_int_op(low, ==, 10); 448 1.3 christos tt_int_op(high, ==, 20); 449 1.3 christos 450 1.1 christos /* Tell the sending bufferevent not to notify us till it's down to 451 1.1 christos 100 bytes. */ 452 1.1 christos bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); 453 1.1 christos 454 1.3 christos bufferevent_getwatermark(bev1, EV_WRITE, &low, &high); 455 1.3 christos tt_int_op(low, ==, 100); 456 1.3 christos tt_int_op(high, ==, 2000); 457 1.3 christos 458 1.3 christos { 459 1.3 christos int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high); 460 1.3 christos tt_int_op(r, !=, 0); 461 1.3 christos } 462 1.3 christos 463 1.1 christos bufferevent_write(bev1, buffer, sizeof(buffer)); 464 1.1 christos 465 1.1 christos event_dispatch(); 466 1.1 christos 467 1.1 christos tt_int_op(test_ok, ==, 2); 468 1.1 christos 469 1.1 christos /* The write callback drained all the data from outbuf, so we 470 1.1 christos * should have removed the write event... */ 471 1.1 christos tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL)); 472 1.1 christos 473 1.1 christos end: 474 1.1 christos if (bev1) 475 1.1 christos bufferevent_free(bev1); 476 1.1 christos if (bev2) 477 1.1 christos bufferevent_free(bev2); 478 1.1 christos } 479 1.1 christos 480 1.1 christos static void 481 1.1 christos test_bufferevent_watermarks(void) 482 1.1 christos { 483 1.1 christos test_bufferevent_watermarks_impl(0); 484 1.1 christos } 485 1.1 christos 486 1.1 christos static void 487 1.1 christos test_bufferevent_pair_watermarks(void) 488 1.1 christos { 489 1.1 christos test_bufferevent_watermarks_impl(1); 490 1.1 christos } 491 1.1 christos 492 1.1 christos /* 493 1.1 christos * Test bufferevent filters 494 1.1 christos */ 495 1.1 christos 496 1.1 christos /* strip an 'x' from each byte */ 497 1.1 christos 498 1.1 christos static enum bufferevent_filter_result 499 1.1 christos bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst, 500 1.1 christos ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 501 1.1 christos { 502 1.1 christos const unsigned char *buffer; 503 1.1 christos unsigned i; 504 1.1 christos 505 1.1 christos buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 506 1.1 christos for (i = 0; i < evbuffer_get_length(src); i += 2) { 507 1.3 christos if (buffer[i] == '-') 508 1.3 christos continue; 509 1.3 christos 510 1.1 christos assert(buffer[i] == 'x'); 511 1.1 christos evbuffer_add(dst, buffer + i + 1, 1); 512 1.1 christos } 513 1.1 christos 514 1.1 christos evbuffer_drain(src, i); 515 1.1 christos return (BEV_OK); 516 1.1 christos } 517 1.1 christos 518 1.1 christos /* add an 'x' before each byte */ 519 1.1 christos 520 1.1 christos static enum bufferevent_filter_result 521 1.1 christos bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst, 522 1.1 christos ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 523 1.1 christos { 524 1.1 christos const unsigned char *buffer; 525 1.1 christos unsigned i; 526 1.3 christos struct bufferevent **bevp = ctx; 527 1.3 christos 528 1.3 christos ++test_ok; 529 1.1 christos 530 1.3 christos if (test_ok == 1) { 531 1.3 christos buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 532 1.3 christos for (i = 0; i < evbuffer_get_length(src); ++i) { 533 1.3 christos evbuffer_add(dst, "x", 1); 534 1.3 christos evbuffer_add(dst, buffer + i, 1); 535 1.3 christos } 536 1.3 christos evbuffer_drain(src, evbuffer_get_length(src)); 537 1.3 christos } else { 538 1.3 christos return BEV_ERROR; 539 1.3 christos } 540 1.3 christos 541 1.3 christos if (bevp && test_ok == 1) { 542 1.3 christos int prev = ++test_ok; 543 1.3 christos bufferevent_write(*bevp, "-", 1); 544 1.3 christos /* check that during this bufferevent_write() 545 1.3 christos * bufferevent_output_filter() will not be called again */ 546 1.3 christos assert(test_ok == prev); 547 1.3 christos --test_ok; 548 1.1 christos } 549 1.1 christos 550 1.1 christos return (BEV_OK); 551 1.1 christos } 552 1.1 christos 553 1.1 christos static void 554 1.3 christos test_bufferevent_filters_impl(int use_pair, int disable) 555 1.1 christos { 556 1.1 christos struct bufferevent *bev1 = NULL, *bev2 = NULL; 557 1.1 christos struct bufferevent *bev1_base = NULL, *bev2_base = NULL; 558 1.1 christos char buffer[8333]; 559 1.1 christos int i; 560 1.1 christos 561 1.1 christos test_ok = 0; 562 1.1 christos 563 1.1 christos if (use_pair) { 564 1.2 christos struct bufferevent *xpair[2]; 565 1.2 christos tt_assert(0 == bufferevent_pair_new(NULL, 0, xpair)); 566 1.2 christos bev1 = xpair[0]; 567 1.2 christos bev2 = xpair[1]; 568 1.1 christos } else { 569 1.1 christos bev1 = bufferevent_socket_new(NULL, pair[0], 0); 570 1.1 christos bev2 = bufferevent_socket_new(NULL, pair[1], 0); 571 1.1 christos } 572 1.1 christos bev1_base = bev1; 573 1.1 christos bev2_base = bev2; 574 1.1 christos 575 1.1 christos for (i = 0; i < (int)sizeof(buffer); i++) 576 1.1 christos buffer[i] = i; 577 1.1 christos 578 1.1 christos bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter, 579 1.3 christos BEV_OPT_CLOSE_ON_FREE, NULL, 580 1.3 christos disable ? &bev1 : NULL); 581 1.1 christos 582 1.1 christos bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter, 583 1.1 christos NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 584 1.1 christos bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL); 585 1.1 christos bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL); 586 1.1 christos 587 1.1 christos tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base); 588 1.1 christos tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base); 589 1.4 christos tt_fd_op(bufferevent_getfd(bev1), ==, bufferevent_getfd(bev1_base)); 590 1.4 christos tt_fd_op(bufferevent_getfd(bev2), ==, bufferevent_getfd(bev2_base)); 591 1.1 christos 592 1.1 christos bufferevent_disable(bev1, EV_READ); 593 1.1 christos bufferevent_enable(bev2, EV_READ); 594 1.1 christos /* insert some filters */ 595 1.1 christos bufferevent_write(bev1, buffer, sizeof(buffer)); 596 1.1 christos 597 1.1 christos event_dispatch(); 598 1.1 christos 599 1.3 christos if (test_ok != 3 + !!disable) 600 1.1 christos test_ok = 0; 601 1.1 christos 602 1.1 christos end: 603 1.1 christos if (bev1) 604 1.1 christos bufferevent_free(bev1); 605 1.1 christos if (bev2) 606 1.1 christos bufferevent_free(bev2); 607 1.1 christos 608 1.1 christos } 609 1.1 christos 610 1.3 christos static void test_bufferevent_filters(void) 611 1.3 christos { test_bufferevent_filters_impl(0, 0); } 612 1.3 christos static void test_bufferevent_pair_filters(void) 613 1.3 christos { test_bufferevent_filters_impl(1, 0); } 614 1.3 christos static void test_bufferevent_filters_disable(void) 615 1.3 christos { test_bufferevent_filters_impl(0, 1); } 616 1.3 christos static void test_bufferevent_pair_filters_disable(void) 617 1.3 christos { test_bufferevent_filters_impl(1, 1); } 618 1.1 christos 619 1.1 christos 620 1.1 christos static void 621 1.1 christos sender_writecb(struct bufferevent *bev, void *ctx) 622 1.1 christos { 623 1.1 christos if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { 624 1.1 christos bufferevent_disable(bev,EV_READ|EV_WRITE); 625 1.3 christos TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev))); 626 1.1 christos bufferevent_free(bev); 627 1.1 christos } 628 1.1 christos } 629 1.1 christos 630 1.1 christos static void 631 1.1 christos sender_errorcb(struct bufferevent *bev, short what, void *ctx) 632 1.1 christos { 633 1.1 christos TT_FAIL(("Got sender error %d",(int)what)); 634 1.1 christos } 635 1.1 christos 636 1.1 christos static int bufferevent_connect_test_flags = 0; 637 1.3 christos static int bufferevent_trigger_test_flags = 0; 638 1.1 christos static int n_strings_read = 0; 639 1.1 christos static int n_reads_invoked = 0; 640 1.3 christos static int n_events_invoked = 0; 641 1.1 christos 642 1.1 christos #define TEST_STR "Now is the time for all good events to signal for " \ 643 1.1 christos "the good of their protocol" 644 1.1 christos static void 645 1.1 christos listen_cb(struct evconnlistener *listener, evutil_socket_t fd, 646 1.1 christos struct sockaddr *sa, int socklen, void *arg) 647 1.1 christos { 648 1.1 christos struct event_base *base = arg; 649 1.1 christos struct bufferevent *bev; 650 1.1 christos const char s[] = TEST_STR; 651 1.1 christos TT_BLATHER(("Got a request on socket %d", (int)fd )); 652 1.1 christos bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags); 653 1.1 christos tt_assert(bev); 654 1.1 christos bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL); 655 1.1 christos bufferevent_write(bev, s, sizeof(s)); 656 1.1 christos end: 657 1.1 christos ; 658 1.1 christos } 659 1.1 christos 660 1.4 christos static evutil_socket_t 661 1.3 christos fake_listener_create(struct sockaddr_in *localhost) 662 1.3 christos { 663 1.3 christos struct sockaddr *sa = (struct sockaddr *)localhost; 664 1.3 christos evutil_socket_t fd = -1; 665 1.3 christos ev_socklen_t slen = sizeof(*localhost); 666 1.3 christos 667 1.3 christos memset(localhost, 0, sizeof(*localhost)); 668 1.3 christos localhost->sin_port = 0; /* have the kernel pick a port */ 669 1.3 christos localhost->sin_addr.s_addr = htonl(0x7f000001L); 670 1.3 christos localhost->sin_family = AF_INET; 671 1.3 christos 672 1.3 christos /* bind, but don't listen or accept. should trigger 673 1.3 christos "Connection refused" reliably on most platforms. */ 674 1.3 christos fd = socket(localhost->sin_family, SOCK_STREAM, 0); 675 1.3 christos tt_assert(fd >= 0); 676 1.3 christos tt_assert(bind(fd, sa, slen) == 0); 677 1.3 christos tt_assert(getsockname(fd, sa, &slen) == 0); 678 1.3 christos 679 1.3 christos return fd; 680 1.3 christos 681 1.3 christos end: 682 1.3 christos return -1; 683 1.3 christos } 684 1.3 christos 685 1.1 christos static void 686 1.1 christos reader_eventcb(struct bufferevent *bev, short what, void *ctx) 687 1.1 christos { 688 1.1 christos struct event_base *base = ctx; 689 1.1 christos if (what & BEV_EVENT_ERROR) { 690 1.1 christos perror("foobar"); 691 1.1 christos TT_FAIL(("got connector error %d", (int)what)); 692 1.1 christos return; 693 1.1 christos } 694 1.1 christos if (what & BEV_EVENT_CONNECTED) { 695 1.3 christos TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev))); 696 1.1 christos bufferevent_enable(bev, EV_READ); 697 1.1 christos } 698 1.1 christos if (what & BEV_EVENT_EOF) { 699 1.1 christos char buf[512]; 700 1.1 christos size_t n; 701 1.1 christos n = bufferevent_read(bev, buf, sizeof(buf)-1); 702 1.3 christos tt_int_op(n, >=, 0); 703 1.1 christos buf[n] = '\0'; 704 1.1 christos tt_str_op(buf, ==, TEST_STR); 705 1.1 christos if (++n_strings_read == 2) 706 1.1 christos event_base_loopexit(base, NULL); 707 1.3 christos TT_BLATHER(("EOF on %d: %d strings read.", 708 1.3 christos (int)bufferevent_getfd(bev), n_strings_read)); 709 1.1 christos } 710 1.1 christos end: 711 1.1 christos ; 712 1.1 christos } 713 1.1 christos 714 1.1 christos static void 715 1.3 christos reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx) 716 1.3 christos { 717 1.3 christos TT_BLATHER(("Read eventcb simple invoked on %d.", 718 1.3 christos (int)bufferevent_getfd(bev))); 719 1.3 christos n_events_invoked++; 720 1.3 christos } 721 1.3 christos 722 1.3 christos static void 723 1.1 christos reader_readcb(struct bufferevent *bev, void *ctx) 724 1.1 christos { 725 1.3 christos TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 726 1.1 christos n_reads_invoked++; 727 1.1 christos } 728 1.1 christos 729 1.1 christos static void 730 1.1 christos test_bufferevent_connect(void *arg) 731 1.1 christos { 732 1.1 christos struct basic_test_data *data = arg; 733 1.1 christos struct evconnlistener *lev=NULL; 734 1.1 christos struct bufferevent *bev1=NULL, *bev2=NULL; 735 1.1 christos struct sockaddr_in localhost; 736 1.1 christos struct sockaddr_storage ss; 737 1.1 christos struct sockaddr *sa; 738 1.1 christos ev_socklen_t slen; 739 1.1 christos 740 1.1 christos int be_flags=BEV_OPT_CLOSE_ON_FREE; 741 1.1 christos 742 1.1 christos if (strstr((char*)data->setup_data, "defer")) { 743 1.1 christos be_flags |= BEV_OPT_DEFER_CALLBACKS; 744 1.1 christos } 745 1.1 christos if (strstr((char*)data->setup_data, "unlocked")) { 746 1.1 christos be_flags |= BEV_OPT_UNLOCK_CALLBACKS; 747 1.1 christos } 748 1.1 christos if (strstr((char*)data->setup_data, "lock")) { 749 1.1 christos be_flags |= BEV_OPT_THREADSAFE; 750 1.1 christos } 751 1.1 christos bufferevent_connect_test_flags = be_flags; 752 1.3 christos #ifdef _WIN32 753 1.1 christos if (!strcmp((char*)data->setup_data, "unset_connectex")) { 754 1.1 christos struct win32_extension_fns *ext = 755 1.1 christos (struct win32_extension_fns *) 756 1.3 christos event_get_win32_extension_fns_(); 757 1.1 christos ext->ConnectEx = NULL; 758 1.1 christos } 759 1.1 christos #endif 760 1.1 christos 761 1.1 christos memset(&localhost, 0, sizeof(localhost)); 762 1.1 christos 763 1.1 christos localhost.sin_port = 0; /* pick-a-port */ 764 1.1 christos localhost.sin_addr.s_addr = htonl(0x7f000001L); 765 1.1 christos localhost.sin_family = AF_INET; 766 1.1 christos sa = (struct sockaddr *)&localhost; 767 1.1 christos lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 768 1.1 christos LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 769 1.1 christos 16, sa, sizeof(localhost)); 770 1.1 christos tt_assert(lev); 771 1.1 christos 772 1.1 christos sa = (struct sockaddr *)&ss; 773 1.1 christos slen = sizeof(ss); 774 1.1 christos if (regress_get_listener_addr(lev, sa, &slen) < 0) { 775 1.1 christos tt_abort_perror("getsockname"); 776 1.1 christos } 777 1.1 christos 778 1.1 christos tt_assert(!evconnlistener_enable(lev)); 779 1.1 christos bev1 = bufferevent_socket_new(data->base, -1, be_flags); 780 1.1 christos bev2 = bufferevent_socket_new(data->base, -1, be_flags); 781 1.1 christos tt_assert(bev1); 782 1.1 christos tt_assert(bev2); 783 1.1 christos bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base); 784 1.1 christos bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base); 785 1.1 christos 786 1.1 christos bufferevent_enable(bev1, EV_READ); 787 1.1 christos bufferevent_enable(bev2, EV_READ); 788 1.1 christos 789 1.1 christos tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost))); 790 1.1 christos tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost))); 791 1.1 christos 792 1.1 christos event_base_dispatch(data->base); 793 1.1 christos 794 1.1 christos tt_int_op(n_strings_read, ==, 2); 795 1.1 christos tt_int_op(n_reads_invoked, >=, 2); 796 1.1 christos end: 797 1.1 christos if (lev) 798 1.1 christos evconnlistener_free(lev); 799 1.1 christos 800 1.1 christos if (bev1) 801 1.1 christos bufferevent_free(bev1); 802 1.1 christos 803 1.1 christos if (bev2) 804 1.1 christos bufferevent_free(bev2); 805 1.1 christos } 806 1.1 christos 807 1.1 christos static void 808 1.4 christos close_socket_cb(evutil_socket_t fd, short what, void *arg) 809 1.4 christos { 810 1.4 christos evutil_socket_t *fdp = arg; 811 1.4 christos if (*fdp >= 0) { 812 1.4 christos evutil_closesocket(*fdp); 813 1.4 christos *fdp = -1; 814 1.4 christos } 815 1.4 christos } 816 1.4 christos 817 1.4 christos static void 818 1.3 christos test_bufferevent_connect_fail_eventcb(void *arg) 819 1.3 christos { 820 1.3 christos struct basic_test_data *data = arg; 821 1.3 christos int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data; 822 1.4 christos struct event close_listener_event; 823 1.3 christos struct bufferevent *bev = NULL; 824 1.3 christos struct evconnlistener *lev = NULL; 825 1.3 christos struct sockaddr_in localhost; 826 1.4 christos struct timeval close_timeout = { 0, 300000 }; 827 1.3 christos ev_socklen_t slen = sizeof(localhost); 828 1.3 christos evutil_socket_t fake_listener = -1; 829 1.4 christos int r; 830 1.3 christos 831 1.3 christos fake_listener = fake_listener_create(&localhost); 832 1.3 christos 833 1.3 christos tt_int_op(n_events_invoked, ==, 0); 834 1.3 christos 835 1.3 christos bev = bufferevent_socket_new(data->base, -1, flags); 836 1.3 christos tt_assert(bev); 837 1.3 christos bufferevent_setcb(bev, reader_readcb, reader_readcb, 838 1.3 christos reader_eventcb_simple, data->base); 839 1.3 christos bufferevent_enable(bev, EV_READ|EV_WRITE); 840 1.3 christos tt_int_op(n_events_invoked, ==, 0); 841 1.3 christos tt_int_op(n_reads_invoked, ==, 0); 842 1.4 christos 843 1.3 christos /** @see also test_bufferevent_connect_fail() */ 844 1.4 christos r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); 845 1.4 christos /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 846 1.4 christos * detects the error immediately, which is not really wrong of it. */ 847 1.4 christos tt_want(r == 0 || r == -1); 848 1.4 christos 849 1.3 christos tt_int_op(n_events_invoked, ==, 0); 850 1.3 christos tt_int_op(n_reads_invoked, ==, 0); 851 1.4 christos 852 1.4 christos /* Close the listener socket after a delay. This should trigger 853 1.4 christos "connection refused" on some other platforms, including OSX. */ 854 1.4 christos evtimer_assign(&close_listener_event, data->base, close_socket_cb, 855 1.4 christos &fake_listener); 856 1.4 christos event_add(&close_listener_event, &close_timeout); 857 1.4 christos 858 1.3 christos event_base_dispatch(data->base); 859 1.3 christos tt_int_op(n_events_invoked, ==, 1); 860 1.3 christos tt_int_op(n_reads_invoked, ==, 0); 861 1.3 christos 862 1.3 christos end: 863 1.3 christos if (lev) 864 1.3 christos evconnlistener_free(lev); 865 1.3 christos if (bev) 866 1.3 christos bufferevent_free(bev); 867 1.3 christos if (fake_listener >= 0) 868 1.3 christos evutil_closesocket(fake_listener); 869 1.3 christos } 870 1.3 christos 871 1.3 christos static void 872 1.1 christos want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 873 1.1 christos { 874 1.1 christos struct event_base *base = ctx; 875 1.1 christos const char *err; 876 1.1 christos evutil_socket_t s; 877 1.1 christos 878 1.1 christos if (what & BEV_EVENT_ERROR) { 879 1.1 christos s = bufferevent_getfd(bev); 880 1.1 christos err = evutil_socket_error_to_string(evutil_socket_geterror(s)); 881 1.1 christos TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s", 882 1.1 christos EV_SOCK_ARG(s), err)); 883 1.1 christos test_ok = 1; 884 1.1 christos } else { 885 1.1 christos TT_FAIL(("didn't fail? what %hd", what)); 886 1.1 christos } 887 1.1 christos 888 1.1 christos event_base_loopexit(base, NULL); 889 1.1 christos } 890 1.1 christos 891 1.1 christos static void 892 1.1 christos test_bufferevent_connect_fail(void *arg) 893 1.1 christos { 894 1.3 christos struct basic_test_data *data = (struct basic_test_data *)arg; 895 1.1 christos struct bufferevent *bev=NULL; 896 1.1 christos struct event close_listener_event; 897 1.1 christos int close_listener_event_added = 0; 898 1.4 christos struct timeval close_timeout = { 0, 300000 }; 899 1.3 christos struct sockaddr_in localhost; 900 1.3 christos ev_socklen_t slen = sizeof(localhost); 901 1.3 christos evutil_socket_t fake_listener = -1; 902 1.1 christos int r; 903 1.1 christos 904 1.1 christos test_ok = 0; 905 1.1 christos 906 1.3 christos fake_listener = fake_listener_create(&localhost); 907 1.1 christos bev = bufferevent_socket_new(data->base, -1, 908 1.1 christos BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 909 1.1 christos tt_assert(bev); 910 1.1 christos bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 911 1.1 christos 912 1.3 christos r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); 913 1.1 christos /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 914 1.1 christos * detects the error immediately, which is not really wrong of it. */ 915 1.1 christos tt_want(r == 0 || r == -1); 916 1.1 christos 917 1.4 christos /* Close the listener socket after a delay. This should trigger 918 1.1 christos "connection refused" on some other platforms, including OSX. */ 919 1.1 christos evtimer_assign(&close_listener_event, data->base, close_socket_cb, 920 1.1 christos &fake_listener); 921 1.4 christos event_add(&close_listener_event, &close_timeout); 922 1.1 christos close_listener_event_added = 1; 923 1.1 christos 924 1.1 christos event_base_dispatch(data->base); 925 1.1 christos 926 1.1 christos tt_int_op(test_ok, ==, 1); 927 1.1 christos 928 1.1 christos end: 929 1.1 christos if (fake_listener >= 0) 930 1.1 christos evutil_closesocket(fake_listener); 931 1.1 christos 932 1.1 christos if (bev) 933 1.1 christos bufferevent_free(bev); 934 1.1 christos 935 1.1 christos if (close_listener_event_added) 936 1.1 christos event_del(&close_listener_event); 937 1.1 christos } 938 1.1 christos 939 1.1 christos struct timeout_cb_result { 940 1.1 christos struct timeval read_timeout_at; 941 1.1 christos struct timeval write_timeout_at; 942 1.1 christos struct timeval last_wrote_at; 943 1.4 christos struct timeval last_read_at; 944 1.1 christos int n_read_timeouts; 945 1.1 christos int n_write_timeouts; 946 1.1 christos int total_calls; 947 1.1 christos }; 948 1.1 christos 949 1.1 christos static void 950 1.4 christos bev_timeout_read_cb(struct bufferevent *bev, void *arg) 951 1.4 christos { 952 1.4 christos struct timeout_cb_result *res = arg; 953 1.4 christos evutil_gettimeofday(&res->last_read_at, NULL); 954 1.4 christos } 955 1.4 christos static void 956 1.1 christos bev_timeout_write_cb(struct bufferevent *bev, void *arg) 957 1.1 christos { 958 1.1 christos struct timeout_cb_result *res = arg; 959 1.1 christos evutil_gettimeofday(&res->last_wrote_at, NULL); 960 1.1 christos } 961 1.1 christos static void 962 1.1 christos bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg) 963 1.1 christos { 964 1.1 christos struct timeout_cb_result *res = arg; 965 1.1 christos ++res->total_calls; 966 1.1 christos 967 1.1 christos if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) 968 1.1 christos == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) { 969 1.1 christos evutil_gettimeofday(&res->read_timeout_at, NULL); 970 1.1 christos ++res->n_read_timeouts; 971 1.1 christos } 972 1.1 christos if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) 973 1.1 christos == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) { 974 1.1 christos evutil_gettimeofday(&res->write_timeout_at, NULL); 975 1.1 christos ++res->n_write_timeouts; 976 1.1 christos } 977 1.1 christos } 978 1.1 christos 979 1.1 christos static void 980 1.1 christos test_bufferevent_timeouts(void *arg) 981 1.1 christos { 982 1.1 christos /* "arg" is a string containing "pair" and/or "filter". */ 983 1.1 christos struct bufferevent *bev1 = NULL, *bev2 = NULL; 984 1.1 christos struct basic_test_data *data = arg; 985 1.1 christos int use_pair = 0, use_filter = 0; 986 1.1 christos struct timeval tv_w, tv_r, started_at; 987 1.1 christos struct timeout_cb_result res1, res2; 988 1.1 christos 989 1.1 christos memset(&res1, 0, sizeof(res1)); 990 1.1 christos memset(&res2, 0, sizeof(res2)); 991 1.1 christos 992 1.1 christos if (strstr((char*)data->setup_data, "pair")) 993 1.1 christos use_pair = 1; 994 1.1 christos if (strstr((char*)data->setup_data, "filter")) 995 1.1 christos use_filter = 1; 996 1.1 christos 997 1.1 christos if (use_pair) { 998 1.1 christos struct bufferevent *p[2]; 999 1.1 christos tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p)); 1000 1.1 christos bev1 = p[0]; 1001 1.1 christos bev2 = p[1]; 1002 1.1 christos } else { 1003 1.1 christos bev1 = bufferevent_socket_new(data->base, data->pair[0], 0); 1004 1.1 christos bev2 = bufferevent_socket_new(data->base, data->pair[1], 0); 1005 1.1 christos } 1006 1.1 christos tt_assert(bev1); 1007 1.1 christos tt_assert(bev2); 1008 1.1 christos 1009 1.1 christos if (use_filter) { 1010 1.1 christos struct bufferevent *bevf1, *bevf2; 1011 1.1 christos bevf1 = bufferevent_filter_new(bev1, NULL, NULL, 1012 1.1 christos BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 1013 1.1 christos bevf2 = bufferevent_filter_new(bev2, NULL, NULL, 1014 1.1 christos BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 1015 1.1 christos tt_assert(bevf1); 1016 1.1 christos tt_assert(bevf2); 1017 1.1 christos bev1 = bevf1; 1018 1.1 christos bev2 = bevf2; 1019 1.1 christos } 1020 1.1 christos 1021 1.1 christos /* Do this nice and early. */ 1022 1.1 christos bufferevent_disable(bev2, EV_READ); 1023 1.1 christos 1024 1.1 christos /* bev1 will try to write and read. Both will time out. */ 1025 1.1 christos evutil_gettimeofday(&started_at, NULL); 1026 1.1 christos tv_w.tv_sec = tv_r.tv_sec = 0; 1027 1.1 christos tv_w.tv_usec = 100*1000; 1028 1.1 christos tv_r.tv_usec = 150*1000; 1029 1.4 christos bufferevent_setcb(bev1, bev_timeout_read_cb, bev_timeout_write_cb, 1030 1.1 christos bev_timeout_event_cb, &res1); 1031 1.1 christos bufferevent_set_timeouts(bev1, &tv_r, &tv_w); 1032 1.4 christos bufferevent_write(bev1, "ABCDEFG", 7); 1033 1.1 christos bufferevent_enable(bev1, EV_READ|EV_WRITE); 1034 1.1 christos 1035 1.1 christos /* bev2 has nothing to say, and isn't listening. */ 1036 1.4 christos bufferevent_setcb(bev2, bev_timeout_read_cb, bev_timeout_write_cb, 1037 1.1 christos bev_timeout_event_cb, &res2); 1038 1.1 christos tv_w.tv_sec = tv_r.tv_sec = 0; 1039 1.1 christos tv_w.tv_usec = 200*1000; 1040 1.1 christos tv_r.tv_usec = 100*1000; 1041 1.1 christos bufferevent_set_timeouts(bev2, &tv_r, &tv_w); 1042 1.1 christos bufferevent_enable(bev2, EV_WRITE); 1043 1.1 christos 1044 1.3 christos tv_r.tv_sec = 0; 1045 1.3 christos tv_r.tv_usec = 350000; 1046 1.1 christos 1047 1.1 christos event_base_loopexit(data->base, &tv_r); 1048 1.1 christos event_base_dispatch(data->base); 1049 1.1 christos 1050 1.1 christos /* XXXX Test that actually reading or writing a little resets the 1051 1.1 christos * timeouts. */ 1052 1.1 christos 1053 1.4 christos tt_want(res1.total_calls == 2); 1054 1.1 christos tt_want(res1.n_read_timeouts == 1); 1055 1.1 christos tt_want(res1.n_write_timeouts == 1); 1056 1.4 christos tt_want(res2.total_calls == !(use_pair && !use_filter)); 1057 1.4 christos tt_want(res2.n_write_timeouts == !(use_pair && !use_filter)); 1058 1.4 christos tt_want(!res2.n_read_timeouts); 1059 1.1 christos 1060 1.1 christos test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150); 1061 1.1 christos test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100); 1062 1.1 christos 1063 1.4 christos #define tt_assert_timeval_empty(tv) do { \ 1064 1.4 christos tt_int_op((tv).tv_sec, ==, 0); \ 1065 1.4 christos tt_int_op((tv).tv_usec, ==, 0); \ 1066 1.4 christos } while(0) 1067 1.4 christos tt_assert_timeval_empty(res1.last_read_at); 1068 1.4 christos tt_assert_timeval_empty(res2.last_read_at); 1069 1.4 christos tt_assert_timeval_empty(res2.last_wrote_at); 1070 1.4 christos tt_assert_timeval_empty(res2.last_wrote_at); 1071 1.4 christos #undef tt_assert_timeval_empty 1072 1.4 christos 1073 1.1 christos end: 1074 1.1 christos if (bev1) 1075 1.1 christos bufferevent_free(bev1); 1076 1.1 christos if (bev2) 1077 1.1 christos bufferevent_free(bev2); 1078 1.1 christos } 1079 1.1 christos 1080 1.3 christos static void 1081 1.3 christos trigger_failure_cb(evutil_socket_t fd, short what, void *ctx) 1082 1.3 christos { 1083 1.3 christos TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout).")); 1084 1.3 christos } 1085 1.3 christos 1086 1.3 christos static void 1087 1.3 christos trigger_eventcb(struct bufferevent *bev, short what, void *ctx) 1088 1.3 christos { 1089 1.3 christos struct event_base *base = ctx; 1090 1.3 christos if (what == ~0) { 1091 1.3 christos TT_BLATHER(("Event successfully triggered.")); 1092 1.3 christos event_base_loopexit(base, NULL); 1093 1.3 christos return; 1094 1.3 christos } 1095 1.3 christos reader_eventcb(bev, what, ctx); 1096 1.3 christos } 1097 1.3 christos 1098 1.3 christos static void 1099 1.3 christos trigger_readcb_triggered(struct bufferevent *bev, void *ctx) 1100 1.3 christos { 1101 1.3 christos TT_BLATHER(("Read successfully triggered.")); 1102 1.3 christos n_reads_invoked++; 1103 1.3 christos bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags); 1104 1.3 christos } 1105 1.3 christos 1106 1.3 christos static void 1107 1.3 christos trigger_readcb(struct bufferevent *bev, void *ctx) 1108 1.3 christos { 1109 1.3 christos struct timeval timeout = { 30, 0 }; 1110 1.3 christos struct event_base *base = ctx; 1111 1.3 christos size_t low, high, len; 1112 1.3 christos int expected_reads; 1113 1.3 christos 1114 1.3 christos TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 1115 1.3 christos expected_reads = ++n_reads_invoked; 1116 1.3 christos 1117 1.3 christos bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx); 1118 1.3 christos 1119 1.3 christos bufferevent_getwatermark(bev, EV_READ, &low, &high); 1120 1.3 christos len = evbuffer_get_length(bufferevent_get_input(bev)); 1121 1.3 christos 1122 1.3 christos bufferevent_setwatermark(bev, EV_READ, len + 1, 0); 1123 1.3 christos bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags); 1124 1.3 christos /* no callback expected */ 1125 1.3 christos tt_int_op(n_reads_invoked, ==, expected_reads); 1126 1.3 christos 1127 1.3 christos if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) || 1128 1.3 christos (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) { 1129 1.3 christos /* will be deferred */ 1130 1.3 christos } else { 1131 1.3 christos expected_reads++; 1132 1.3 christos } 1133 1.3 christos 1134 1.3 christos event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout); 1135 1.3 christos 1136 1.3 christos bufferevent_trigger(bev, EV_READ, 1137 1.3 christos bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS); 1138 1.3 christos tt_int_op(n_reads_invoked, ==, expected_reads); 1139 1.3 christos 1140 1.3 christos bufferevent_setwatermark(bev, EV_READ, low, high); 1141 1.3 christos end: 1142 1.3 christos ; 1143 1.3 christos } 1144 1.3 christos 1145 1.3 christos static void 1146 1.3 christos test_bufferevent_trigger(void *arg) 1147 1.3 christos { 1148 1.3 christos struct basic_test_data *data = arg; 1149 1.3 christos struct evconnlistener *lev=NULL; 1150 1.3 christos struct bufferevent *bev=NULL; 1151 1.3 christos struct sockaddr_in localhost; 1152 1.3 christos struct sockaddr_storage ss; 1153 1.3 christos struct sockaddr *sa; 1154 1.3 christos ev_socklen_t slen; 1155 1.3 christos 1156 1.3 christos int be_flags=BEV_OPT_CLOSE_ON_FREE; 1157 1.3 christos int trig_flags=0; 1158 1.3 christos 1159 1.3 christos if (strstr((char*)data->setup_data, "defer")) { 1160 1.3 christos be_flags |= BEV_OPT_DEFER_CALLBACKS; 1161 1.3 christos } 1162 1.3 christos bufferevent_connect_test_flags = be_flags; 1163 1.3 christos 1164 1.3 christos if (strstr((char*)data->setup_data, "postpone")) { 1165 1.3 christos trig_flags |= BEV_TRIG_DEFER_CALLBACKS; 1166 1.3 christos } 1167 1.3 christos bufferevent_trigger_test_flags = trig_flags; 1168 1.3 christos 1169 1.3 christos memset(&localhost, 0, sizeof(localhost)); 1170 1.3 christos 1171 1.3 christos localhost.sin_port = 0; /* pick-a-port */ 1172 1.3 christos localhost.sin_addr.s_addr = htonl(0x7f000001L); 1173 1.3 christos localhost.sin_family = AF_INET; 1174 1.3 christos sa = (struct sockaddr *)&localhost; 1175 1.3 christos lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 1176 1.3 christos LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 1177 1.3 christos 16, sa, sizeof(localhost)); 1178 1.3 christos tt_assert(lev); 1179 1.3 christos 1180 1.3 christos sa = (struct sockaddr *)&ss; 1181 1.3 christos slen = sizeof(ss); 1182 1.3 christos if (regress_get_listener_addr(lev, sa, &slen) < 0) { 1183 1.3 christos tt_abort_perror("getsockname"); 1184 1.3 christos } 1185 1.3 christos 1186 1.3 christos tt_assert(!evconnlistener_enable(lev)); 1187 1.3 christos bev = bufferevent_socket_new(data->base, -1, be_flags); 1188 1.3 christos tt_assert(bev); 1189 1.3 christos bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base); 1190 1.3 christos 1191 1.3 christos bufferevent_enable(bev, EV_READ); 1192 1.3 christos 1193 1.3 christos tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost))); 1194 1.3 christos 1195 1.3 christos event_base_dispatch(data->base); 1196 1.3 christos 1197 1.3 christos tt_int_op(n_reads_invoked, ==, 2); 1198 1.3 christos end: 1199 1.3 christos if (lev) 1200 1.3 christos evconnlistener_free(lev); 1201 1.3 christos 1202 1.3 christos if (bev) 1203 1.3 christos bufferevent_free(bev); 1204 1.3 christos } 1205 1.3 christos 1206 1.3 christos static void 1207 1.3 christos test_bufferevent_socket_filter_inactive(void *arg) 1208 1.3 christos { 1209 1.3 christos struct basic_test_data *data = arg; 1210 1.3 christos struct bufferevent *bev = NULL, *bevf = NULL; 1211 1.3 christos 1212 1.3 christos bev = bufferevent_socket_new(data->base, -1, 0); 1213 1.3 christos tt_assert(bev); 1214 1.3 christos bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL); 1215 1.3 christos tt_assert(bevf); 1216 1.3 christos 1217 1.3 christos end: 1218 1.3 christos if (bevf) 1219 1.3 christos bufferevent_free(bevf); 1220 1.3 christos if (bev) 1221 1.3 christos bufferevent_free(bev); 1222 1.3 christos } 1223 1.3 christos 1224 1.3 christos static void 1225 1.3 christos pair_flush_eventcb(struct bufferevent *bev, short what, void *ctx) 1226 1.3 christos { 1227 1.3 christos int *callback_what = ctx; 1228 1.3 christos *callback_what = what; 1229 1.3 christos } 1230 1.3 christos 1231 1.3 christos static void 1232 1.3 christos test_bufferevent_pair_flush(void *arg) 1233 1.3 christos { 1234 1.3 christos struct basic_test_data *data = arg; 1235 1.3 christos struct bufferevent *xpair[2]; 1236 1.3 christos struct bufferevent *bev1 = NULL; 1237 1.3 christos struct bufferevent *bev2 = NULL; 1238 1.3 christos int callback_what = 0; 1239 1.3 christos 1240 1.3 christos tt_assert(0 == bufferevent_pair_new(data->base, 0, xpair)); 1241 1.3 christos bev1 = xpair[0]; 1242 1.3 christos bev2 = xpair[1]; 1243 1.3 christos tt_assert(0 == bufferevent_enable(bev1, EV_WRITE)); 1244 1.3 christos tt_assert(0 == bufferevent_enable(bev2, EV_READ)); 1245 1.3 christos 1246 1.3 christos bufferevent_setcb(bev2, NULL, NULL, pair_flush_eventcb, &callback_what); 1247 1.3 christos 1248 1.3 christos bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED); 1249 1.3 christos 1250 1.3 christos event_base_loop(data->base, EVLOOP_ONCE); 1251 1.3 christos 1252 1.3 christos tt_assert(callback_what == (BEV_EVENT_READING | BEV_EVENT_EOF)); 1253 1.3 christos 1254 1.3 christos end: 1255 1.3 christos if (bev1) 1256 1.3 christos bufferevent_free(bev1); 1257 1.3 christos if (bev2) 1258 1.3 christos bufferevent_free(bev2); 1259 1.3 christos } 1260 1.3 christos 1261 1.3 christos struct bufferevent_filter_data_stuck { 1262 1.3 christos size_t header_size; 1263 1.3 christos size_t total_read; 1264 1.3 christos }; 1265 1.3 christos 1266 1.3 christos static void 1267 1.3 christos bufferevent_filter_data_stuck_readcb(struct bufferevent *bev, void *arg) 1268 1.3 christos { 1269 1.3 christos struct bufferevent_filter_data_stuck *filter_data = arg; 1270 1.3 christos struct evbuffer *input = bufferevent_get_input(bev); 1271 1.3 christos size_t read_size = evbuffer_get_length(input); 1272 1.3 christos evbuffer_drain(input, read_size); 1273 1.3 christos filter_data->total_read += read_size; 1274 1.3 christos } 1275 1.3 christos 1276 1.3 christos /** 1277 1.3 christos * This filter prepends header once before forwarding data. 1278 1.3 christos */ 1279 1.3 christos static enum bufferevent_filter_result 1280 1.3 christos bufferevent_filter_data_stuck_inputcb( 1281 1.3 christos struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit, 1282 1.3 christos enum bufferevent_flush_mode mode, void *ctx) 1283 1.3 christos { 1284 1.3 christos struct bufferevent_filter_data_stuck *filter_data = ctx; 1285 1.3 christos static int header_inserted = 0; 1286 1.3 christos size_t payload_size; 1287 1.3 christos size_t header_size = 0; 1288 1.3 christos 1289 1.3 christos if (!header_inserted) { 1290 1.3 christos char *header = calloc(filter_data->header_size, 1); 1291 1.3 christos evbuffer_add(dst, header, filter_data->header_size); 1292 1.3 christos free(header); 1293 1.3 christos header_size = filter_data->header_size; 1294 1.3 christos header_inserted = 1; 1295 1.3 christos } 1296 1.3 christos 1297 1.3 christos payload_size = evbuffer_get_length(src); 1298 1.3 christos if (payload_size > dst_limit - header_size) { 1299 1.3 christos payload_size = dst_limit - header_size; 1300 1.3 christos } 1301 1.3 christos 1302 1.3 christos tt_int_op(payload_size, ==, evbuffer_remove_buffer(src, dst, payload_size)); 1303 1.3 christos 1304 1.3 christos end: 1305 1.3 christos return BEV_OK; 1306 1.3 christos } 1307 1.3 christos 1308 1.3 christos static void 1309 1.3 christos test_bufferevent_filter_data_stuck(void *arg) 1310 1.3 christos { 1311 1.3 christos const size_t read_high_wm = 4096; 1312 1.3 christos struct bufferevent_filter_data_stuck filter_data; 1313 1.3 christos struct basic_test_data *data = arg; 1314 1.3 christos struct bufferevent *xpair[2]; 1315 1.3 christos struct bufferevent *filter = NULL; 1316 1.3 christos 1317 1.3 christos int options = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS; 1318 1.3 christos 1319 1.3 christos char payload[4096]; 1320 1.3 christos int payload_size = sizeof(payload); 1321 1.3 christos 1322 1.3 christos memset(&filter_data, 0, sizeof(filter_data)); 1323 1.3 christos filter_data.header_size = 20; 1324 1.3 christos 1325 1.3 christos tt_assert(bufferevent_pair_new(data->base, options, xpair) == 0); 1326 1.3 christos 1327 1.3 christos bufferevent_setwatermark(xpair[0], EV_READ, 0, read_high_wm); 1328 1.3 christos bufferevent_setwatermark(xpair[1], EV_READ, 0, read_high_wm); 1329 1.3 christos 1330 1.3 christos tt_assert( 1331 1.3 christos filter = 1332 1.3 christos bufferevent_filter_new(xpair[1], 1333 1.3 christos bufferevent_filter_data_stuck_inputcb, 1334 1.3 christos NULL, 1335 1.3 christos options, 1336 1.3 christos NULL, 1337 1.3 christos &filter_data)); 1338 1.3 christos 1339 1.3 christos bufferevent_setcb(filter, 1340 1.3 christos bufferevent_filter_data_stuck_readcb, 1341 1.3 christos NULL, 1342 1.3 christos NULL, 1343 1.3 christos &filter_data); 1344 1.3 christos 1345 1.3 christos tt_assert(bufferevent_enable(filter, EV_READ|EV_WRITE) == 0); 1346 1.3 christos 1347 1.3 christos bufferevent_setwatermark(filter, EV_READ, 0, read_high_wm); 1348 1.3 christos 1349 1.3 christos tt_assert(bufferevent_write(xpair[0], payload, sizeof(payload)) == 0); 1350 1.3 christos 1351 1.3 christos event_base_dispatch(data->base); 1352 1.3 christos 1353 1.3 christos tt_int_op(filter_data.total_read, ==, payload_size + filter_data.header_size); 1354 1.3 christos end: 1355 1.3 christos if (xpair[0]) 1356 1.3 christos bufferevent_free(xpair[0]); 1357 1.3 christos if (filter) 1358 1.3 christos bufferevent_free(filter); 1359 1.3 christos } 1360 1.3 christos 1361 1.1 christos struct testcase_t bufferevent_testcases[] = { 1362 1.1 christos 1363 1.1 christos LEGACY(bufferevent, TT_ISOLATED), 1364 1.1 christos LEGACY(bufferevent_pair, TT_ISOLATED), 1365 1.3 christos LEGACY(bufferevent_flush_normal, TT_ISOLATED), 1366 1.3 christos LEGACY(bufferevent_flush_flush, TT_ISOLATED), 1367 1.3 christos LEGACY(bufferevent_flush_finished, TT_ISOLATED), 1368 1.3 christos LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED), 1369 1.3 christos LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED), 1370 1.3 christos LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED), 1371 1.4 christos #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__) 1372 1.3 christos { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, 1373 1.4 christos TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY|TT_NO_LOGS, 1374 1.3 christos &basic_setup, NULL }, 1375 1.3 christos #endif 1376 1.1 christos LEGACY(bufferevent_watermarks, TT_ISOLATED), 1377 1.1 christos LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), 1378 1.1 christos LEGACY(bufferevent_filters, TT_ISOLATED), 1379 1.1 christos LEGACY(bufferevent_pair_filters, TT_ISOLATED), 1380 1.3 christos LEGACY(bufferevent_filters_disable, TT_ISOLATED), 1381 1.3 christos LEGACY(bufferevent_pair_filters_disable, TT_ISOLATED), 1382 1.1 christos { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE, 1383 1.2 christos &basic_setup, __UNCONST("") }, 1384 1.1 christos { "bufferevent_connect_defer", test_bufferevent_connect, 1385 1.2 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("defer") }, 1386 1.1 christos { "bufferevent_connect_lock", test_bufferevent_connect, 1387 1.2 christos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, __UNCONST("lock") }, 1388 1.1 christos { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1389 1.1 christos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1390 1.2 christos __UNCONST("defer lock") }, 1391 1.1 christos { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect, 1392 1.1 christos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1393 1.2 christos __UNCONST("lock defer unlocked") }, 1394 1.1 christos { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1395 1.1 christos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1396 1.1 christos { "bufferevent_timeout", test_bufferevent_timeouts, 1397 1.4 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("") }, 1398 1.1 christos { "bufferevent_timeout_pair", test_bufferevent_timeouts, 1399 1.2 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("pair") }, 1400 1.1 christos { "bufferevent_timeout_filter", test_bufferevent_timeouts, 1401 1.2 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("filter") }, 1402 1.1 christos { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts, 1403 1.2 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("filter pair") }, 1404 1.3 christos { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE, 1405 1.3 christos &basic_setup, __UNCONST("") }, 1406 1.3 christos { "bufferevent_trigger_defer", test_bufferevent_trigger, 1407 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, __UNCONST("defer") }, 1408 1.3 christos { "bufferevent_trigger_postpone", test_bufferevent_trigger, 1409 1.3 christos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1410 1.3 christos __UNCONST("postpone") }, 1411 1.3 christos { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger, 1412 1.3 christos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1413 1.3 christos __UNCONST("defer postpone") }, 1414 1.3 christos #ifdef EVENT__HAVE_LIBZ 1415 1.1 christos LEGACY(bufferevent_zlib, TT_ISOLATED), 1416 1.1 christos #else 1417 1.1 christos { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, 1418 1.1 christos #endif 1419 1.1 christos 1420 1.3 christos { "bufferevent_connect_fail_eventcb_defer", 1421 1.3 christos test_bufferevent_connect_fail_eventcb, 1422 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS }, 1423 1.3 christos { "bufferevent_connect_fail_eventcb", 1424 1.3 christos test_bufferevent_connect_fail_eventcb, 1425 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1426 1.3 christos 1427 1.3 christos { "bufferevent_socket_filter_inactive", 1428 1.3 christos test_bufferevent_socket_filter_inactive, 1429 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1430 1.3 christos { "bufferevent_pair_flush", 1431 1.3 christos test_bufferevent_pair_flush, 1432 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1433 1.3 christos { "bufferevent_filter_data_stuck", 1434 1.3 christos test_bufferevent_filter_data_stuck, 1435 1.3 christos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1436 1.3 christos 1437 1.1 christos END_OF_TESTCASES, 1438 1.1 christos }; 1439 1.1 christos 1440 1.4 christos #define TT_IOCP (TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP) 1441 1.4 christos #define TT_IOCP_LEGACY (TT_ISOLATED|TT_ENABLE_IOCP) 1442 1.1 christos struct testcase_t bufferevent_iocp_testcases[] = { 1443 1.4 christos LEGACY(bufferevent, TT_IOCP_LEGACY), 1444 1.3 christos LEGACY(bufferevent_flush_normal, TT_ISOLATED), 1445 1.3 christos LEGACY(bufferevent_flush_flush, TT_ISOLATED), 1446 1.3 christos LEGACY(bufferevent_flush_finished, TT_ISOLATED), 1447 1.4 christos LEGACY(bufferevent_watermarks, TT_IOCP_LEGACY), 1448 1.4 christos LEGACY(bufferevent_filters, TT_IOCP_LEGACY), 1449 1.4 christos LEGACY(bufferevent_filters_disable, TT_IOCP_LEGACY), 1450 1.4 christos 1451 1.1 christos { "bufferevent_connect", test_bufferevent_connect, 1452 1.4 christos TT_IOCP, &basic_setup, __UNCONST("") }, 1453 1.1 christos { "bufferevent_connect_defer", test_bufferevent_connect, 1454 1.4 christos TT_IOCP, &basic_setup, __UNCONST("defer") }, 1455 1.1 christos { "bufferevent_connect_lock", test_bufferevent_connect, 1456 1.4 christos TT_IOCP, &basic_setup, __UNCONST("lock") }, 1457 1.1 christos { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1458 1.4 christos TT_IOCP, &basic_setup, __UNCONST("defer lock") }, 1459 1.1 christos { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1460 1.4 christos TT_IOCP, &basic_setup, NULL }, 1461 1.1 christos { "bufferevent_connect_nonblocking", test_bufferevent_connect, 1462 1.4 christos TT_IOCP, &basic_setup, __UNCONST("unset_connectex") }, 1463 1.1 christos 1464 1.3 christos { "bufferevent_connect_fail_eventcb_defer", 1465 1.3 christos test_bufferevent_connect_fail_eventcb, 1466 1.4 christos TT_IOCP, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS }, 1467 1.3 christos { "bufferevent_connect_fail_eventcb", 1468 1.4 christos test_bufferevent_connect_fail_eventcb, TT_IOCP, &basic_setup, NULL }, 1469 1.3 christos 1470 1.1 christos END_OF_TESTCASES, 1471 1.1 christos }; 1472