xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/test/regress_bufferevent.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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