1*eabc0478Schristos /* $NetBSD: regress_bufferevent.c,v 1.7 2024/08/18 20:47:23 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> 58585484eSchristos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 68585484eSchristos * 78585484eSchristos * Redistribution and use in source and binary forms, with or without 88585484eSchristos * modification, are permitted provided that the following conditions 98585484eSchristos * are met: 108585484eSchristos * 1. Redistributions of source code must retain the above copyright 118585484eSchristos * notice, this list of conditions and the following disclaimer. 128585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 138585484eSchristos * notice, this list of conditions and the following disclaimer in the 148585484eSchristos * documentation and/or other materials provided with the distribution. 158585484eSchristos * 3. The name of the author may not be used to endorse or promote products 168585484eSchristos * derived from this software without specific prior written permission. 178585484eSchristos * 188585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 198585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 208585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 218585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 228585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 238585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 248585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 258585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 268585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 278585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 288585484eSchristos */ 298585484eSchristos #include "util-internal.h" 308585484eSchristos 318585484eSchristos /* The old tests here need assertions to work. */ 328585484eSchristos #undef NDEBUG 338585484eSchristos 34*eabc0478Schristos /** 35*eabc0478Schristos * - clang supports __has_feature 36*eabc0478Schristos * - gcc supports __SANITIZE_ADDRESS__ 37*eabc0478Schristos * 38*eabc0478Schristos * Let's set __SANITIZE_ADDRESS__ if __has_feature(address_sanitizer) 39*eabc0478Schristos */ 40*eabc0478Schristos #ifndef __has_feature 41*eabc0478Schristos #define __has_feature(x) 0 42*eabc0478Schristos #endif 43*eabc0478Schristos #if !defined(__SANITIZE_ADDRESS__) && __has_feature(address_sanitizer) 44*eabc0478Schristos #define __SANITIZE_ADDRESS__ 45*eabc0478Schristos #endif 46*eabc0478Schristos 478585484eSchristos #ifdef _WIN32 488585484eSchristos #include <winsock2.h> 498585484eSchristos #include <windows.h> 508585484eSchristos #endif 518585484eSchristos 528585484eSchristos #include "event2/event-config.h" 538585484eSchristos 548585484eSchristos #include <sys/types.h> 558585484eSchristos #include <sys/stat.h> 568585484eSchristos #ifdef EVENT__HAVE_SYS_TIME_H 578585484eSchristos #include <sys/time.h> 588585484eSchristos #endif 598585484eSchristos #include <sys/queue.h> 608585484eSchristos #ifndef _WIN32 618585484eSchristos #include <sys/socket.h> 628585484eSchristos #include <sys/wait.h> 638585484eSchristos #include <signal.h> 648585484eSchristos #include <unistd.h> 658585484eSchristos #include <netdb.h> 668585484eSchristos #include <netinet/in.h> 678585484eSchristos #endif 688585484eSchristos #include <fcntl.h> 698585484eSchristos #include <signal.h> 708585484eSchristos #include <stdlib.h> 718585484eSchristos #include <stdio.h> 728585484eSchristos #include <string.h> 738585484eSchristos #include <errno.h> 748585484eSchristos #include <assert.h> 758585484eSchristos 768585484eSchristos #ifdef EVENT__HAVE_ARPA_INET_H 778585484eSchristos #include <arpa/inet.h> 788585484eSchristos #endif 798585484eSchristos 808585484eSchristos #include "event2/event-config.h" 818585484eSchristos #include "event2/event.h" 828585484eSchristos #include "event2/event_struct.h" 838585484eSchristos #include "event2/event_compat.h" 848585484eSchristos #include "event2/tag.h" 858585484eSchristos #include "event2/buffer.h" 868585484eSchristos #include "event2/bufferevent.h" 878585484eSchristos #include "event2/bufferevent_compat.h" 888585484eSchristos #include "event2/bufferevent_struct.h" 898585484eSchristos #include "event2/listener.h" 908585484eSchristos #include "event2/util.h" 918585484eSchristos 928585484eSchristos #include "bufferevent-internal.h" 937476e6e4Schristos #include "evthread-internal.h" 948585484eSchristos #include "util-internal.h" 958585484eSchristos #ifdef _WIN32 968585484eSchristos #include "iocp-internal.h" 978585484eSchristos #endif 988585484eSchristos 998585484eSchristos #include "regress.h" 1008585484eSchristos #include "regress_testutils.h" 1018585484eSchristos 1028585484eSchristos /* 1038585484eSchristos * simple bufferevent test 1048585484eSchristos */ 1058585484eSchristos 1068585484eSchristos static void 1078585484eSchristos readcb(struct bufferevent *bev, void *arg) 1088585484eSchristos { 1098585484eSchristos if (evbuffer_get_length(bev->input) == 8333) { 1108585484eSchristos struct evbuffer *evbuf = evbuffer_new(); 1118585484eSchristos assert(evbuf != NULL); 1128585484eSchristos 1138585484eSchristos /* gratuitous test of bufferevent_read_buffer */ 1148585484eSchristos bufferevent_read_buffer(bev, evbuf); 1158585484eSchristos 1168585484eSchristos bufferevent_disable(bev, EV_READ); 1178585484eSchristos 1188585484eSchristos if (evbuffer_get_length(evbuf) == 8333) { 1198585484eSchristos test_ok++; 1208585484eSchristos } 1218585484eSchristos 1228585484eSchristos evbuffer_free(evbuf); 1238585484eSchristos } 1248585484eSchristos } 1258585484eSchristos 1268585484eSchristos static void 1278585484eSchristos writecb(struct bufferevent *bev, void *arg) 1288585484eSchristos { 1298585484eSchristos if (evbuffer_get_length(bev->output) == 0) { 1308585484eSchristos test_ok++; 1318585484eSchristos } 1328585484eSchristos } 1338585484eSchristos 1348585484eSchristos static void 1358585484eSchristos errorcb(struct bufferevent *bev, short what, void *arg) 1368585484eSchristos { 1378585484eSchristos test_ok = -2; 1388585484eSchristos } 1398585484eSchristos 1408585484eSchristos static void 141*eabc0478Schristos test_bufferevent_impl(int use_pair, int flush) 1428585484eSchristos { 1438585484eSchristos struct bufferevent *bev1 = NULL, *bev2 = NULL; 1448585484eSchristos char buffer[8333]; 1458585484eSchristos int i; 146*eabc0478Schristos int expected = 2; 1478585484eSchristos 1488585484eSchristos if (use_pair) { 1498585484eSchristos struct bufferevent *pair[2]; 1508585484eSchristos tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 1518585484eSchristos bev1 = pair[0]; 1528585484eSchristos bev2 = pair[1]; 1538585484eSchristos bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1); 1548585484eSchristos bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL); 155*eabc0478Schristos tt_fd_op(bufferevent_getfd(bev1), ==, EVUTIL_INVALID_SOCKET); 1568585484eSchristos tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 1578585484eSchristos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2); 1588585484eSchristos tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1); 1598585484eSchristos } else { 1608585484eSchristos bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL); 1618585484eSchristos bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL); 162*eabc0478Schristos tt_fd_op(bufferevent_getfd(bev1), ==, pair[0]); 1638585484eSchristos tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL); 1648585484eSchristos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 1658585484eSchristos tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL); 1668585484eSchristos } 1678585484eSchristos 1688585484eSchristos { 1698585484eSchristos /* Test getcb. */ 1708585484eSchristos bufferevent_data_cb r, w; 1718585484eSchristos bufferevent_event_cb e; 1728585484eSchristos void *a; 1738585484eSchristos bufferevent_getcb(bev1, &r, &w, &e, &a); 1748585484eSchristos tt_ptr_op(r, ==, readcb); 1758585484eSchristos tt_ptr_op(w, ==, writecb); 1768585484eSchristos tt_ptr_op(e, ==, errorcb); 1778585484eSchristos tt_ptr_op(a, ==, use_pair ? bev1 : NULL); 1788585484eSchristos } 1798585484eSchristos 1808585484eSchristos bufferevent_disable(bev1, EV_READ); 1818585484eSchristos bufferevent_enable(bev2, EV_READ); 1828585484eSchristos 1838585484eSchristos tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE); 1848585484eSchristos tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ); 1858585484eSchristos 1868585484eSchristos for (i = 0; i < (int)sizeof(buffer); i++) 1878585484eSchristos buffer[i] = i; 1888585484eSchristos 1898585484eSchristos bufferevent_write(bev1, buffer, sizeof(buffer)); 190*eabc0478Schristos if (flush >= 0) { 191*eabc0478Schristos tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0); 192*eabc0478Schristos } 1938585484eSchristos 1948585484eSchristos event_dispatch(); 1958585484eSchristos 1968585484eSchristos bufferevent_free(bev2); 1977476e6e4Schristos tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL); 1987476e6e4Schristos bufferevent_free(bev1); 1998585484eSchristos 200*eabc0478Schristos /** Only pair call errorcb for BEV_FINISHED */ 201*eabc0478Schristos if (use_pair && flush == BEV_FINISHED) { 202*eabc0478Schristos expected = -1; 203*eabc0478Schristos } 204*eabc0478Schristos if (test_ok != expected) 2058585484eSchristos test_ok = 0; 2068585484eSchristos end: 2078585484eSchristos ; 2088585484eSchristos } 2098585484eSchristos 210*eabc0478Schristos static void test_bufferevent(void) { test_bufferevent_impl(0, -1); } 211*eabc0478Schristos static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); } 2128585484eSchristos 213*eabc0478Schristos static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); } 214*eabc0478Schristos static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); } 215*eabc0478Schristos static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); } 2168585484eSchristos 217*eabc0478Schristos static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); } 218*eabc0478Schristos static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); } 219*eabc0478Schristos static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); } 220*eabc0478Schristos 221*eabc0478Schristos #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__) 2227476e6e4Schristos /** 2237476e6e4Schristos * Trace lock/unlock/alloc/free for locks. 2247476e6e4Schristos * (More heavier then evthread_debug*) 2257476e6e4Schristos */ 2267476e6e4Schristos typedef struct 2277476e6e4Schristos { 2287476e6e4Schristos void *lock; 2297476e6e4Schristos enum { 2307476e6e4Schristos ALLOC, FREE, 2317476e6e4Schristos } status; 2327476e6e4Schristos size_t locked /** allow recursive locking */; 2337476e6e4Schristos } lock_wrapper; 2347476e6e4Schristos struct lock_unlock_base 2357476e6e4Schristos { 2367476e6e4Schristos /* Original callbacks */ 2377476e6e4Schristos struct evthread_lock_callbacks cbs; 2387476e6e4Schristos /* Map of locks */ 2397476e6e4Schristos lock_wrapper *locks; 2407476e6e4Schristos size_t nr_locks; 2417476e6e4Schristos } lu_base = { 2427476e6e4Schristos .locks = NULL, 2437476e6e4Schristos }; 2447476e6e4Schristos 2457476e6e4Schristos static lock_wrapper *lu_find(void *lock_) 2467476e6e4Schristos { 2477476e6e4Schristos size_t i; 2487476e6e4Schristos for (i = 0; i < lu_base.nr_locks; ++i) { 2497476e6e4Schristos lock_wrapper *lock = &lu_base.locks[i]; 2507476e6e4Schristos if (lock->lock == lock_) 2517476e6e4Schristos return lock; 2527476e6e4Schristos } 2537476e6e4Schristos return NULL; 2547476e6e4Schristos } 2557476e6e4Schristos 2567476e6e4Schristos static void *trace_lock_alloc(unsigned locktype) 2577476e6e4Schristos { 258*eabc0478Schristos void *lock; 2597476e6e4Schristos ++lu_base.nr_locks; 2607476e6e4Schristos lu_base.locks = realloc(lu_base.locks, 2617476e6e4Schristos sizeof(lock_wrapper) * lu_base.nr_locks); 262*eabc0478Schristos lock = lu_base.cbs.alloc(locktype); 2637476e6e4Schristos lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 }; 2647476e6e4Schristos return lock; 2657476e6e4Schristos } 2667476e6e4Schristos static void trace_lock_free(void *lock_, unsigned locktype) 2677476e6e4Schristos { 2687476e6e4Schristos lock_wrapper *lock = lu_find(lock_); 2697476e6e4Schristos if (!lock || lock->status == FREE || lock->locked) { 2707476e6e4Schristos TT_FAIL(("lock: free error")); 2717476e6e4Schristos } else { 2727476e6e4Schristos lock->status = FREE; 2737476e6e4Schristos lu_base.cbs.free(lock_, locktype); 2747476e6e4Schristos } 2757476e6e4Schristos } 2767476e6e4Schristos static int trace_lock_lock(unsigned mode, void *lock_) 2777476e6e4Schristos { 2787476e6e4Schristos lock_wrapper *lock = lu_find(lock_); 2797476e6e4Schristos if (!lock || lock->status == FREE) { 2807476e6e4Schristos TT_FAIL(("lock: lock error")); 2817476e6e4Schristos return -1; 2827476e6e4Schristos } else { 2837476e6e4Schristos ++lock->locked; 2847476e6e4Schristos return lu_base.cbs.lock(mode, lock_); 2857476e6e4Schristos } 2867476e6e4Schristos } 2877476e6e4Schristos static int trace_lock_unlock(unsigned mode, void *lock_) 2887476e6e4Schristos { 2897476e6e4Schristos lock_wrapper *lock = lu_find(lock_); 2907476e6e4Schristos if (!lock || lock->status == FREE || !lock->locked) { 2917476e6e4Schristos TT_FAIL(("lock: unlock error")); 2927476e6e4Schristos return -1; 2937476e6e4Schristos } else { 2947476e6e4Schristos --lock->locked; 2957476e6e4Schristos return lu_base.cbs.unlock(mode, lock_); 2967476e6e4Schristos } 2977476e6e4Schristos } 298*eabc0478Schristos static void lock_unlock_free_thread_cbs(void) 2997476e6e4Schristos { 3007476e6e4Schristos event_base_free(NULL); 3017476e6e4Schristos 302*eabc0478Schristos if (libevent_tests_running_in_debug_mode) 303*eabc0478Schristos libevent_global_shutdown(); 304*eabc0478Schristos 3057476e6e4Schristos /** drop immutable flag */ 3067476e6e4Schristos evthread_set_lock_callbacks(NULL); 3077476e6e4Schristos /** avoid calling of event_global_setup_locks_() for new cbs */ 3087476e6e4Schristos libevent_global_shutdown(); 3097476e6e4Schristos /** drop immutable flag for non-debug ops (since called after shutdown) */ 3107476e6e4Schristos evthread_set_lock_callbacks(NULL); 3117476e6e4Schristos } 3127476e6e4Schristos 3137476e6e4Schristos static int use_lock_unlock_profiler(void) 3147476e6e4Schristos { 3157476e6e4Schristos struct evthread_lock_callbacks cbs = { 3167476e6e4Schristos EVTHREAD_LOCK_API_VERSION, 3177476e6e4Schristos EVTHREAD_LOCKTYPE_RECURSIVE, 3187476e6e4Schristos trace_lock_alloc, 3197476e6e4Schristos trace_lock_free, 3207476e6e4Schristos trace_lock_lock, 3217476e6e4Schristos trace_lock_unlock, 3227476e6e4Schristos }; 3237476e6e4Schristos memcpy(&lu_base.cbs, evthread_get_lock_callbacks(), 3247476e6e4Schristos sizeof(lu_base.cbs)); 3257476e6e4Schristos { 3267476e6e4Schristos lock_unlock_free_thread_cbs(); 3277476e6e4Schristos 3287476e6e4Schristos evthread_set_lock_callbacks(&cbs); 3297476e6e4Schristos /** re-create debug locks correctly */ 3307476e6e4Schristos evthread_enable_lock_debugging(); 3317476e6e4Schristos 3327476e6e4Schristos event_init(); 3337476e6e4Schristos } 3347476e6e4Schristos return 0; 3357476e6e4Schristos } 3367476e6e4Schristos static void free_lock_unlock_profiler(struct basic_test_data *data) 3377476e6e4Schristos { 338*eabc0478Schristos /** fix "held_by" for kqueue */ 339*eabc0478Schristos evthread_set_lock_callbacks(NULL); 340*eabc0478Schristos 3417476e6e4Schristos lock_unlock_free_thread_cbs(); 3427476e6e4Schristos free(lu_base.locks); 3437476e6e4Schristos data->base = NULL; 3447476e6e4Schristos } 3457476e6e4Schristos 3467476e6e4Schristos static void test_bufferevent_pair_release_lock(void *arg) 3477476e6e4Schristos { 3487476e6e4Schristos struct basic_test_data *data = arg; 3497476e6e4Schristos use_lock_unlock_profiler(); 3507476e6e4Schristos { 3517476e6e4Schristos struct bufferevent *pair[2]; 3527476e6e4Schristos if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) { 3537476e6e4Schristos bufferevent_free(pair[0]); 3547476e6e4Schristos bufferevent_free(pair[1]); 3557476e6e4Schristos } else 3567476e6e4Schristos tt_abort_perror("bufferevent_pair_new"); 3577476e6e4Schristos } 3587476e6e4Schristos free_lock_unlock_profiler(data); 3597476e6e4Schristos end: 3607476e6e4Schristos ; 3617476e6e4Schristos } 3627476e6e4Schristos #endif 3637476e6e4Schristos 3648585484eSchristos /* 3658585484eSchristos * test watermarks and bufferevent 3668585484eSchristos */ 3678585484eSchristos 3688585484eSchristos static void 3698585484eSchristos wm_readcb(struct bufferevent *bev, void *arg) 3708585484eSchristos { 3718585484eSchristos struct evbuffer *evbuf = evbuffer_new(); 3728585484eSchristos int len = (int)evbuffer_get_length(bev->input); 3738585484eSchristos static int nread; 3748585484eSchristos 3758585484eSchristos assert(len >= 10 && len <= 20); 3768585484eSchristos 3778585484eSchristos assert(evbuf != NULL); 3788585484eSchristos 3798585484eSchristos /* gratuitous test of bufferevent_read_buffer */ 3808585484eSchristos bufferevent_read_buffer(bev, evbuf); 3818585484eSchristos 3828585484eSchristos nread += len; 3838585484eSchristos if (nread == 65000) { 3848585484eSchristos bufferevent_disable(bev, EV_READ); 3858585484eSchristos test_ok++; 3868585484eSchristos } 3878585484eSchristos 3888585484eSchristos evbuffer_free(evbuf); 3898585484eSchristos } 3908585484eSchristos 3918585484eSchristos static void 3928585484eSchristos wm_writecb(struct bufferevent *bev, void *arg) 3938585484eSchristos { 3948585484eSchristos assert(evbuffer_get_length(bev->output) <= 100); 3958585484eSchristos if (evbuffer_get_length(bev->output) == 0) { 3968585484eSchristos evbuffer_drain(bev->output, evbuffer_get_length(bev->output)); 3978585484eSchristos test_ok++; 3988585484eSchristos } 3998585484eSchristos } 4008585484eSchristos 4018585484eSchristos static void 4028585484eSchristos wm_errorcb(struct bufferevent *bev, short what, void *arg) 4038585484eSchristos { 4048585484eSchristos test_ok = -2; 4058585484eSchristos } 4068585484eSchristos 4078585484eSchristos static void 4088585484eSchristos test_bufferevent_watermarks_impl(int use_pair) 4098585484eSchristos { 4108585484eSchristos struct bufferevent *bev1 = NULL, *bev2 = NULL; 4118585484eSchristos char buffer[65000]; 412b8ecfcfeSchristos size_t low, high; 4138585484eSchristos int i; 4148585484eSchristos test_ok = 0; 4158585484eSchristos 4168585484eSchristos if (use_pair) { 4178585484eSchristos struct bufferevent *pair[2]; 4188585484eSchristos tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 4198585484eSchristos bev1 = pair[0]; 4208585484eSchristos bev2 = pair[1]; 4218585484eSchristos bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL); 4228585484eSchristos bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL); 4238585484eSchristos } else { 4248585484eSchristos bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL); 4258585484eSchristos bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL); 4268585484eSchristos } 4278585484eSchristos tt_assert(bev1); 4288585484eSchristos tt_assert(bev2); 4298585484eSchristos bufferevent_disable(bev1, EV_READ); 4308585484eSchristos bufferevent_enable(bev2, EV_READ); 4318585484eSchristos 432b8ecfcfeSchristos /* By default, low watermarks are set to 0 */ 433b8ecfcfeSchristos bufferevent_getwatermark(bev1, EV_READ, &low, NULL); 434b8ecfcfeSchristos tt_int_op(low, ==, 0); 435b8ecfcfeSchristos bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL); 436b8ecfcfeSchristos tt_int_op(low, ==, 0); 437b8ecfcfeSchristos 4388585484eSchristos for (i = 0; i < (int)sizeof(buffer); i++) 4398585484eSchristos buffer[i] = (char)i; 4408585484eSchristos 4418585484eSchristos /* limit the reading on the receiving bufferevent */ 4428585484eSchristos bufferevent_setwatermark(bev2, EV_READ, 10, 20); 4438585484eSchristos 444b8ecfcfeSchristos bufferevent_getwatermark(bev2, EV_READ, &low, &high); 445b8ecfcfeSchristos tt_int_op(low, ==, 10); 446b8ecfcfeSchristos tt_int_op(high, ==, 20); 447b8ecfcfeSchristos 4488585484eSchristos /* Tell the sending bufferevent not to notify us till it's down to 4498585484eSchristos 100 bytes. */ 4508585484eSchristos bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000); 4518585484eSchristos 452b8ecfcfeSchristos bufferevent_getwatermark(bev1, EV_WRITE, &low, &high); 453b8ecfcfeSchristos tt_int_op(low, ==, 100); 454b8ecfcfeSchristos tt_int_op(high, ==, 2000); 455b8ecfcfeSchristos 4567476e6e4Schristos { 4577476e6e4Schristos int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high); 4587476e6e4Schristos tt_int_op(r, !=, 0); 4597476e6e4Schristos } 4607476e6e4Schristos 4618585484eSchristos bufferevent_write(bev1, buffer, sizeof(buffer)); 4628585484eSchristos 4638585484eSchristos event_dispatch(); 4648585484eSchristos 4658585484eSchristos tt_int_op(test_ok, ==, 2); 4668585484eSchristos 4678585484eSchristos /* The write callback drained all the data from outbuf, so we 4688585484eSchristos * should have removed the write event... */ 4698585484eSchristos tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL)); 4708585484eSchristos 4718585484eSchristos end: 4728585484eSchristos if (bev1) 4738585484eSchristos bufferevent_free(bev1); 4748585484eSchristos if (bev2) 4758585484eSchristos bufferevent_free(bev2); 4768585484eSchristos } 4778585484eSchristos 4788585484eSchristos static void 4798585484eSchristos test_bufferevent_watermarks(void) 4808585484eSchristos { 4818585484eSchristos test_bufferevent_watermarks_impl(0); 4828585484eSchristos } 4838585484eSchristos 4848585484eSchristos static void 4858585484eSchristos test_bufferevent_pair_watermarks(void) 4868585484eSchristos { 4878585484eSchristos test_bufferevent_watermarks_impl(1); 4888585484eSchristos } 4898585484eSchristos 4908585484eSchristos /* 4918585484eSchristos * Test bufferevent filters 4928585484eSchristos */ 4938585484eSchristos 4948585484eSchristos /* strip an 'x' from each byte */ 4958585484eSchristos 4968585484eSchristos static enum bufferevent_filter_result 4978585484eSchristos bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst, 4988585484eSchristos ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 4998585484eSchristos { 5008585484eSchristos const unsigned char *buffer; 5018585484eSchristos unsigned i; 5028585484eSchristos 5038585484eSchristos buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 5048585484eSchristos for (i = 0; i < evbuffer_get_length(src); i += 2) { 505*eabc0478Schristos if (buffer[i] == '-') 506*eabc0478Schristos continue; 507*eabc0478Schristos 5088585484eSchristos assert(buffer[i] == 'x'); 5098585484eSchristos evbuffer_add(dst, buffer + i + 1, 1); 5108585484eSchristos } 5118585484eSchristos 5128585484eSchristos evbuffer_drain(src, i); 5138585484eSchristos return (BEV_OK); 5148585484eSchristos } 5158585484eSchristos 5168585484eSchristos /* add an 'x' before each byte */ 5178585484eSchristos 5188585484eSchristos static enum bufferevent_filter_result 5198585484eSchristos bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst, 5208585484eSchristos ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) 5218585484eSchristos { 5228585484eSchristos const unsigned char *buffer; 5238585484eSchristos unsigned i; 524*eabc0478Schristos struct bufferevent **bevp = ctx; 5258585484eSchristos 526*eabc0478Schristos ++test_ok; 527*eabc0478Schristos 528*eabc0478Schristos if (test_ok == 1) { 5298585484eSchristos buffer = evbuffer_pullup(src, evbuffer_get_length(src)); 5308585484eSchristos for (i = 0; i < evbuffer_get_length(src); ++i) { 5318585484eSchristos evbuffer_add(dst, "x", 1); 5328585484eSchristos evbuffer_add(dst, buffer + i, 1); 5338585484eSchristos } 5348585484eSchristos evbuffer_drain(src, evbuffer_get_length(src)); 535*eabc0478Schristos } else { 536*eabc0478Schristos return BEV_ERROR; 537*eabc0478Schristos } 538*eabc0478Schristos 539*eabc0478Schristos if (bevp && test_ok == 1) { 540*eabc0478Schristos int prev = ++test_ok; 541*eabc0478Schristos bufferevent_write(*bevp, "-", 1); 542*eabc0478Schristos /* check that during this bufferevent_write() 543*eabc0478Schristos * bufferevent_output_filter() will not be called again */ 544*eabc0478Schristos assert(test_ok == prev); 545*eabc0478Schristos --test_ok; 546*eabc0478Schristos } 547*eabc0478Schristos 5488585484eSchristos return (BEV_OK); 5498585484eSchristos } 5508585484eSchristos 5518585484eSchristos static void 552*eabc0478Schristos test_bufferevent_filters_impl(int use_pair, int disable) 5538585484eSchristos { 5548585484eSchristos struct bufferevent *bev1 = NULL, *bev2 = NULL; 5558585484eSchristos struct bufferevent *bev1_base = NULL, *bev2_base = NULL; 5568585484eSchristos char buffer[8333]; 5578585484eSchristos int i; 5588585484eSchristos 5598585484eSchristos test_ok = 0; 5608585484eSchristos 5618585484eSchristos if (use_pair) { 5628585484eSchristos struct bufferevent *pair[2]; 5638585484eSchristos tt_assert(0 == bufferevent_pair_new(NULL, 0, pair)); 5648585484eSchristos bev1 = pair[0]; 5658585484eSchristos bev2 = pair[1]; 5668585484eSchristos } else { 5678585484eSchristos bev1 = bufferevent_socket_new(NULL, pair[0], 0); 5688585484eSchristos bev2 = bufferevent_socket_new(NULL, pair[1], 0); 5698585484eSchristos } 5708585484eSchristos bev1_base = bev1; 5718585484eSchristos bev2_base = bev2; 5728585484eSchristos 5738585484eSchristos for (i = 0; i < (int)sizeof(buffer); i++) 5748585484eSchristos buffer[i] = i; 5758585484eSchristos 5768585484eSchristos bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter, 577*eabc0478Schristos BEV_OPT_CLOSE_ON_FREE, NULL, 578*eabc0478Schristos disable ? &bev1 : NULL); 5798585484eSchristos 5808585484eSchristos bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter, 5818585484eSchristos NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 5828585484eSchristos bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL); 5838585484eSchristos bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL); 5848585484eSchristos 5858585484eSchristos tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base); 5868585484eSchristos tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base); 587*eabc0478Schristos tt_fd_op(bufferevent_getfd(bev1), ==, bufferevent_getfd(bev1_base)); 588*eabc0478Schristos tt_fd_op(bufferevent_getfd(bev2), ==, bufferevent_getfd(bev2_base)); 5898585484eSchristos 5908585484eSchristos bufferevent_disable(bev1, EV_READ); 5918585484eSchristos bufferevent_enable(bev2, EV_READ); 5928585484eSchristos /* insert some filters */ 5938585484eSchristos bufferevent_write(bev1, buffer, sizeof(buffer)); 5948585484eSchristos 5958585484eSchristos event_dispatch(); 5968585484eSchristos 597*eabc0478Schristos if (test_ok != 3 + !!disable) 5988585484eSchristos test_ok = 0; 5998585484eSchristos 6008585484eSchristos end: 6018585484eSchristos if (bev1) 6028585484eSchristos bufferevent_free(bev1); 6038585484eSchristos if (bev2) 6048585484eSchristos bufferevent_free(bev2); 6058585484eSchristos 6068585484eSchristos } 6078585484eSchristos 608*eabc0478Schristos static void test_bufferevent_filters(void) 609*eabc0478Schristos { test_bufferevent_filters_impl(0, 0); } 610*eabc0478Schristos static void test_bufferevent_pair_filters(void) 611*eabc0478Schristos { test_bufferevent_filters_impl(1, 0); } 612*eabc0478Schristos static void test_bufferevent_filters_disable(void) 613*eabc0478Schristos { test_bufferevent_filters_impl(0, 1); } 614*eabc0478Schristos static void test_bufferevent_pair_filters_disable(void) 615*eabc0478Schristos { test_bufferevent_filters_impl(1, 1); } 6168585484eSchristos 6178585484eSchristos 6188585484eSchristos static void 6198585484eSchristos sender_writecb(struct bufferevent *bev, void *ctx) 6208585484eSchristos { 6218585484eSchristos if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { 6228585484eSchristos bufferevent_disable(bev,EV_READ|EV_WRITE); 623b8ecfcfeSchristos TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev))); 6248585484eSchristos bufferevent_free(bev); 6258585484eSchristos } 6268585484eSchristos } 6278585484eSchristos 6288585484eSchristos static void 6298585484eSchristos sender_errorcb(struct bufferevent *bev, short what, void *ctx) 6308585484eSchristos { 6318585484eSchristos TT_FAIL(("Got sender error %d",(int)what)); 6328585484eSchristos } 6338585484eSchristos 6348585484eSchristos static int bufferevent_connect_test_flags = 0; 635b8ecfcfeSchristos static int bufferevent_trigger_test_flags = 0; 6368585484eSchristos static int n_strings_read = 0; 6378585484eSchristos static int n_reads_invoked = 0; 638*eabc0478Schristos static int n_events_invoked = 0; 6398585484eSchristos 6408585484eSchristos #define TEST_STR "Now is the time for all good events to signal for " \ 6418585484eSchristos "the good of their protocol" 6428585484eSchristos static void 6438585484eSchristos listen_cb(struct evconnlistener *listener, evutil_socket_t fd, 6448585484eSchristos struct sockaddr *sa, int socklen, void *arg) 6458585484eSchristos { 6468585484eSchristos struct event_base *base = arg; 6478585484eSchristos struct bufferevent *bev; 6488585484eSchristos const char s[] = TEST_STR; 6498585484eSchristos TT_BLATHER(("Got a request on socket %d", (int)fd )); 6508585484eSchristos bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags); 6518585484eSchristos tt_assert(bev); 6528585484eSchristos bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL); 6538585484eSchristos bufferevent_write(bev, s, sizeof(s)); 6548585484eSchristos end: 6558585484eSchristos ; 6568585484eSchristos } 6578585484eSchristos 658*eabc0478Schristos static evutil_socket_t 659*eabc0478Schristos fake_listener_create(struct sockaddr_in *localhost) 660*eabc0478Schristos { 661*eabc0478Schristos struct sockaddr *sa = (struct sockaddr *)localhost; 662*eabc0478Schristos evutil_socket_t fd = -1; 663*eabc0478Schristos ev_socklen_t slen = sizeof(*localhost); 664*eabc0478Schristos 665*eabc0478Schristos memset(localhost, 0, sizeof(*localhost)); 666*eabc0478Schristos localhost->sin_port = 0; /* have the kernel pick a port */ 667*eabc0478Schristos localhost->sin_addr.s_addr = htonl(0x7f000001L); 668*eabc0478Schristos localhost->sin_family = AF_INET; 669*eabc0478Schristos 670*eabc0478Schristos /* bind, but don't listen or accept. should trigger 671*eabc0478Schristos "Connection refused" reliably on most platforms. */ 672*eabc0478Schristos fd = socket(localhost->sin_family, SOCK_STREAM, 0); 673*eabc0478Schristos tt_assert(fd >= 0); 674*eabc0478Schristos tt_assert(bind(fd, sa, slen) == 0); 675*eabc0478Schristos tt_assert(getsockname(fd, sa, &slen) == 0); 676*eabc0478Schristos 677*eabc0478Schristos return fd; 678*eabc0478Schristos 679*eabc0478Schristos end: 680*eabc0478Schristos return -1; 681*eabc0478Schristos } 682*eabc0478Schristos 6838585484eSchristos static void 6848585484eSchristos reader_eventcb(struct bufferevent *bev, short what, void *ctx) 6858585484eSchristos { 6868585484eSchristos struct event_base *base = ctx; 6878585484eSchristos if (what & BEV_EVENT_ERROR) { 6888585484eSchristos perror("foobar"); 6898585484eSchristos TT_FAIL(("got connector error %d", (int)what)); 6908585484eSchristos return; 6918585484eSchristos } 6928585484eSchristos if (what & BEV_EVENT_CONNECTED) { 693b8ecfcfeSchristos TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev))); 6948585484eSchristos bufferevent_enable(bev, EV_READ); 6958585484eSchristos } 6968585484eSchristos if (what & BEV_EVENT_EOF) { 6978585484eSchristos char buf[512]; 6988585484eSchristos size_t n; 6998585484eSchristos n = bufferevent_read(bev, buf, sizeof(buf)-1); 700b8ecfcfeSchristos tt_int_op(n, >=, 0); 7018585484eSchristos buf[n] = '\0'; 7028585484eSchristos tt_str_op(buf, ==, TEST_STR); 7038585484eSchristos if (++n_strings_read == 2) 7048585484eSchristos event_base_loopexit(base, NULL); 705b8ecfcfeSchristos TT_BLATHER(("EOF on %d: %d strings read.", 706b8ecfcfeSchristos (int)bufferevent_getfd(bev), n_strings_read)); 7078585484eSchristos } 7088585484eSchristos end: 7098585484eSchristos ; 7108585484eSchristos } 7118585484eSchristos 7128585484eSchristos static void 713*eabc0478Schristos reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx) 714*eabc0478Schristos { 715*eabc0478Schristos TT_BLATHER(("Read eventcb simple invoked on %d.", 716*eabc0478Schristos (int)bufferevent_getfd(bev))); 717*eabc0478Schristos n_events_invoked++; 718*eabc0478Schristos } 719*eabc0478Schristos 720*eabc0478Schristos static void 7218585484eSchristos reader_readcb(struct bufferevent *bev, void *ctx) 7228585484eSchristos { 723b8ecfcfeSchristos TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 7248585484eSchristos n_reads_invoked++; 7258585484eSchristos } 7268585484eSchristos 7278585484eSchristos static void 7288585484eSchristos test_bufferevent_connect(void *arg) 7298585484eSchristos { 7308585484eSchristos struct basic_test_data *data = arg; 7318585484eSchristos struct evconnlistener *lev=NULL; 7328585484eSchristos struct bufferevent *bev1=NULL, *bev2=NULL; 7338585484eSchristos struct sockaddr_in localhost; 7348585484eSchristos struct sockaddr_storage ss; 7358585484eSchristos struct sockaddr *sa; 7368585484eSchristos ev_socklen_t slen; 7378585484eSchristos 7388585484eSchristos int be_flags=BEV_OPT_CLOSE_ON_FREE; 7398585484eSchristos 7408585484eSchristos if (strstr((char*)data->setup_data, "defer")) { 7418585484eSchristos be_flags |= BEV_OPT_DEFER_CALLBACKS; 7428585484eSchristos } 7438585484eSchristos if (strstr((char*)data->setup_data, "unlocked")) { 7448585484eSchristos be_flags |= BEV_OPT_UNLOCK_CALLBACKS; 7458585484eSchristos } 7468585484eSchristos if (strstr((char*)data->setup_data, "lock")) { 7478585484eSchristos be_flags |= BEV_OPT_THREADSAFE; 7488585484eSchristos } 7498585484eSchristos bufferevent_connect_test_flags = be_flags; 7508585484eSchristos #ifdef _WIN32 7518585484eSchristos if (!strcmp((char*)data->setup_data, "unset_connectex")) { 7528585484eSchristos struct win32_extension_fns *ext = 7538585484eSchristos (struct win32_extension_fns *) 7548585484eSchristos event_get_win32_extension_fns_(); 7558585484eSchristos ext->ConnectEx = NULL; 7568585484eSchristos } 7578585484eSchristos #endif 7588585484eSchristos 7598585484eSchristos memset(&localhost, 0, sizeof(localhost)); 7608585484eSchristos 7618585484eSchristos localhost.sin_port = 0; /* pick-a-port */ 7628585484eSchristos localhost.sin_addr.s_addr = htonl(0x7f000001L); 7638585484eSchristos localhost.sin_family = AF_INET; 7648585484eSchristos sa = (struct sockaddr *)&localhost; 7658585484eSchristos lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 7668585484eSchristos LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 7678585484eSchristos 16, sa, sizeof(localhost)); 7688585484eSchristos tt_assert(lev); 7698585484eSchristos 7708585484eSchristos sa = (struct sockaddr *)&ss; 7718585484eSchristos slen = sizeof(ss); 7728585484eSchristos if (regress_get_listener_addr(lev, sa, &slen) < 0) { 7738585484eSchristos tt_abort_perror("getsockname"); 7748585484eSchristos } 7758585484eSchristos 7768585484eSchristos tt_assert(!evconnlistener_enable(lev)); 7778585484eSchristos bev1 = bufferevent_socket_new(data->base, -1, be_flags); 7788585484eSchristos bev2 = bufferevent_socket_new(data->base, -1, be_flags); 7798585484eSchristos tt_assert(bev1); 7808585484eSchristos tt_assert(bev2); 7818585484eSchristos bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base); 7828585484eSchristos bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base); 7838585484eSchristos 7848585484eSchristos bufferevent_enable(bev1, EV_READ); 7858585484eSchristos bufferevent_enable(bev2, EV_READ); 7868585484eSchristos 7878585484eSchristos tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost))); 7888585484eSchristos tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost))); 7898585484eSchristos 7908585484eSchristos event_base_dispatch(data->base); 7918585484eSchristos 7928585484eSchristos tt_int_op(n_strings_read, ==, 2); 7938585484eSchristos tt_int_op(n_reads_invoked, >=, 2); 7948585484eSchristos end: 7958585484eSchristos if (lev) 7968585484eSchristos evconnlistener_free(lev); 7978585484eSchristos 7988585484eSchristos if (bev1) 7998585484eSchristos bufferevent_free(bev1); 8008585484eSchristos 8018585484eSchristos if (bev2) 8028585484eSchristos bufferevent_free(bev2); 8038585484eSchristos } 8048585484eSchristos 8058585484eSchristos static void 806*eabc0478Schristos close_socket_cb(evutil_socket_t fd, short what, void *arg) 807*eabc0478Schristos { 808*eabc0478Schristos evutil_socket_t *fdp = arg; 809*eabc0478Schristos if (*fdp >= 0) { 810*eabc0478Schristos evutil_closesocket(*fdp); 811*eabc0478Schristos *fdp = -1; 812*eabc0478Schristos } 813*eabc0478Schristos } 814*eabc0478Schristos 815*eabc0478Schristos static void 816*eabc0478Schristos test_bufferevent_connect_fail_eventcb(void *arg) 817*eabc0478Schristos { 818*eabc0478Schristos struct basic_test_data *data = arg; 819*eabc0478Schristos int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data; 820*eabc0478Schristos struct event close_listener_event; 821*eabc0478Schristos struct bufferevent *bev = NULL; 822*eabc0478Schristos struct evconnlistener *lev = NULL; 823*eabc0478Schristos struct sockaddr_in localhost; 824*eabc0478Schristos struct timeval close_timeout = { 0, 300000 }; 825*eabc0478Schristos ev_socklen_t slen = sizeof(localhost); 826*eabc0478Schristos evutil_socket_t fake_listener = -1; 827*eabc0478Schristos int r; 828*eabc0478Schristos 829*eabc0478Schristos fake_listener = fake_listener_create(&localhost); 830*eabc0478Schristos 831*eabc0478Schristos tt_int_op(n_events_invoked, ==, 0); 832*eabc0478Schristos 833*eabc0478Schristos bev = bufferevent_socket_new(data->base, -1, flags); 834*eabc0478Schristos tt_assert(bev); 835*eabc0478Schristos bufferevent_setcb(bev, reader_readcb, reader_readcb, 836*eabc0478Schristos reader_eventcb_simple, data->base); 837*eabc0478Schristos bufferevent_enable(bev, EV_READ|EV_WRITE); 838*eabc0478Schristos tt_int_op(n_events_invoked, ==, 0); 839*eabc0478Schristos tt_int_op(n_reads_invoked, ==, 0); 840*eabc0478Schristos 841*eabc0478Schristos /** @see also test_bufferevent_connect_fail() */ 842*eabc0478Schristos r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); 843*eabc0478Schristos /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 844*eabc0478Schristos * detects the error immediately, which is not really wrong of it. */ 845*eabc0478Schristos tt_want(r == 0 || r == -1); 846*eabc0478Schristos 847*eabc0478Schristos tt_int_op(n_events_invoked, ==, 0); 848*eabc0478Schristos tt_int_op(n_reads_invoked, ==, 0); 849*eabc0478Schristos 850*eabc0478Schristos /* Close the listener socket after a delay. This should trigger 851*eabc0478Schristos "connection refused" on some other platforms, including OSX. */ 852*eabc0478Schristos evtimer_assign(&close_listener_event, data->base, close_socket_cb, 853*eabc0478Schristos &fake_listener); 854*eabc0478Schristos event_add(&close_listener_event, &close_timeout); 855*eabc0478Schristos 856*eabc0478Schristos event_base_dispatch(data->base); 857*eabc0478Schristos tt_int_op(n_events_invoked, ==, 1); 858*eabc0478Schristos tt_int_op(n_reads_invoked, ==, 0); 859*eabc0478Schristos 860*eabc0478Schristos end: 861*eabc0478Schristos if (lev) 862*eabc0478Schristos evconnlistener_free(lev); 863*eabc0478Schristos if (bev) 864*eabc0478Schristos bufferevent_free(bev); 865*eabc0478Schristos if (fake_listener >= 0) 866*eabc0478Schristos evutil_closesocket(fake_listener); 867*eabc0478Schristos } 868*eabc0478Schristos 869*eabc0478Schristos static void 8708585484eSchristos want_fail_eventcb(struct bufferevent *bev, short what, void *ctx) 8718585484eSchristos { 8728585484eSchristos struct event_base *base = ctx; 8738585484eSchristos const char *err; 8748585484eSchristos evutil_socket_t s; 8758585484eSchristos 8768585484eSchristos if (what & BEV_EVENT_ERROR) { 8778585484eSchristos s = bufferevent_getfd(bev); 8788585484eSchristos err = evutil_socket_error_to_string(evutil_socket_geterror(s)); 8798585484eSchristos TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s", 8808585484eSchristos EV_SOCK_ARG(s), err)); 8818585484eSchristos test_ok = 1; 8828585484eSchristos } else { 8838585484eSchristos TT_FAIL(("didn't fail? what %hd", what)); 8848585484eSchristos } 8858585484eSchristos 8868585484eSchristos event_base_loopexit(base, NULL); 8878585484eSchristos } 8888585484eSchristos 8898585484eSchristos static void 8908585484eSchristos test_bufferevent_connect_fail(void *arg) 8918585484eSchristos { 892b8ecfcfeSchristos struct basic_test_data *data = (struct basic_test_data *)arg; 8938585484eSchristos struct bufferevent *bev=NULL; 8948585484eSchristos struct event close_listener_event; 8958585484eSchristos int close_listener_event_added = 0; 896*eabc0478Schristos struct timeval close_timeout = { 0, 300000 }; 897*eabc0478Schristos struct sockaddr_in localhost; 898*eabc0478Schristos ev_socklen_t slen = sizeof(localhost); 899*eabc0478Schristos evutil_socket_t fake_listener = -1; 9008585484eSchristos int r; 9018585484eSchristos 9028585484eSchristos test_ok = 0; 9038585484eSchristos 904*eabc0478Schristos fake_listener = fake_listener_create(&localhost); 9058585484eSchristos bev = bufferevent_socket_new(data->base, -1, 9068585484eSchristos BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 9078585484eSchristos tt_assert(bev); 9088585484eSchristos bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base); 9098585484eSchristos 910*eabc0478Schristos r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen); 9118585484eSchristos /* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells 9128585484eSchristos * detects the error immediately, which is not really wrong of it. */ 9138585484eSchristos tt_want(r == 0 || r == -1); 9148585484eSchristos 915*eabc0478Schristos /* Close the listener socket after a delay. This should trigger 9168585484eSchristos "connection refused" on some other platforms, including OSX. */ 9178585484eSchristos evtimer_assign(&close_listener_event, data->base, close_socket_cb, 9188585484eSchristos &fake_listener); 919*eabc0478Schristos event_add(&close_listener_event, &close_timeout); 9208585484eSchristos close_listener_event_added = 1; 9218585484eSchristos 9228585484eSchristos event_base_dispatch(data->base); 9238585484eSchristos 9248585484eSchristos tt_int_op(test_ok, ==, 1); 9258585484eSchristos 9268585484eSchristos end: 9278585484eSchristos if (fake_listener >= 0) 9288585484eSchristos evutil_closesocket(fake_listener); 9298585484eSchristos 9308585484eSchristos if (bev) 9318585484eSchristos bufferevent_free(bev); 9328585484eSchristos 9338585484eSchristos if (close_listener_event_added) 9348585484eSchristos event_del(&close_listener_event); 9358585484eSchristos } 9368585484eSchristos 9378585484eSchristos struct timeout_cb_result { 9388585484eSchristos struct timeval read_timeout_at; 9398585484eSchristos struct timeval write_timeout_at; 9408585484eSchristos struct timeval last_wrote_at; 941*eabc0478Schristos struct timeval last_read_at; 9428585484eSchristos int n_read_timeouts; 9438585484eSchristos int n_write_timeouts; 9448585484eSchristos int total_calls; 9458585484eSchristos }; 9468585484eSchristos 9478585484eSchristos static void 948*eabc0478Schristos bev_timeout_read_cb(struct bufferevent *bev, void *arg) 949*eabc0478Schristos { 950*eabc0478Schristos struct timeout_cb_result *res = arg; 951*eabc0478Schristos evutil_gettimeofday(&res->last_read_at, NULL); 952*eabc0478Schristos } 953*eabc0478Schristos static void 9548585484eSchristos bev_timeout_write_cb(struct bufferevent *bev, void *arg) 9558585484eSchristos { 9568585484eSchristos struct timeout_cb_result *res = arg; 9578585484eSchristos evutil_gettimeofday(&res->last_wrote_at, NULL); 9588585484eSchristos } 9598585484eSchristos static void 9608585484eSchristos bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg) 9618585484eSchristos { 9628585484eSchristos struct timeout_cb_result *res = arg; 9638585484eSchristos ++res->total_calls; 9648585484eSchristos 9658585484eSchristos if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) 9668585484eSchristos == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) { 9678585484eSchristos evutil_gettimeofday(&res->read_timeout_at, NULL); 9688585484eSchristos ++res->n_read_timeouts; 9698585484eSchristos } 9708585484eSchristos if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) 9718585484eSchristos == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) { 9728585484eSchristos evutil_gettimeofday(&res->write_timeout_at, NULL); 9738585484eSchristos ++res->n_write_timeouts; 9748585484eSchristos } 9758585484eSchristos } 9768585484eSchristos 9778585484eSchristos static void 9788585484eSchristos test_bufferevent_timeouts(void *arg) 9798585484eSchristos { 9808585484eSchristos /* "arg" is a string containing "pair" and/or "filter". */ 9818585484eSchristos struct bufferevent *bev1 = NULL, *bev2 = NULL; 9828585484eSchristos struct basic_test_data *data = arg; 9838585484eSchristos int use_pair = 0, use_filter = 0; 9848585484eSchristos struct timeval tv_w, tv_r, started_at; 9858585484eSchristos struct timeout_cb_result res1, res2; 9868585484eSchristos 9878585484eSchristos memset(&res1, 0, sizeof(res1)); 9888585484eSchristos memset(&res2, 0, sizeof(res2)); 9898585484eSchristos 9908585484eSchristos if (strstr((char*)data->setup_data, "pair")) 9918585484eSchristos use_pair = 1; 9928585484eSchristos if (strstr((char*)data->setup_data, "filter")) 9938585484eSchristos use_filter = 1; 9948585484eSchristos 9958585484eSchristos if (use_pair) { 9968585484eSchristos struct bufferevent *p[2]; 9978585484eSchristos tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p)); 9988585484eSchristos bev1 = p[0]; 9998585484eSchristos bev2 = p[1]; 10008585484eSchristos } else { 10018585484eSchristos bev1 = bufferevent_socket_new(data->base, data->pair[0], 0); 10028585484eSchristos bev2 = bufferevent_socket_new(data->base, data->pair[1], 0); 10038585484eSchristos } 10048585484eSchristos tt_assert(bev1); 10058585484eSchristos tt_assert(bev2); 10068585484eSchristos 10078585484eSchristos if (use_filter) { 10088585484eSchristos struct bufferevent *bevf1, *bevf2; 10098585484eSchristos bevf1 = bufferevent_filter_new(bev1, NULL, NULL, 10108585484eSchristos BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 10118585484eSchristos bevf2 = bufferevent_filter_new(bev2, NULL, NULL, 10128585484eSchristos BEV_OPT_CLOSE_ON_FREE, NULL, NULL); 10138585484eSchristos tt_assert(bevf1); 10148585484eSchristos tt_assert(bevf2); 10158585484eSchristos bev1 = bevf1; 10168585484eSchristos bev2 = bevf2; 10178585484eSchristos } 10188585484eSchristos 10198585484eSchristos /* Do this nice and early. */ 10208585484eSchristos bufferevent_disable(bev2, EV_READ); 10218585484eSchristos 10228585484eSchristos /* bev1 will try to write and read. Both will time out. */ 10238585484eSchristos evutil_gettimeofday(&started_at, NULL); 10248585484eSchristos tv_w.tv_sec = tv_r.tv_sec = 0; 10258585484eSchristos tv_w.tv_usec = 100*1000; 10268585484eSchristos tv_r.tv_usec = 150*1000; 1027*eabc0478Schristos bufferevent_setcb(bev1, bev_timeout_read_cb, bev_timeout_write_cb, 10288585484eSchristos bev_timeout_event_cb, &res1); 10298585484eSchristos bufferevent_set_timeouts(bev1, &tv_r, &tv_w); 10308585484eSchristos bufferevent_write(bev1, "ABCDEFG", 7); 10318585484eSchristos bufferevent_enable(bev1, EV_READ|EV_WRITE); 10328585484eSchristos 10338585484eSchristos /* bev2 has nothing to say, and isn't listening. */ 1034*eabc0478Schristos bufferevent_setcb(bev2, bev_timeout_read_cb, bev_timeout_write_cb, 10358585484eSchristos bev_timeout_event_cb, &res2); 10368585484eSchristos tv_w.tv_sec = tv_r.tv_sec = 0; 10378585484eSchristos tv_w.tv_usec = 200*1000; 10388585484eSchristos tv_r.tv_usec = 100*1000; 10398585484eSchristos bufferevent_set_timeouts(bev2, &tv_r, &tv_w); 10408585484eSchristos bufferevent_enable(bev2, EV_WRITE); 10418585484eSchristos 10428585484eSchristos tv_r.tv_sec = 0; 10438585484eSchristos tv_r.tv_usec = 350000; 10448585484eSchristos 10458585484eSchristos event_base_loopexit(data->base, &tv_r); 10468585484eSchristos event_base_dispatch(data->base); 10478585484eSchristos 10488585484eSchristos /* XXXX Test that actually reading or writing a little resets the 10498585484eSchristos * timeouts. */ 10508585484eSchristos 1051*eabc0478Schristos tt_want(res1.total_calls == 2); 10528585484eSchristos tt_want(res1.n_read_timeouts == 1); 10538585484eSchristos tt_want(res1.n_write_timeouts == 1); 1054*eabc0478Schristos tt_want(res2.total_calls == !(use_pair && !use_filter)); 1055*eabc0478Schristos tt_want(res2.n_write_timeouts == !(use_pair && !use_filter)); 1056*eabc0478Schristos tt_want(!res2.n_read_timeouts); 10578585484eSchristos 10588585484eSchristos test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150); 10598585484eSchristos test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100); 10608585484eSchristos 1061*eabc0478Schristos #define tt_assert_timeval_empty(tv) do { \ 1062*eabc0478Schristos tt_int_op((tv).tv_sec, ==, 0); \ 1063*eabc0478Schristos tt_int_op((tv).tv_usec, ==, 0); \ 1064*eabc0478Schristos } while(0) 1065*eabc0478Schristos tt_assert_timeval_empty(res1.last_read_at); 1066*eabc0478Schristos tt_assert_timeval_empty(res2.last_read_at); 1067*eabc0478Schristos tt_assert_timeval_empty(res2.last_wrote_at); 1068*eabc0478Schristos tt_assert_timeval_empty(res2.last_wrote_at); 1069*eabc0478Schristos #undef tt_assert_timeval_empty 1070*eabc0478Schristos 10718585484eSchristos end: 10728585484eSchristos if (bev1) 10738585484eSchristos bufferevent_free(bev1); 10748585484eSchristos if (bev2) 10758585484eSchristos bufferevent_free(bev2); 10768585484eSchristos } 10778585484eSchristos 1078b8ecfcfeSchristos static void 1079b8ecfcfeSchristos trigger_failure_cb(evutil_socket_t fd, short what, void *ctx) 1080b8ecfcfeSchristos { 1081b8ecfcfeSchristos TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout).")); 1082b8ecfcfeSchristos } 1083b8ecfcfeSchristos 1084b8ecfcfeSchristos static void 1085b8ecfcfeSchristos trigger_eventcb(struct bufferevent *bev, short what, void *ctx) 1086b8ecfcfeSchristos { 1087b8ecfcfeSchristos struct event_base *base = ctx; 1088b8ecfcfeSchristos if (what == ~0) { 1089b8ecfcfeSchristos TT_BLATHER(("Event successfully triggered.")); 1090b8ecfcfeSchristos event_base_loopexit(base, NULL); 1091b8ecfcfeSchristos return; 1092b8ecfcfeSchristos } 1093b8ecfcfeSchristos reader_eventcb(bev, what, ctx); 1094b8ecfcfeSchristos } 1095b8ecfcfeSchristos 1096b8ecfcfeSchristos static void 1097b8ecfcfeSchristos trigger_readcb_triggered(struct bufferevent *bev, void *ctx) 1098b8ecfcfeSchristos { 1099b8ecfcfeSchristos TT_BLATHER(("Read successfully triggered.")); 1100b8ecfcfeSchristos n_reads_invoked++; 1101b8ecfcfeSchristos bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags); 1102b8ecfcfeSchristos } 1103b8ecfcfeSchristos 1104b8ecfcfeSchristos static void 1105b8ecfcfeSchristos trigger_readcb(struct bufferevent *bev, void *ctx) 1106b8ecfcfeSchristos { 1107b8ecfcfeSchristos struct timeval timeout = { 30, 0 }; 1108b8ecfcfeSchristos struct event_base *base = ctx; 1109b8ecfcfeSchristos size_t low, high, len; 1110b8ecfcfeSchristos int expected_reads; 1111b8ecfcfeSchristos 1112b8ecfcfeSchristos TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev))); 1113b8ecfcfeSchristos expected_reads = ++n_reads_invoked; 1114b8ecfcfeSchristos 1115b8ecfcfeSchristos bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx); 1116b8ecfcfeSchristos 1117b8ecfcfeSchristos bufferevent_getwatermark(bev, EV_READ, &low, &high); 1118b8ecfcfeSchristos len = evbuffer_get_length(bufferevent_get_input(bev)); 1119b8ecfcfeSchristos 1120b8ecfcfeSchristos bufferevent_setwatermark(bev, EV_READ, len + 1, 0); 1121b8ecfcfeSchristos bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags); 1122b8ecfcfeSchristos /* no callback expected */ 1123b8ecfcfeSchristos tt_int_op(n_reads_invoked, ==, expected_reads); 1124b8ecfcfeSchristos 1125b8ecfcfeSchristos if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) || 1126b8ecfcfeSchristos (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) { 1127b8ecfcfeSchristos /* will be deferred */ 1128b8ecfcfeSchristos } else { 1129b8ecfcfeSchristos expected_reads++; 1130b8ecfcfeSchristos } 1131b8ecfcfeSchristos 1132b8ecfcfeSchristos event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout); 1133b8ecfcfeSchristos 1134b8ecfcfeSchristos bufferevent_trigger(bev, EV_READ, 1135b8ecfcfeSchristos bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS); 1136b8ecfcfeSchristos tt_int_op(n_reads_invoked, ==, expected_reads); 1137b8ecfcfeSchristos 1138b8ecfcfeSchristos bufferevent_setwatermark(bev, EV_READ, low, high); 1139b8ecfcfeSchristos end: 1140b8ecfcfeSchristos ; 1141b8ecfcfeSchristos } 1142b8ecfcfeSchristos 1143b8ecfcfeSchristos static void 1144b8ecfcfeSchristos test_bufferevent_trigger(void *arg) 1145b8ecfcfeSchristos { 1146b8ecfcfeSchristos struct basic_test_data *data = arg; 1147b8ecfcfeSchristos struct evconnlistener *lev=NULL; 1148b8ecfcfeSchristos struct bufferevent *bev=NULL; 1149b8ecfcfeSchristos struct sockaddr_in localhost; 1150b8ecfcfeSchristos struct sockaddr_storage ss; 1151b8ecfcfeSchristos struct sockaddr *sa; 1152b8ecfcfeSchristos ev_socklen_t slen; 1153b8ecfcfeSchristos 1154b8ecfcfeSchristos int be_flags=BEV_OPT_CLOSE_ON_FREE; 1155b8ecfcfeSchristos int trig_flags=0; 1156b8ecfcfeSchristos 1157b8ecfcfeSchristos if (strstr((char*)data->setup_data, "defer")) { 1158b8ecfcfeSchristos be_flags |= BEV_OPT_DEFER_CALLBACKS; 1159b8ecfcfeSchristos } 1160b8ecfcfeSchristos bufferevent_connect_test_flags = be_flags; 1161b8ecfcfeSchristos 1162b8ecfcfeSchristos if (strstr((char*)data->setup_data, "postpone")) { 1163b8ecfcfeSchristos trig_flags |= BEV_TRIG_DEFER_CALLBACKS; 1164b8ecfcfeSchristos } 1165b8ecfcfeSchristos bufferevent_trigger_test_flags = trig_flags; 1166b8ecfcfeSchristos 1167b8ecfcfeSchristos memset(&localhost, 0, sizeof(localhost)); 1168b8ecfcfeSchristos 1169b8ecfcfeSchristos localhost.sin_port = 0; /* pick-a-port */ 1170b8ecfcfeSchristos localhost.sin_addr.s_addr = htonl(0x7f000001L); 1171b8ecfcfeSchristos localhost.sin_family = AF_INET; 1172b8ecfcfeSchristos sa = (struct sockaddr *)&localhost; 1173b8ecfcfeSchristos lev = evconnlistener_new_bind(data->base, listen_cb, data->base, 1174b8ecfcfeSchristos LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 1175b8ecfcfeSchristos 16, sa, sizeof(localhost)); 1176b8ecfcfeSchristos tt_assert(lev); 1177b8ecfcfeSchristos 1178b8ecfcfeSchristos sa = (struct sockaddr *)&ss; 1179b8ecfcfeSchristos slen = sizeof(ss); 1180b8ecfcfeSchristos if (regress_get_listener_addr(lev, sa, &slen) < 0) { 1181b8ecfcfeSchristos tt_abort_perror("getsockname"); 1182b8ecfcfeSchristos } 1183b8ecfcfeSchristos 1184b8ecfcfeSchristos tt_assert(!evconnlistener_enable(lev)); 1185b8ecfcfeSchristos bev = bufferevent_socket_new(data->base, -1, be_flags); 1186b8ecfcfeSchristos tt_assert(bev); 1187b8ecfcfeSchristos bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base); 1188b8ecfcfeSchristos 1189b8ecfcfeSchristos bufferevent_enable(bev, EV_READ); 1190b8ecfcfeSchristos 1191b8ecfcfeSchristos tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost))); 1192b8ecfcfeSchristos 1193b8ecfcfeSchristos event_base_dispatch(data->base); 1194b8ecfcfeSchristos 1195b8ecfcfeSchristos tt_int_op(n_reads_invoked, ==, 2); 1196b8ecfcfeSchristos end: 1197b8ecfcfeSchristos if (lev) 1198b8ecfcfeSchristos evconnlistener_free(lev); 1199b8ecfcfeSchristos 1200b8ecfcfeSchristos if (bev) 1201b8ecfcfeSchristos bufferevent_free(bev); 1202b8ecfcfeSchristos } 1203b8ecfcfeSchristos 1204*eabc0478Schristos static void 1205*eabc0478Schristos test_bufferevent_socket_filter_inactive(void *arg) 1206*eabc0478Schristos { 1207*eabc0478Schristos struct basic_test_data *data = arg; 1208*eabc0478Schristos struct bufferevent *bev = NULL, *bevf = NULL; 1209*eabc0478Schristos 1210*eabc0478Schristos bev = bufferevent_socket_new(data->base, -1, 0); 1211*eabc0478Schristos tt_assert(bev); 1212*eabc0478Schristos bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL); 1213*eabc0478Schristos tt_assert(bevf); 1214*eabc0478Schristos 1215*eabc0478Schristos end: 1216*eabc0478Schristos if (bevf) 1217*eabc0478Schristos bufferevent_free(bevf); 1218*eabc0478Schristos if (bev) 1219*eabc0478Schristos bufferevent_free(bev); 1220*eabc0478Schristos } 1221*eabc0478Schristos 1222*eabc0478Schristos static void 1223*eabc0478Schristos pair_flush_eventcb(struct bufferevent *bev, short what, void *ctx) 1224*eabc0478Schristos { 1225*eabc0478Schristos int *callback_what = ctx; 1226*eabc0478Schristos *callback_what = what; 1227*eabc0478Schristos } 1228*eabc0478Schristos 1229*eabc0478Schristos static void 1230*eabc0478Schristos test_bufferevent_pair_flush(void *arg) 1231*eabc0478Schristos { 1232*eabc0478Schristos struct basic_test_data *data = arg; 1233*eabc0478Schristos struct bufferevent *pair[2]; 1234*eabc0478Schristos struct bufferevent *bev1 = NULL; 1235*eabc0478Schristos struct bufferevent *bev2 = NULL; 1236*eabc0478Schristos int callback_what = 0; 1237*eabc0478Schristos 1238*eabc0478Schristos tt_assert(0 == bufferevent_pair_new(data->base, 0, pair)); 1239*eabc0478Schristos bev1 = pair[0]; 1240*eabc0478Schristos bev2 = pair[1]; 1241*eabc0478Schristos tt_assert(0 == bufferevent_enable(bev1, EV_WRITE)); 1242*eabc0478Schristos tt_assert(0 == bufferevent_enable(bev2, EV_READ)); 1243*eabc0478Schristos 1244*eabc0478Schristos bufferevent_setcb(bev2, NULL, NULL, pair_flush_eventcb, &callback_what); 1245*eabc0478Schristos 1246*eabc0478Schristos bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED); 1247*eabc0478Schristos 1248*eabc0478Schristos event_base_loop(data->base, EVLOOP_ONCE); 1249*eabc0478Schristos 1250*eabc0478Schristos tt_assert(callback_what == (BEV_EVENT_READING | BEV_EVENT_EOF)); 1251*eabc0478Schristos 1252*eabc0478Schristos end: 1253*eabc0478Schristos if (bev1) 1254*eabc0478Schristos bufferevent_free(bev1); 1255*eabc0478Schristos if (bev2) 1256*eabc0478Schristos bufferevent_free(bev2); 1257*eabc0478Schristos } 1258*eabc0478Schristos 1259*eabc0478Schristos struct bufferevent_filter_data_stuck { 1260*eabc0478Schristos size_t header_size; 1261*eabc0478Schristos size_t total_read; 1262*eabc0478Schristos }; 1263*eabc0478Schristos 1264*eabc0478Schristos static void 1265*eabc0478Schristos bufferevent_filter_data_stuck_readcb(struct bufferevent *bev, void *arg) 1266*eabc0478Schristos { 1267*eabc0478Schristos struct bufferevent_filter_data_stuck *filter_data = arg; 1268*eabc0478Schristos struct evbuffer *input = bufferevent_get_input(bev); 1269*eabc0478Schristos size_t read_size = evbuffer_get_length(input); 1270*eabc0478Schristos evbuffer_drain(input, read_size); 1271*eabc0478Schristos filter_data->total_read += read_size; 1272*eabc0478Schristos } 1273*eabc0478Schristos 1274*eabc0478Schristos /** 1275*eabc0478Schristos * This filter prepends header once before forwarding data. 1276*eabc0478Schristos */ 1277*eabc0478Schristos static enum bufferevent_filter_result 1278*eabc0478Schristos bufferevent_filter_data_stuck_inputcb( 1279*eabc0478Schristos struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit, 1280*eabc0478Schristos enum bufferevent_flush_mode mode, void *ctx) 1281*eabc0478Schristos { 1282*eabc0478Schristos struct bufferevent_filter_data_stuck *filter_data = ctx; 1283*eabc0478Schristos static int header_inserted = 0; 1284*eabc0478Schristos size_t payload_size; 1285*eabc0478Schristos size_t header_size = 0; 1286*eabc0478Schristos 1287*eabc0478Schristos if (!header_inserted) { 1288*eabc0478Schristos char *header = calloc(filter_data->header_size, 1); 1289*eabc0478Schristos evbuffer_add(dst, header, filter_data->header_size); 1290*eabc0478Schristos free(header); 1291*eabc0478Schristos header_size = filter_data->header_size; 1292*eabc0478Schristos header_inserted = 1; 1293*eabc0478Schristos } 1294*eabc0478Schristos 1295*eabc0478Schristos payload_size = evbuffer_get_length(src); 1296*eabc0478Schristos if (payload_size > dst_limit - header_size) { 1297*eabc0478Schristos payload_size = dst_limit - header_size; 1298*eabc0478Schristos } 1299*eabc0478Schristos 1300*eabc0478Schristos tt_int_op(payload_size, ==, evbuffer_remove_buffer(src, dst, payload_size)); 1301*eabc0478Schristos 1302*eabc0478Schristos end: 1303*eabc0478Schristos return BEV_OK; 1304*eabc0478Schristos } 1305*eabc0478Schristos 1306*eabc0478Schristos static void 1307*eabc0478Schristos test_bufferevent_filter_data_stuck(void *arg) 1308*eabc0478Schristos { 1309*eabc0478Schristos const size_t read_high_wm = 4096; 1310*eabc0478Schristos struct bufferevent_filter_data_stuck filter_data; 1311*eabc0478Schristos struct basic_test_data *data = arg; 1312*eabc0478Schristos struct bufferevent *pair[2]; 1313*eabc0478Schristos struct bufferevent *filter = NULL; 1314*eabc0478Schristos 1315*eabc0478Schristos int options = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS; 1316*eabc0478Schristos 1317*eabc0478Schristos char payload[4096]; 1318*eabc0478Schristos int payload_size = sizeof(payload); 1319*eabc0478Schristos 1320*eabc0478Schristos memset(&filter_data, 0, sizeof(filter_data)); 1321*eabc0478Schristos filter_data.header_size = 20; 1322*eabc0478Schristos 1323*eabc0478Schristos tt_assert(bufferevent_pair_new(data->base, options, pair) == 0); 1324*eabc0478Schristos 1325*eabc0478Schristos bufferevent_setwatermark(pair[0], EV_READ, 0, read_high_wm); 1326*eabc0478Schristos bufferevent_setwatermark(pair[1], EV_READ, 0, read_high_wm); 1327*eabc0478Schristos 1328*eabc0478Schristos tt_assert( 1329*eabc0478Schristos filter = 1330*eabc0478Schristos bufferevent_filter_new(pair[1], 1331*eabc0478Schristos bufferevent_filter_data_stuck_inputcb, 1332*eabc0478Schristos NULL, 1333*eabc0478Schristos options, 1334*eabc0478Schristos NULL, 1335*eabc0478Schristos &filter_data)); 1336*eabc0478Schristos 1337*eabc0478Schristos bufferevent_setcb(filter, 1338*eabc0478Schristos bufferevent_filter_data_stuck_readcb, 1339*eabc0478Schristos NULL, 1340*eabc0478Schristos NULL, 1341*eabc0478Schristos &filter_data); 1342*eabc0478Schristos 1343*eabc0478Schristos tt_assert(bufferevent_enable(filter, EV_READ|EV_WRITE) == 0); 1344*eabc0478Schristos 1345*eabc0478Schristos bufferevent_setwatermark(filter, EV_READ, 0, read_high_wm); 1346*eabc0478Schristos 1347*eabc0478Schristos tt_assert(bufferevent_write(pair[0], payload, sizeof(payload)) == 0); 1348*eabc0478Schristos 1349*eabc0478Schristos event_base_dispatch(data->base); 1350*eabc0478Schristos 1351*eabc0478Schristos tt_int_op(filter_data.total_read, ==, payload_size + filter_data.header_size); 1352*eabc0478Schristos end: 1353*eabc0478Schristos if (pair[0]) 1354*eabc0478Schristos bufferevent_free(pair[0]); 1355*eabc0478Schristos if (filter) 1356*eabc0478Schristos bufferevent_free(filter); 1357*eabc0478Schristos } 1358*eabc0478Schristos 13598585484eSchristos struct testcase_t bufferevent_testcases[] = { 13608585484eSchristos 13618585484eSchristos LEGACY(bufferevent, TT_ISOLATED), 13628585484eSchristos LEGACY(bufferevent_pair, TT_ISOLATED), 1363*eabc0478Schristos LEGACY(bufferevent_flush_normal, TT_ISOLATED), 1364*eabc0478Schristos LEGACY(bufferevent_flush_flush, TT_ISOLATED), 1365*eabc0478Schristos LEGACY(bufferevent_flush_finished, TT_ISOLATED), 1366*eabc0478Schristos LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED), 1367*eabc0478Schristos LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED), 1368*eabc0478Schristos LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED), 1369*eabc0478Schristos #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__) 13707476e6e4Schristos { "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock, 1371*eabc0478Schristos TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY|TT_NO_LOGS, 13727476e6e4Schristos &basic_setup, NULL }, 13737476e6e4Schristos #endif 13748585484eSchristos LEGACY(bufferevent_watermarks, TT_ISOLATED), 13758585484eSchristos LEGACY(bufferevent_pair_watermarks, TT_ISOLATED), 13768585484eSchristos LEGACY(bufferevent_filters, TT_ISOLATED), 13778585484eSchristos LEGACY(bufferevent_pair_filters, TT_ISOLATED), 1378*eabc0478Schristos LEGACY(bufferevent_filters_disable, TT_ISOLATED), 1379*eabc0478Schristos LEGACY(bufferevent_pair_filters_disable, TT_ISOLATED), 13808585484eSchristos { "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE, 13818585484eSchristos &basic_setup, (void*)"" }, 13828585484eSchristos { "bufferevent_connect_defer", test_bufferevent_connect, 13838585484eSchristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 13848585484eSchristos { "bufferevent_connect_lock", test_bufferevent_connect, 13858585484eSchristos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" }, 13868585484eSchristos { "bufferevent_connect_lock_defer", test_bufferevent_connect, 13878585484eSchristos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 13888585484eSchristos (void*)"defer lock" }, 13898585484eSchristos { "bufferevent_connect_unlocked_cbs", test_bufferevent_connect, 13908585484eSchristos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 13918585484eSchristos (void*)"lock defer unlocked" }, 13928585484eSchristos { "bufferevent_connect_fail", test_bufferevent_connect_fail, 13938585484eSchristos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 13948585484eSchristos { "bufferevent_timeout", test_bufferevent_timeouts, 1395*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"" }, 13968585484eSchristos { "bufferevent_timeout_pair", test_bufferevent_timeouts, 13978585484eSchristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" }, 13988585484eSchristos { "bufferevent_timeout_filter", test_bufferevent_timeouts, 13998585484eSchristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" }, 14008585484eSchristos { "bufferevent_timeout_filter_pair", test_bufferevent_timeouts, 14018585484eSchristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" }, 1402b8ecfcfeSchristos { "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE, 1403b8ecfcfeSchristos &basic_setup, (void*)"" }, 1404b8ecfcfeSchristos { "bufferevent_trigger_defer", test_bufferevent_trigger, 1405b8ecfcfeSchristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" }, 1406b8ecfcfeSchristos { "bufferevent_trigger_postpone", test_bufferevent_trigger, 1407b8ecfcfeSchristos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1408b8ecfcfeSchristos (void*)"postpone" }, 1409b8ecfcfeSchristos { "bufferevent_trigger_defer_postpone", test_bufferevent_trigger, 1410b8ecfcfeSchristos TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, 1411b8ecfcfeSchristos (void*)"defer postpone" }, 14128585484eSchristos #ifdef EVENT__HAVE_LIBZ 14138585484eSchristos LEGACY(bufferevent_zlib, TT_ISOLATED), 14148585484eSchristos #else 14158585484eSchristos { "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL }, 14168585484eSchristos #endif 14178585484eSchristos 1418*eabc0478Schristos { "bufferevent_connect_fail_eventcb_defer", 1419*eabc0478Schristos test_bufferevent_connect_fail_eventcb, 1420*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS }, 1421*eabc0478Schristos { "bufferevent_connect_fail_eventcb", 1422*eabc0478Schristos test_bufferevent_connect_fail_eventcb, 1423*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1424*eabc0478Schristos 1425*eabc0478Schristos { "bufferevent_socket_filter_inactive", 1426*eabc0478Schristos test_bufferevent_socket_filter_inactive, 1427*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1428*eabc0478Schristos { "bufferevent_pair_flush", 1429*eabc0478Schristos test_bufferevent_pair_flush, 1430*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1431*eabc0478Schristos { "bufferevent_filter_data_stuck", 1432*eabc0478Schristos test_bufferevent_filter_data_stuck, 1433*eabc0478Schristos TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, 1434*eabc0478Schristos 14358585484eSchristos END_OF_TESTCASES, 14368585484eSchristos }; 14378585484eSchristos 1438*eabc0478Schristos #define TT_IOCP (TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP) 1439*eabc0478Schristos #define TT_IOCP_LEGACY (TT_ISOLATED|TT_ENABLE_IOCP) 14408585484eSchristos struct testcase_t bufferevent_iocp_testcases[] = { 1441*eabc0478Schristos LEGACY(bufferevent, TT_IOCP_LEGACY), 1442*eabc0478Schristos LEGACY(bufferevent_flush_normal, TT_ISOLATED), 1443*eabc0478Schristos LEGACY(bufferevent_flush_flush, TT_ISOLATED), 1444*eabc0478Schristos LEGACY(bufferevent_flush_finished, TT_ISOLATED), 1445*eabc0478Schristos LEGACY(bufferevent_watermarks, TT_IOCP_LEGACY), 1446*eabc0478Schristos LEGACY(bufferevent_filters, TT_IOCP_LEGACY), 1447*eabc0478Schristos LEGACY(bufferevent_filters_disable, TT_IOCP_LEGACY), 14488585484eSchristos 14498585484eSchristos { "bufferevent_connect", test_bufferevent_connect, 1450*eabc0478Schristos TT_IOCP, &basic_setup, (void*)"" }, 14518585484eSchristos { "bufferevent_connect_defer", test_bufferevent_connect, 1452*eabc0478Schristos TT_IOCP, &basic_setup, (void*)"defer" }, 14538585484eSchristos { "bufferevent_connect_lock", test_bufferevent_connect, 1454*eabc0478Schristos TT_IOCP, &basic_setup, (void*)"lock" }, 14558585484eSchristos { "bufferevent_connect_lock_defer", test_bufferevent_connect, 1456*eabc0478Schristos TT_IOCP, &basic_setup, (void*)"defer lock" }, 14578585484eSchristos { "bufferevent_connect_fail", test_bufferevent_connect_fail, 1458*eabc0478Schristos TT_IOCP, &basic_setup, NULL }, 14598585484eSchristos { "bufferevent_connect_nonblocking", test_bufferevent_connect, 1460*eabc0478Schristos TT_IOCP, &basic_setup, (void*)"unset_connectex" }, 1461*eabc0478Schristos 1462*eabc0478Schristos { "bufferevent_connect_fail_eventcb_defer", 1463*eabc0478Schristos test_bufferevent_connect_fail_eventcb, 1464*eabc0478Schristos TT_IOCP, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS }, 1465*eabc0478Schristos { "bufferevent_connect_fail_eventcb", 1466*eabc0478Schristos test_bufferevent_connect_fail_eventcb, TT_IOCP, &basic_setup, NULL }, 14678585484eSchristos 14688585484eSchristos END_OF_TESTCASES, 14698585484eSchristos }; 1470