xref: /freebsd/contrib/ntp/sntp/libevent/test/regress_bufferevent.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
32b15cb3dSCy Schubert  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
42b15cb3dSCy Schubert  *
52b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
62b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
72b15cb3dSCy Schubert  * are met:
82b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
92b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
102b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
112b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
122b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
132b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
142b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
152b15cb3dSCy Schubert  *
162b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
172b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
182b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
192b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
202b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
212b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
252b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262b15cb3dSCy Schubert  */
272b15cb3dSCy Schubert #include "util-internal.h"
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert /* The old tests here need assertions to work. */
302b15cb3dSCy Schubert #undef NDEBUG
312b15cb3dSCy Schubert 
32*a466cc55SCy Schubert /**
33*a466cc55SCy Schubert  * - clang supports __has_feature
34*a466cc55SCy Schubert  * - gcc supports __SANITIZE_ADDRESS__
35*a466cc55SCy Schubert  *
36*a466cc55SCy Schubert  * Let's set __SANITIZE_ADDRESS__ if __has_feature(address_sanitizer)
37*a466cc55SCy Schubert  */
38*a466cc55SCy Schubert #ifndef __has_feature
39*a466cc55SCy Schubert #define __has_feature(x) 0
40*a466cc55SCy Schubert #endif
41*a466cc55SCy Schubert #if !defined(__SANITIZE_ADDRESS__) && __has_feature(address_sanitizer)
42*a466cc55SCy Schubert #define __SANITIZE_ADDRESS__
43*a466cc55SCy Schubert #endif
44*a466cc55SCy Schubert 
452b15cb3dSCy Schubert #ifdef _WIN32
462b15cb3dSCy Schubert #include <winsock2.h>
472b15cb3dSCy Schubert #include <windows.h>
482b15cb3dSCy Schubert #endif
492b15cb3dSCy Schubert 
502b15cb3dSCy Schubert #include "event2/event-config.h"
512b15cb3dSCy Schubert 
522b15cb3dSCy Schubert #include <sys/types.h>
532b15cb3dSCy Schubert #include <sys/stat.h>
542b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
552b15cb3dSCy Schubert #include <sys/time.h>
562b15cb3dSCy Schubert #endif
572b15cb3dSCy Schubert #include <sys/queue.h>
582b15cb3dSCy Schubert #ifndef _WIN32
592b15cb3dSCy Schubert #include <sys/socket.h>
602b15cb3dSCy Schubert #include <sys/wait.h>
612b15cb3dSCy Schubert #include <signal.h>
622b15cb3dSCy Schubert #include <unistd.h>
632b15cb3dSCy Schubert #include <netdb.h>
642b15cb3dSCy Schubert #include <netinet/in.h>
652b15cb3dSCy Schubert #endif
662b15cb3dSCy Schubert #include <fcntl.h>
672b15cb3dSCy Schubert #include <signal.h>
682b15cb3dSCy Schubert #include <stdlib.h>
692b15cb3dSCy Schubert #include <stdio.h>
702b15cb3dSCy Schubert #include <string.h>
712b15cb3dSCy Schubert #include <errno.h>
722b15cb3dSCy Schubert #include <assert.h>
732b15cb3dSCy Schubert 
742b15cb3dSCy Schubert #ifdef EVENT__HAVE_ARPA_INET_H
752b15cb3dSCy Schubert #include <arpa/inet.h>
762b15cb3dSCy Schubert #endif
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert #include "event2/event-config.h"
792b15cb3dSCy Schubert #include "event2/event.h"
802b15cb3dSCy Schubert #include "event2/event_struct.h"
812b15cb3dSCy Schubert #include "event2/event_compat.h"
822b15cb3dSCy Schubert #include "event2/tag.h"
832b15cb3dSCy Schubert #include "event2/buffer.h"
842b15cb3dSCy Schubert #include "event2/bufferevent.h"
852b15cb3dSCy Schubert #include "event2/bufferevent_compat.h"
862b15cb3dSCy Schubert #include "event2/bufferevent_struct.h"
872b15cb3dSCy Schubert #include "event2/listener.h"
882b15cb3dSCy Schubert #include "event2/util.h"
892b15cb3dSCy Schubert 
902b15cb3dSCy Schubert #include "bufferevent-internal.h"
91a25439b6SCy Schubert #include "evthread-internal.h"
922b15cb3dSCy Schubert #include "util-internal.h"
932b15cb3dSCy Schubert #ifdef _WIN32
942b15cb3dSCy Schubert #include "iocp-internal.h"
952b15cb3dSCy Schubert #endif
962b15cb3dSCy Schubert 
972b15cb3dSCy Schubert #include "regress.h"
982b15cb3dSCy Schubert #include "regress_testutils.h"
992b15cb3dSCy Schubert 
1002b15cb3dSCy Schubert /*
1012b15cb3dSCy Schubert  * simple bufferevent test
1022b15cb3dSCy Schubert  */
1032b15cb3dSCy Schubert 
1042b15cb3dSCy Schubert static void
readcb(struct bufferevent * bev,void * arg)1052b15cb3dSCy Schubert readcb(struct bufferevent *bev, void *arg)
1062b15cb3dSCy Schubert {
1072b15cb3dSCy Schubert 	if (evbuffer_get_length(bev->input) == 8333) {
1082b15cb3dSCy Schubert 		struct evbuffer *evbuf = evbuffer_new();
1092b15cb3dSCy Schubert 		assert(evbuf != NULL);
1102b15cb3dSCy Schubert 
1112b15cb3dSCy Schubert 		/* gratuitous test of bufferevent_read_buffer */
1122b15cb3dSCy Schubert 		bufferevent_read_buffer(bev, evbuf);
1132b15cb3dSCy Schubert 
1142b15cb3dSCy Schubert 		bufferevent_disable(bev, EV_READ);
1152b15cb3dSCy Schubert 
1162b15cb3dSCy Schubert 		if (evbuffer_get_length(evbuf) == 8333) {
1172b15cb3dSCy Schubert 			test_ok++;
1182b15cb3dSCy Schubert 		}
1192b15cb3dSCy Schubert 
1202b15cb3dSCy Schubert 		evbuffer_free(evbuf);
1212b15cb3dSCy Schubert 	}
1222b15cb3dSCy Schubert }
1232b15cb3dSCy Schubert 
1242b15cb3dSCy Schubert static void
writecb(struct bufferevent * bev,void * arg)1252b15cb3dSCy Schubert writecb(struct bufferevent *bev, void *arg)
1262b15cb3dSCy Schubert {
1272b15cb3dSCy Schubert 	if (evbuffer_get_length(bev->output) == 0) {
1282b15cb3dSCy Schubert 		test_ok++;
1292b15cb3dSCy Schubert 	}
1302b15cb3dSCy Schubert }
1312b15cb3dSCy Schubert 
1322b15cb3dSCy Schubert static void
errorcb(struct bufferevent * bev,short what,void * arg)1332b15cb3dSCy Schubert errorcb(struct bufferevent *bev, short what, void *arg)
1342b15cb3dSCy Schubert {
1352b15cb3dSCy Schubert 	test_ok = -2;
1362b15cb3dSCy Schubert }
1372b15cb3dSCy Schubert 
1382b15cb3dSCy Schubert static void
test_bufferevent_impl(int use_pair,int flush)139*a466cc55SCy Schubert test_bufferevent_impl(int use_pair, int flush)
1402b15cb3dSCy Schubert {
1412b15cb3dSCy Schubert 	struct bufferevent *bev1 = NULL, *bev2 = NULL;
1422b15cb3dSCy Schubert 	char buffer[8333];
1432b15cb3dSCy Schubert 	int i;
144*a466cc55SCy Schubert 	int expected = 2;
1452b15cb3dSCy Schubert 
1462b15cb3dSCy Schubert 	if (use_pair) {
1472b15cb3dSCy Schubert 		struct bufferevent *pair[2];
1482b15cb3dSCy Schubert 		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
1492b15cb3dSCy Schubert 		bev1 = pair[0];
1502b15cb3dSCy Schubert 		bev2 = pair[1];
1512b15cb3dSCy Schubert 		bufferevent_setcb(bev1, readcb, writecb, errorcb, bev1);
1522b15cb3dSCy Schubert 		bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
153*a466cc55SCy Schubert 		tt_fd_op(bufferevent_getfd(bev1), ==, EVUTIL_INVALID_SOCKET);
1542b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
1552b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
1562b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
1572b15cb3dSCy Schubert 	} else {
1582b15cb3dSCy Schubert 		bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
1592b15cb3dSCy Schubert 		bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
160*a466cc55SCy Schubert 		tt_fd_op(bufferevent_getfd(bev1), ==, pair[0]);
1612b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
1622b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
1632b15cb3dSCy Schubert 		tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
1642b15cb3dSCy Schubert 	}
1652b15cb3dSCy Schubert 
1662b15cb3dSCy Schubert 	{
1672b15cb3dSCy Schubert 		/* Test getcb. */
1682b15cb3dSCy Schubert 		bufferevent_data_cb r, w;
1692b15cb3dSCy Schubert 		bufferevent_event_cb e;
1702b15cb3dSCy Schubert 		void *a;
1712b15cb3dSCy Schubert 		bufferevent_getcb(bev1, &r, &w, &e, &a);
1722b15cb3dSCy Schubert 		tt_ptr_op(r, ==, readcb);
1732b15cb3dSCy Schubert 		tt_ptr_op(w, ==, writecb);
1742b15cb3dSCy Schubert 		tt_ptr_op(e, ==, errorcb);
1752b15cb3dSCy Schubert 		tt_ptr_op(a, ==, use_pair ? bev1 : NULL);
1762b15cb3dSCy Schubert 	}
1772b15cb3dSCy Schubert 
1782b15cb3dSCy Schubert 	bufferevent_disable(bev1, EV_READ);
1792b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_READ);
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert 	tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE);
1822b15cb3dSCy Schubert 	tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ);
1832b15cb3dSCy Schubert 
1842b15cb3dSCy Schubert 	for (i = 0; i < (int)sizeof(buffer); i++)
1852b15cb3dSCy Schubert 		buffer[i] = i;
1862b15cb3dSCy Schubert 
1872b15cb3dSCy Schubert 	bufferevent_write(bev1, buffer, sizeof(buffer));
188*a466cc55SCy Schubert 	if (flush >= 0) {
189*a466cc55SCy Schubert 		tt_int_op(bufferevent_flush(bev1, EV_WRITE, flush), >=, 0);
190*a466cc55SCy Schubert 	}
1912b15cb3dSCy Schubert 
1922b15cb3dSCy Schubert 	event_dispatch();
1932b15cb3dSCy Schubert 
1942b15cb3dSCy Schubert 	bufferevent_free(bev2);
195a25439b6SCy Schubert 	tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
196a25439b6SCy Schubert 	bufferevent_free(bev1);
1972b15cb3dSCy Schubert 
198*a466cc55SCy Schubert 	/** Only pair call errorcb for BEV_FINISHED */
199*a466cc55SCy Schubert 	if (use_pair && flush == BEV_FINISHED) {
200*a466cc55SCy Schubert 		expected = -1;
201*a466cc55SCy Schubert 	}
202*a466cc55SCy Schubert 	if (test_ok != expected)
2032b15cb3dSCy Schubert 		test_ok = 0;
2042b15cb3dSCy Schubert end:
2052b15cb3dSCy Schubert 	;
2062b15cb3dSCy Schubert }
2072b15cb3dSCy Schubert 
test_bufferevent(void)208*a466cc55SCy Schubert static void test_bufferevent(void) { test_bufferevent_impl(0, -1); }
test_bufferevent_pair(void)209*a466cc55SCy Schubert static void test_bufferevent_pair(void) { test_bufferevent_impl(1, -1); }
2102b15cb3dSCy Schubert 
test_bufferevent_flush_normal(void)211*a466cc55SCy Schubert static void test_bufferevent_flush_normal(void) { test_bufferevent_impl(0, BEV_NORMAL); }
test_bufferevent_flush_flush(void)212*a466cc55SCy Schubert static void test_bufferevent_flush_flush(void) { test_bufferevent_impl(0, BEV_FLUSH); }
test_bufferevent_flush_finished(void)213*a466cc55SCy Schubert static void test_bufferevent_flush_finished(void) { test_bufferevent_impl(0, BEV_FINISHED); }
2142b15cb3dSCy Schubert 
test_bufferevent_pair_flush_normal(void)215*a466cc55SCy Schubert static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, BEV_NORMAL); }
test_bufferevent_pair_flush_flush(void)216*a466cc55SCy Schubert static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); }
test_bufferevent_pair_flush_finished(void)217*a466cc55SCy Schubert static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); }
218*a466cc55SCy Schubert 
219*a466cc55SCy Schubert #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__)
220a25439b6SCy Schubert /**
221a25439b6SCy Schubert  * Trace lock/unlock/alloc/free for locks.
222a25439b6SCy Schubert  * (More heavier then evthread_debug*)
223a25439b6SCy Schubert  */
224a25439b6SCy Schubert typedef struct
225a25439b6SCy Schubert {
226a25439b6SCy Schubert 	void *lock;
227a25439b6SCy Schubert 	enum {
228a25439b6SCy Schubert 		ALLOC, FREE,
229a25439b6SCy Schubert 	} status;
230a25439b6SCy Schubert 	size_t locked /** allow recursive locking */;
231a25439b6SCy Schubert } lock_wrapper;
232a25439b6SCy Schubert struct lock_unlock_base
233a25439b6SCy Schubert {
234a25439b6SCy Schubert 	/* Original callbacks */
235a25439b6SCy Schubert 	struct evthread_lock_callbacks cbs;
236a25439b6SCy Schubert 	/* Map of locks */
237a25439b6SCy Schubert 	lock_wrapper *locks;
238a25439b6SCy Schubert 	size_t nr_locks;
239a25439b6SCy Schubert } lu_base = {
240a25439b6SCy Schubert 	.locks = NULL,
241a25439b6SCy Schubert };
242a25439b6SCy Schubert 
lu_find(void * lock_)243a25439b6SCy Schubert static lock_wrapper *lu_find(void *lock_)
244a25439b6SCy Schubert {
245a25439b6SCy Schubert 	size_t i;
246a25439b6SCy Schubert 	for (i = 0; i < lu_base.nr_locks; ++i) {
247a25439b6SCy Schubert 		lock_wrapper *lock = &lu_base.locks[i];
248a25439b6SCy Schubert 		if (lock->lock == lock_)
249a25439b6SCy Schubert 			return lock;
250a25439b6SCy Schubert 	}
251a25439b6SCy Schubert 	return NULL;
252a25439b6SCy Schubert }
253a25439b6SCy Schubert 
trace_lock_alloc(unsigned locktype)254a25439b6SCy Schubert static void *trace_lock_alloc(unsigned locktype)
255a25439b6SCy Schubert {
256*a466cc55SCy Schubert 	void *lock;
257a25439b6SCy Schubert 	++lu_base.nr_locks;
258a25439b6SCy Schubert 	lu_base.locks = realloc(lu_base.locks,
259a25439b6SCy Schubert 		sizeof(lock_wrapper) * lu_base.nr_locks);
260*a466cc55SCy Schubert 	lock = lu_base.cbs.alloc(locktype);
261a25439b6SCy Schubert 	lu_base.locks[lu_base.nr_locks - 1] = (lock_wrapper){ lock, ALLOC, 0 };
262a25439b6SCy Schubert 	return lock;
263a25439b6SCy Schubert }
trace_lock_free(void * lock_,unsigned locktype)264a25439b6SCy Schubert static void trace_lock_free(void *lock_, unsigned locktype)
265a25439b6SCy Schubert {
266a25439b6SCy Schubert 	lock_wrapper *lock = lu_find(lock_);
267a25439b6SCy Schubert 	if (!lock || lock->status == FREE || lock->locked) {
268a25439b6SCy Schubert 		TT_FAIL(("lock: free error"));
269a25439b6SCy Schubert 	} else {
270a25439b6SCy Schubert 		lock->status = FREE;
271a25439b6SCy Schubert 		lu_base.cbs.free(lock_, locktype);
272a25439b6SCy Schubert 	}
273a25439b6SCy Schubert }
trace_lock_lock(unsigned mode,void * lock_)274a25439b6SCy Schubert static int trace_lock_lock(unsigned mode, void *lock_)
275a25439b6SCy Schubert {
276a25439b6SCy Schubert 	lock_wrapper *lock = lu_find(lock_);
277a25439b6SCy Schubert 	if (!lock || lock->status == FREE) {
278a25439b6SCy Schubert 		TT_FAIL(("lock: lock error"));
279a25439b6SCy Schubert 		return -1;
280a25439b6SCy Schubert 	} else {
281a25439b6SCy Schubert 		++lock->locked;
282a25439b6SCy Schubert 		return lu_base.cbs.lock(mode, lock_);
283a25439b6SCy Schubert 	}
284a25439b6SCy Schubert }
trace_lock_unlock(unsigned mode,void * lock_)285a25439b6SCy Schubert static int trace_lock_unlock(unsigned mode, void *lock_)
286a25439b6SCy Schubert {
287a25439b6SCy Schubert 	lock_wrapper *lock = lu_find(lock_);
288a25439b6SCy Schubert 	if (!lock || lock->status == FREE || !lock->locked) {
289a25439b6SCy Schubert 		TT_FAIL(("lock: unlock error"));
290a25439b6SCy Schubert 		return -1;
291a25439b6SCy Schubert 	} else {
292a25439b6SCy Schubert 		--lock->locked;
293a25439b6SCy Schubert 		return lu_base.cbs.unlock(mode, lock_);
294a25439b6SCy Schubert 	}
295a25439b6SCy Schubert }
lock_unlock_free_thread_cbs(void)296*a466cc55SCy Schubert static void lock_unlock_free_thread_cbs(void)
297a25439b6SCy Schubert {
298a25439b6SCy Schubert 	event_base_free(NULL);
299a25439b6SCy Schubert 
300*a466cc55SCy Schubert 	if (libevent_tests_running_in_debug_mode)
301*a466cc55SCy Schubert 		libevent_global_shutdown();
302*a466cc55SCy Schubert 
303a25439b6SCy Schubert 	/** drop immutable flag */
304a25439b6SCy Schubert 	evthread_set_lock_callbacks(NULL);
305a25439b6SCy Schubert 	/** avoid calling of event_global_setup_locks_() for new cbs */
306a25439b6SCy Schubert 	libevent_global_shutdown();
307a25439b6SCy Schubert 	/** drop immutable flag for non-debug ops (since called after shutdown) */
308a25439b6SCy Schubert 	evthread_set_lock_callbacks(NULL);
309a25439b6SCy Schubert }
310a25439b6SCy Schubert 
use_lock_unlock_profiler(void)311a25439b6SCy Schubert static int use_lock_unlock_profiler(void)
312a25439b6SCy Schubert {
313a25439b6SCy Schubert 	struct evthread_lock_callbacks cbs = {
314a25439b6SCy Schubert 		EVTHREAD_LOCK_API_VERSION,
315a25439b6SCy Schubert 		EVTHREAD_LOCKTYPE_RECURSIVE,
316a25439b6SCy Schubert 		trace_lock_alloc,
317a25439b6SCy Schubert 		trace_lock_free,
318a25439b6SCy Schubert 		trace_lock_lock,
319a25439b6SCy Schubert 		trace_lock_unlock,
320a25439b6SCy Schubert 	};
321a25439b6SCy Schubert 	memcpy(&lu_base.cbs, evthread_get_lock_callbacks(),
322a25439b6SCy Schubert 		sizeof(lu_base.cbs));
323a25439b6SCy Schubert 	{
324a25439b6SCy Schubert 		lock_unlock_free_thread_cbs();
325a25439b6SCy Schubert 
326a25439b6SCy Schubert 		evthread_set_lock_callbacks(&cbs);
327a25439b6SCy Schubert 		/** re-create debug locks correctly */
328a25439b6SCy Schubert 		evthread_enable_lock_debugging();
329a25439b6SCy Schubert 
330a25439b6SCy Schubert 		event_init();
331a25439b6SCy Schubert 	}
332a25439b6SCy Schubert 	return 0;
333a25439b6SCy Schubert }
free_lock_unlock_profiler(struct basic_test_data * data)334a25439b6SCy Schubert static void free_lock_unlock_profiler(struct basic_test_data *data)
335a25439b6SCy Schubert {
336*a466cc55SCy Schubert 	/** fix "held_by" for kqueue */
337*a466cc55SCy Schubert 	evthread_set_lock_callbacks(NULL);
338*a466cc55SCy Schubert 
339a25439b6SCy Schubert 	lock_unlock_free_thread_cbs();
340a25439b6SCy Schubert 	free(lu_base.locks);
341a25439b6SCy Schubert 	data->base = NULL;
342a25439b6SCy Schubert }
343a25439b6SCy Schubert 
test_bufferevent_pair_release_lock(void * arg)344a25439b6SCy Schubert static void test_bufferevent_pair_release_lock(void *arg)
345a25439b6SCy Schubert {
346a25439b6SCy Schubert 	struct basic_test_data *data = arg;
347a25439b6SCy Schubert 	use_lock_unlock_profiler();
348a25439b6SCy Schubert 	{
349a25439b6SCy Schubert 		struct bufferevent *pair[2];
350a25439b6SCy Schubert 		if (!bufferevent_pair_new(NULL, BEV_OPT_THREADSAFE, pair)) {
351a25439b6SCy Schubert 			bufferevent_free(pair[0]);
352a25439b6SCy Schubert 			bufferevent_free(pair[1]);
353a25439b6SCy Schubert 		} else
354a25439b6SCy Schubert 			tt_abort_perror("bufferevent_pair_new");
355a25439b6SCy Schubert 	}
356a25439b6SCy Schubert 	free_lock_unlock_profiler(data);
357a25439b6SCy Schubert end:
358a25439b6SCy Schubert 	;
359a25439b6SCy Schubert }
360a25439b6SCy Schubert #endif
361a25439b6SCy Schubert 
3622b15cb3dSCy Schubert /*
3632b15cb3dSCy Schubert  * test watermarks and bufferevent
3642b15cb3dSCy Schubert  */
3652b15cb3dSCy Schubert 
3662b15cb3dSCy Schubert static void
wm_readcb(struct bufferevent * bev,void * arg)3672b15cb3dSCy Schubert wm_readcb(struct bufferevent *bev, void *arg)
3682b15cb3dSCy Schubert {
3692b15cb3dSCy Schubert 	struct evbuffer *evbuf = evbuffer_new();
3702b15cb3dSCy Schubert 	int len = (int)evbuffer_get_length(bev->input);
3712b15cb3dSCy Schubert 	static int nread;
3722b15cb3dSCy Schubert 
3732b15cb3dSCy Schubert 	assert(len >= 10 && len <= 20);
3742b15cb3dSCy Schubert 
3752b15cb3dSCy Schubert 	assert(evbuf != NULL);
3762b15cb3dSCy Schubert 
3772b15cb3dSCy Schubert 	/* gratuitous test of bufferevent_read_buffer */
3782b15cb3dSCy Schubert 	bufferevent_read_buffer(bev, evbuf);
3792b15cb3dSCy Schubert 
3802b15cb3dSCy Schubert 	nread += len;
3812b15cb3dSCy Schubert 	if (nread == 65000) {
3822b15cb3dSCy Schubert 		bufferevent_disable(bev, EV_READ);
3832b15cb3dSCy Schubert 		test_ok++;
3842b15cb3dSCy Schubert 	}
3852b15cb3dSCy Schubert 
3862b15cb3dSCy Schubert 	evbuffer_free(evbuf);
3872b15cb3dSCy Schubert }
3882b15cb3dSCy Schubert 
3892b15cb3dSCy Schubert static void
wm_writecb(struct bufferevent * bev,void * arg)3902b15cb3dSCy Schubert wm_writecb(struct bufferevent *bev, void *arg)
3912b15cb3dSCy Schubert {
3922b15cb3dSCy Schubert 	assert(evbuffer_get_length(bev->output) <= 100);
3932b15cb3dSCy Schubert 	if (evbuffer_get_length(bev->output) == 0) {
3942b15cb3dSCy Schubert 		evbuffer_drain(bev->output, evbuffer_get_length(bev->output));
3952b15cb3dSCy Schubert 		test_ok++;
3962b15cb3dSCy Schubert 	}
3972b15cb3dSCy Schubert }
3982b15cb3dSCy Schubert 
3992b15cb3dSCy Schubert static void
wm_errorcb(struct bufferevent * bev,short what,void * arg)4002b15cb3dSCy Schubert wm_errorcb(struct bufferevent *bev, short what, void *arg)
4012b15cb3dSCy Schubert {
4022b15cb3dSCy Schubert 	test_ok = -2;
4032b15cb3dSCy Schubert }
4042b15cb3dSCy Schubert 
4052b15cb3dSCy Schubert static void
test_bufferevent_watermarks_impl(int use_pair)4062b15cb3dSCy Schubert test_bufferevent_watermarks_impl(int use_pair)
4072b15cb3dSCy Schubert {
4082b15cb3dSCy Schubert 	struct bufferevent *bev1 = NULL, *bev2 = NULL;
4092b15cb3dSCy Schubert 	char buffer[65000];
4102b15cb3dSCy Schubert 	size_t low, high;
4112b15cb3dSCy Schubert 	int i;
4122b15cb3dSCy Schubert 	test_ok = 0;
4132b15cb3dSCy Schubert 
4142b15cb3dSCy Schubert 	if (use_pair) {
4152b15cb3dSCy Schubert 		struct bufferevent *pair[2];
4162b15cb3dSCy Schubert 		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
4172b15cb3dSCy Schubert 		bev1 = pair[0];
4182b15cb3dSCy Schubert 		bev2 = pair[1];
4192b15cb3dSCy Schubert 		bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL);
4202b15cb3dSCy Schubert 		bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL);
4212b15cb3dSCy Schubert 	} else {
4222b15cb3dSCy Schubert 		bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
4232b15cb3dSCy Schubert 		bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
4242b15cb3dSCy Schubert 	}
4252b15cb3dSCy Schubert 	tt_assert(bev1);
4262b15cb3dSCy Schubert 	tt_assert(bev2);
4272b15cb3dSCy Schubert 	bufferevent_disable(bev1, EV_READ);
4282b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_READ);
4292b15cb3dSCy Schubert 
4302b15cb3dSCy Schubert 	/* By default, low watermarks are set to 0 */
4312b15cb3dSCy Schubert 	bufferevent_getwatermark(bev1, EV_READ, &low, NULL);
4322b15cb3dSCy Schubert 	tt_int_op(low, ==, 0);
4332b15cb3dSCy Schubert 	bufferevent_getwatermark(bev2, EV_WRITE, &low, NULL);
4342b15cb3dSCy Schubert 	tt_int_op(low, ==, 0);
4352b15cb3dSCy Schubert 
4362b15cb3dSCy Schubert 	for (i = 0; i < (int)sizeof(buffer); i++)
4372b15cb3dSCy Schubert 		buffer[i] = (char)i;
4382b15cb3dSCy Schubert 
4392b15cb3dSCy Schubert 	/* limit the reading on the receiving bufferevent */
4402b15cb3dSCy Schubert 	bufferevent_setwatermark(bev2, EV_READ, 10, 20);
4412b15cb3dSCy Schubert 
4422b15cb3dSCy Schubert 	bufferevent_getwatermark(bev2, EV_READ, &low, &high);
4432b15cb3dSCy Schubert 	tt_int_op(low, ==, 10);
4442b15cb3dSCy Schubert 	tt_int_op(high, ==, 20);
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert 	/* Tell the sending bufferevent not to notify us till it's down to
4472b15cb3dSCy Schubert 	   100 bytes. */
4482b15cb3dSCy Schubert 	bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
4492b15cb3dSCy Schubert 
4502b15cb3dSCy Schubert 	bufferevent_getwatermark(bev1, EV_WRITE, &low, &high);
4512b15cb3dSCy Schubert 	tt_int_op(low, ==, 100);
4522b15cb3dSCy Schubert 	tt_int_op(high, ==, 2000);
4532b15cb3dSCy Schubert 
454a25439b6SCy Schubert 	{
455a25439b6SCy Schubert 	int r = bufferevent_getwatermark(bev1, EV_WRITE | EV_READ, &low, &high);
456a25439b6SCy Schubert 	tt_int_op(r, !=, 0);
457a25439b6SCy Schubert 	}
458a25439b6SCy Schubert 
4592b15cb3dSCy Schubert 	bufferevent_write(bev1, buffer, sizeof(buffer));
4602b15cb3dSCy Schubert 
4612b15cb3dSCy Schubert 	event_dispatch();
4622b15cb3dSCy Schubert 
4632b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
4642b15cb3dSCy Schubert 
4652b15cb3dSCy Schubert 	/* The write callback drained all the data from outbuf, so we
4662b15cb3dSCy Schubert 	 * should have removed the write event... */
4672b15cb3dSCy Schubert 	tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL));
4682b15cb3dSCy Schubert 
4692b15cb3dSCy Schubert end:
4702b15cb3dSCy Schubert 	if (bev1)
4712b15cb3dSCy Schubert 		bufferevent_free(bev1);
4722b15cb3dSCy Schubert 	if (bev2)
4732b15cb3dSCy Schubert 		bufferevent_free(bev2);
4742b15cb3dSCy Schubert }
4752b15cb3dSCy Schubert 
4762b15cb3dSCy Schubert static void
test_bufferevent_watermarks(void)4772b15cb3dSCy Schubert test_bufferevent_watermarks(void)
4782b15cb3dSCy Schubert {
4792b15cb3dSCy Schubert 	test_bufferevent_watermarks_impl(0);
4802b15cb3dSCy Schubert }
4812b15cb3dSCy Schubert 
4822b15cb3dSCy Schubert static void
test_bufferevent_pair_watermarks(void)4832b15cb3dSCy Schubert test_bufferevent_pair_watermarks(void)
4842b15cb3dSCy Schubert {
4852b15cb3dSCy Schubert 	test_bufferevent_watermarks_impl(1);
4862b15cb3dSCy Schubert }
4872b15cb3dSCy Schubert 
4882b15cb3dSCy Schubert /*
4892b15cb3dSCy Schubert  * Test bufferevent filters
4902b15cb3dSCy Schubert  */
4912b15cb3dSCy Schubert 
4922b15cb3dSCy Schubert /* strip an 'x' from each byte */
4932b15cb3dSCy Schubert 
4942b15cb3dSCy Schubert static enum bufferevent_filter_result
bufferevent_input_filter(struct evbuffer * src,struct evbuffer * dst,ev_ssize_t lim,enum bufferevent_flush_mode state,void * ctx)4952b15cb3dSCy Schubert bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
4962b15cb3dSCy Schubert     ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
4972b15cb3dSCy Schubert {
4982b15cb3dSCy Schubert 	const unsigned char *buffer;
4992b15cb3dSCy Schubert 	unsigned i;
5002b15cb3dSCy Schubert 
5012b15cb3dSCy Schubert 	buffer = evbuffer_pullup(src, evbuffer_get_length(src));
5022b15cb3dSCy Schubert 	for (i = 0; i < evbuffer_get_length(src); i += 2) {
503*a466cc55SCy Schubert 		if (buffer[i] == '-')
504*a466cc55SCy Schubert 			continue;
505*a466cc55SCy Schubert 
5062b15cb3dSCy Schubert 		assert(buffer[i] == 'x');
5072b15cb3dSCy Schubert 		evbuffer_add(dst, buffer + i + 1, 1);
5082b15cb3dSCy Schubert 	}
5092b15cb3dSCy Schubert 
5102b15cb3dSCy Schubert 	evbuffer_drain(src, i);
5112b15cb3dSCy Schubert 	return (BEV_OK);
5122b15cb3dSCy Schubert }
5132b15cb3dSCy Schubert 
5142b15cb3dSCy Schubert /* add an 'x' before each byte */
5152b15cb3dSCy Schubert 
5162b15cb3dSCy Schubert static enum bufferevent_filter_result
bufferevent_output_filter(struct evbuffer * src,struct evbuffer * dst,ev_ssize_t lim,enum bufferevent_flush_mode state,void * ctx)5172b15cb3dSCy Schubert bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
5182b15cb3dSCy Schubert     ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
5192b15cb3dSCy Schubert {
5202b15cb3dSCy Schubert 	const unsigned char *buffer;
5212b15cb3dSCy Schubert 	unsigned i;
522*a466cc55SCy Schubert 	struct bufferevent **bevp = ctx;
5232b15cb3dSCy Schubert 
524*a466cc55SCy Schubert 	++test_ok;
525*a466cc55SCy Schubert 
526*a466cc55SCy Schubert 	if (test_ok == 1) {
5272b15cb3dSCy Schubert 		buffer = evbuffer_pullup(src, evbuffer_get_length(src));
5282b15cb3dSCy Schubert 		for (i = 0; i < evbuffer_get_length(src); ++i) {
5292b15cb3dSCy Schubert 			evbuffer_add(dst, "x", 1);
5302b15cb3dSCy Schubert 			evbuffer_add(dst, buffer + i, 1);
5312b15cb3dSCy Schubert 		}
5322b15cb3dSCy Schubert 		evbuffer_drain(src, evbuffer_get_length(src));
533*a466cc55SCy Schubert 	} else {
534*a466cc55SCy Schubert 		return BEV_ERROR;
535*a466cc55SCy Schubert 	}
536*a466cc55SCy Schubert 
537*a466cc55SCy Schubert 	if (bevp && test_ok == 1) {
538*a466cc55SCy Schubert 		int prev = ++test_ok;
539*a466cc55SCy Schubert 		bufferevent_write(*bevp, "-", 1);
540*a466cc55SCy Schubert 		/* check that during this bufferevent_write()
541*a466cc55SCy Schubert 		 * bufferevent_output_filter() will not be called again */
542*a466cc55SCy Schubert 		assert(test_ok == prev);
543*a466cc55SCy Schubert 		--test_ok;
544*a466cc55SCy Schubert 	}
545*a466cc55SCy Schubert 
5462b15cb3dSCy Schubert 	return (BEV_OK);
5472b15cb3dSCy Schubert }
5482b15cb3dSCy Schubert 
5492b15cb3dSCy Schubert static void
test_bufferevent_filters_impl(int use_pair,int disable)550*a466cc55SCy Schubert test_bufferevent_filters_impl(int use_pair, int disable)
5512b15cb3dSCy Schubert {
5522b15cb3dSCy Schubert 	struct bufferevent *bev1 = NULL, *bev2 = NULL;
5532b15cb3dSCy Schubert 	struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
5542b15cb3dSCy Schubert 	char buffer[8333];
5552b15cb3dSCy Schubert 	int i;
5562b15cb3dSCy Schubert 
5572b15cb3dSCy Schubert 	test_ok = 0;
5582b15cb3dSCy Schubert 
5592b15cb3dSCy Schubert 	if (use_pair) {
5602b15cb3dSCy Schubert 		struct bufferevent *pair[2];
5612b15cb3dSCy Schubert 		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
5622b15cb3dSCy Schubert 		bev1 = pair[0];
5632b15cb3dSCy Schubert 		bev2 = pair[1];
5642b15cb3dSCy Schubert 	} else {
5652b15cb3dSCy Schubert 		bev1 = bufferevent_socket_new(NULL, pair[0], 0);
5662b15cb3dSCy Schubert 		bev2 = bufferevent_socket_new(NULL, pair[1], 0);
5672b15cb3dSCy Schubert 	}
5682b15cb3dSCy Schubert 	bev1_base = bev1;
5692b15cb3dSCy Schubert 	bev2_base = bev2;
5702b15cb3dSCy Schubert 
5712b15cb3dSCy Schubert 	for (i = 0; i < (int)sizeof(buffer); i++)
5722b15cb3dSCy Schubert 		buffer[i] = i;
5732b15cb3dSCy Schubert 
5742b15cb3dSCy Schubert 	bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
575*a466cc55SCy Schubert 				      BEV_OPT_CLOSE_ON_FREE, NULL,
576*a466cc55SCy Schubert 					  disable ? &bev1 : NULL);
5772b15cb3dSCy Schubert 
5782b15cb3dSCy Schubert 	bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
5792b15cb3dSCy Schubert 				      NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
5802b15cb3dSCy Schubert 	bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL);
5812b15cb3dSCy Schubert 	bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL);
5822b15cb3dSCy Schubert 
5832b15cb3dSCy Schubert 	tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
5842b15cb3dSCy Schubert 	tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
585*a466cc55SCy Schubert 	tt_fd_op(bufferevent_getfd(bev1), ==, bufferevent_getfd(bev1_base));
586*a466cc55SCy Schubert 	tt_fd_op(bufferevent_getfd(bev2), ==, bufferevent_getfd(bev2_base));
5872b15cb3dSCy Schubert 
5882b15cb3dSCy Schubert 	bufferevent_disable(bev1, EV_READ);
5892b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_READ);
5902b15cb3dSCy Schubert 	/* insert some filters */
5912b15cb3dSCy Schubert 	bufferevent_write(bev1, buffer, sizeof(buffer));
5922b15cb3dSCy Schubert 
5932b15cb3dSCy Schubert 	event_dispatch();
5942b15cb3dSCy Schubert 
595*a466cc55SCy Schubert 	if (test_ok != 3 + !!disable)
5962b15cb3dSCy Schubert 		test_ok = 0;
5972b15cb3dSCy Schubert 
5982b15cb3dSCy Schubert end:
5992b15cb3dSCy Schubert 	if (bev1)
6002b15cb3dSCy Schubert 		bufferevent_free(bev1);
6012b15cb3dSCy Schubert 	if (bev2)
6022b15cb3dSCy Schubert 		bufferevent_free(bev2);
6032b15cb3dSCy Schubert 
6042b15cb3dSCy Schubert }
6052b15cb3dSCy Schubert 
test_bufferevent_filters(void)606*a466cc55SCy Schubert static void test_bufferevent_filters(void)
607*a466cc55SCy Schubert { test_bufferevent_filters_impl(0, 0); }
test_bufferevent_pair_filters(void)608*a466cc55SCy Schubert static void test_bufferevent_pair_filters(void)
609*a466cc55SCy Schubert { test_bufferevent_filters_impl(1, 0); }
test_bufferevent_filters_disable(void)610*a466cc55SCy Schubert static void test_bufferevent_filters_disable(void)
611*a466cc55SCy Schubert { test_bufferevent_filters_impl(0, 1); }
test_bufferevent_pair_filters_disable(void)612*a466cc55SCy Schubert static void test_bufferevent_pair_filters_disable(void)
613*a466cc55SCy Schubert { test_bufferevent_filters_impl(1, 1); }
6142b15cb3dSCy Schubert 
6152b15cb3dSCy Schubert 
6162b15cb3dSCy Schubert static void
sender_writecb(struct bufferevent * bev,void * ctx)6172b15cb3dSCy Schubert sender_writecb(struct bufferevent *bev, void *ctx)
6182b15cb3dSCy Schubert {
6192b15cb3dSCy Schubert 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
6202b15cb3dSCy Schubert 		bufferevent_disable(bev,EV_READ|EV_WRITE);
6212b15cb3dSCy Schubert 		TT_BLATHER(("Flushed %d: freeing it.", (int)bufferevent_getfd(bev)));
6222b15cb3dSCy Schubert 		bufferevent_free(bev);
6232b15cb3dSCy Schubert 	}
6242b15cb3dSCy Schubert }
6252b15cb3dSCy Schubert 
6262b15cb3dSCy Schubert static void
sender_errorcb(struct bufferevent * bev,short what,void * ctx)6272b15cb3dSCy Schubert sender_errorcb(struct bufferevent *bev, short what, void *ctx)
6282b15cb3dSCy Schubert {
6292b15cb3dSCy Schubert 	TT_FAIL(("Got sender error %d",(int)what));
6302b15cb3dSCy Schubert }
6312b15cb3dSCy Schubert 
6322b15cb3dSCy Schubert static int bufferevent_connect_test_flags = 0;
6332b15cb3dSCy Schubert static int bufferevent_trigger_test_flags = 0;
6342b15cb3dSCy Schubert static int n_strings_read = 0;
6352b15cb3dSCy Schubert static int n_reads_invoked = 0;
636*a466cc55SCy Schubert static int n_events_invoked = 0;
6372b15cb3dSCy Schubert 
6382b15cb3dSCy Schubert #define TEST_STR "Now is the time for all good events to signal for " \
6392b15cb3dSCy Schubert 	"the good of their protocol"
6402b15cb3dSCy Schubert static void
listen_cb(struct evconnlistener * listener,evutil_socket_t fd,struct sockaddr * sa,int socklen,void * arg)6412b15cb3dSCy Schubert listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
6422b15cb3dSCy Schubert     struct sockaddr *sa, int socklen, void *arg)
6432b15cb3dSCy Schubert {
6442b15cb3dSCy Schubert 	struct event_base *base = arg;
6452b15cb3dSCy Schubert 	struct bufferevent *bev;
6462b15cb3dSCy Schubert 	const char s[] = TEST_STR;
6472b15cb3dSCy Schubert 	TT_BLATHER(("Got a request on socket %d", (int)fd ));
6482b15cb3dSCy Schubert 	bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags);
6492b15cb3dSCy Schubert 	tt_assert(bev);
6502b15cb3dSCy Schubert 	bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL);
6512b15cb3dSCy Schubert 	bufferevent_write(bev, s, sizeof(s));
6522b15cb3dSCy Schubert end:
6532b15cb3dSCy Schubert 	;
6542b15cb3dSCy Schubert }
6552b15cb3dSCy Schubert 
656*a466cc55SCy Schubert static evutil_socket_t
fake_listener_create(struct sockaddr_in * localhost)657*a466cc55SCy Schubert fake_listener_create(struct sockaddr_in *localhost)
658*a466cc55SCy Schubert {
659*a466cc55SCy Schubert 	struct sockaddr *sa = (struct sockaddr *)localhost;
660*a466cc55SCy Schubert 	evutil_socket_t fd = -1;
661*a466cc55SCy Schubert 	ev_socklen_t slen = sizeof(*localhost);
662*a466cc55SCy Schubert 
663*a466cc55SCy Schubert 	memset(localhost, 0, sizeof(*localhost));
664*a466cc55SCy Schubert 	localhost->sin_port = 0; /* have the kernel pick a port */
665*a466cc55SCy Schubert 	localhost->sin_addr.s_addr = htonl(0x7f000001L);
666*a466cc55SCy Schubert 	localhost->sin_family = AF_INET;
667*a466cc55SCy Schubert 
668*a466cc55SCy Schubert 	/* bind, but don't listen or accept. should trigger
669*a466cc55SCy Schubert 	   "Connection refused" reliably on most platforms. */
670*a466cc55SCy Schubert 	fd = socket(localhost->sin_family, SOCK_STREAM, 0);
671*a466cc55SCy Schubert 	tt_assert(fd >= 0);
672*a466cc55SCy Schubert 	tt_assert(bind(fd, sa, slen) == 0);
673*a466cc55SCy Schubert 	tt_assert(getsockname(fd, sa, &slen) == 0);
674*a466cc55SCy Schubert 
675*a466cc55SCy Schubert 	return fd;
676*a466cc55SCy Schubert 
677*a466cc55SCy Schubert end:
678*a466cc55SCy Schubert 	return -1;
679*a466cc55SCy Schubert }
680*a466cc55SCy Schubert 
6812b15cb3dSCy Schubert static void
reader_eventcb(struct bufferevent * bev,short what,void * ctx)6822b15cb3dSCy Schubert reader_eventcb(struct bufferevent *bev, short what, void *ctx)
6832b15cb3dSCy Schubert {
6842b15cb3dSCy Schubert 	struct event_base *base = ctx;
6852b15cb3dSCy Schubert 	if (what & BEV_EVENT_ERROR) {
6862b15cb3dSCy Schubert 		perror("foobar");
6872b15cb3dSCy Schubert 		TT_FAIL(("got connector error %d", (int)what));
6882b15cb3dSCy Schubert 		return;
6892b15cb3dSCy Schubert 	}
6902b15cb3dSCy Schubert 	if (what & BEV_EVENT_CONNECTED) {
6912b15cb3dSCy Schubert 		TT_BLATHER(("connected on %d", (int)bufferevent_getfd(bev)));
6922b15cb3dSCy Schubert 		bufferevent_enable(bev, EV_READ);
6932b15cb3dSCy Schubert 	}
6942b15cb3dSCy Schubert 	if (what & BEV_EVENT_EOF) {
6952b15cb3dSCy Schubert 		char buf[512];
6962b15cb3dSCy Schubert 		size_t n;
6972b15cb3dSCy Schubert 		n = bufferevent_read(bev, buf, sizeof(buf)-1);
6982b15cb3dSCy Schubert 		tt_int_op(n, >=, 0);
6992b15cb3dSCy Schubert 		buf[n] = '\0';
7002b15cb3dSCy Schubert 		tt_str_op(buf, ==, TEST_STR);
7012b15cb3dSCy Schubert 		if (++n_strings_read == 2)
7022b15cb3dSCy Schubert 			event_base_loopexit(base, NULL);
7032b15cb3dSCy Schubert 		TT_BLATHER(("EOF on %d: %d strings read.",
7042b15cb3dSCy Schubert 			(int)bufferevent_getfd(bev), n_strings_read));
7052b15cb3dSCy Schubert 	}
7062b15cb3dSCy Schubert end:
7072b15cb3dSCy Schubert 	;
7082b15cb3dSCy Schubert }
7092b15cb3dSCy Schubert 
7102b15cb3dSCy Schubert static void
reader_eventcb_simple(struct bufferevent * bev,short what,void * ctx)711*a466cc55SCy Schubert reader_eventcb_simple(struct bufferevent *bev, short what, void *ctx)
712*a466cc55SCy Schubert {
713*a466cc55SCy Schubert 	TT_BLATHER(("Read eventcb simple invoked on %d.",
714*a466cc55SCy Schubert 		(int)bufferevent_getfd(bev)));
715*a466cc55SCy Schubert 	n_events_invoked++;
716*a466cc55SCy Schubert }
717*a466cc55SCy Schubert 
718*a466cc55SCy Schubert static void
reader_readcb(struct bufferevent * bev,void * ctx)7192b15cb3dSCy Schubert reader_readcb(struct bufferevent *bev, void *ctx)
7202b15cb3dSCy Schubert {
7212b15cb3dSCy Schubert 	TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev)));
7222b15cb3dSCy Schubert 	n_reads_invoked++;
7232b15cb3dSCy Schubert }
7242b15cb3dSCy Schubert 
7252b15cb3dSCy Schubert static void
test_bufferevent_connect(void * arg)7262b15cb3dSCy Schubert test_bufferevent_connect(void *arg)
7272b15cb3dSCy Schubert {
7282b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
7292b15cb3dSCy Schubert 	struct evconnlistener *lev=NULL;
7302b15cb3dSCy Schubert 	struct bufferevent *bev1=NULL, *bev2=NULL;
7312b15cb3dSCy Schubert 	struct sockaddr_in localhost;
7322b15cb3dSCy Schubert 	struct sockaddr_storage ss;
7332b15cb3dSCy Schubert 	struct sockaddr *sa;
7342b15cb3dSCy Schubert 	ev_socklen_t slen;
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert 	int be_flags=BEV_OPT_CLOSE_ON_FREE;
7372b15cb3dSCy Schubert 
7382b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "defer")) {
7392b15cb3dSCy Schubert 		be_flags |= BEV_OPT_DEFER_CALLBACKS;
7402b15cb3dSCy Schubert 	}
7412b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "unlocked")) {
7422b15cb3dSCy Schubert 		be_flags |= BEV_OPT_UNLOCK_CALLBACKS;
7432b15cb3dSCy Schubert 	}
7442b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "lock")) {
7452b15cb3dSCy Schubert 		be_flags |= BEV_OPT_THREADSAFE;
7462b15cb3dSCy Schubert 	}
7472b15cb3dSCy Schubert 	bufferevent_connect_test_flags = be_flags;
7482b15cb3dSCy Schubert #ifdef _WIN32
7492b15cb3dSCy Schubert 	if (!strcmp((char*)data->setup_data, "unset_connectex")) {
7502b15cb3dSCy Schubert 		struct win32_extension_fns *ext =
7512b15cb3dSCy Schubert 		    (struct win32_extension_fns *)
7522b15cb3dSCy Schubert 		    event_get_win32_extension_fns_();
7532b15cb3dSCy Schubert 		ext->ConnectEx = NULL;
7542b15cb3dSCy Schubert 	}
7552b15cb3dSCy Schubert #endif
7562b15cb3dSCy Schubert 
7572b15cb3dSCy Schubert 	memset(&localhost, 0, sizeof(localhost));
7582b15cb3dSCy Schubert 
7592b15cb3dSCy Schubert 	localhost.sin_port = 0; /* pick-a-port */
7602b15cb3dSCy Schubert 	localhost.sin_addr.s_addr = htonl(0x7f000001L);
7612b15cb3dSCy Schubert 	localhost.sin_family = AF_INET;
7622b15cb3dSCy Schubert 	sa = (struct sockaddr *)&localhost;
7632b15cb3dSCy Schubert 	lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
7642b15cb3dSCy Schubert 	    LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
7652b15cb3dSCy Schubert 	    16, sa, sizeof(localhost));
7662b15cb3dSCy Schubert 	tt_assert(lev);
7672b15cb3dSCy Schubert 
7682b15cb3dSCy Schubert 	sa = (struct sockaddr *)&ss;
7692b15cb3dSCy Schubert 	slen = sizeof(ss);
7702b15cb3dSCy Schubert 	if (regress_get_listener_addr(lev, sa, &slen) < 0) {
7712b15cb3dSCy Schubert 		tt_abort_perror("getsockname");
7722b15cb3dSCy Schubert 	}
7732b15cb3dSCy Schubert 
7742b15cb3dSCy Schubert 	tt_assert(!evconnlistener_enable(lev));
7752b15cb3dSCy Schubert 	bev1 = bufferevent_socket_new(data->base, -1, be_flags);
7762b15cb3dSCy Schubert 	bev2 = bufferevent_socket_new(data->base, -1, be_flags);
7772b15cb3dSCy Schubert 	tt_assert(bev1);
7782b15cb3dSCy Schubert 	tt_assert(bev2);
7792b15cb3dSCy Schubert 	bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base);
7802b15cb3dSCy Schubert 	bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base);
7812b15cb3dSCy Schubert 
7822b15cb3dSCy Schubert 	bufferevent_enable(bev1, EV_READ);
7832b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_READ);
7842b15cb3dSCy Schubert 
7852b15cb3dSCy Schubert 	tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost)));
7862b15cb3dSCy Schubert 	tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost)));
7872b15cb3dSCy Schubert 
7882b15cb3dSCy Schubert 	event_base_dispatch(data->base);
7892b15cb3dSCy Schubert 
7902b15cb3dSCy Schubert 	tt_int_op(n_strings_read, ==, 2);
7912b15cb3dSCy Schubert 	tt_int_op(n_reads_invoked, >=, 2);
7922b15cb3dSCy Schubert end:
7932b15cb3dSCy Schubert 	if (lev)
7942b15cb3dSCy Schubert 		evconnlistener_free(lev);
7952b15cb3dSCy Schubert 
7962b15cb3dSCy Schubert 	if (bev1)
7972b15cb3dSCy Schubert 		bufferevent_free(bev1);
7982b15cb3dSCy Schubert 
7992b15cb3dSCy Schubert 	if (bev2)
8002b15cb3dSCy Schubert 		bufferevent_free(bev2);
8012b15cb3dSCy Schubert }
8022b15cb3dSCy Schubert 
8032b15cb3dSCy Schubert static void
close_socket_cb(evutil_socket_t fd,short what,void * arg)804*a466cc55SCy Schubert close_socket_cb(evutil_socket_t fd, short what, void *arg)
805*a466cc55SCy Schubert {
806*a466cc55SCy Schubert 	evutil_socket_t *fdp = arg;
807*a466cc55SCy Schubert 	if (*fdp >= 0) {
808*a466cc55SCy Schubert 		evutil_closesocket(*fdp);
809*a466cc55SCy Schubert 		*fdp = -1;
810*a466cc55SCy Schubert 	}
811*a466cc55SCy Schubert }
812*a466cc55SCy Schubert 
813*a466cc55SCy Schubert static void
test_bufferevent_connect_fail_eventcb(void * arg)814*a466cc55SCy Schubert test_bufferevent_connect_fail_eventcb(void *arg)
815*a466cc55SCy Schubert {
816*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
817*a466cc55SCy Schubert 	int flags = BEV_OPT_CLOSE_ON_FREE | (long)data->setup_data;
818*a466cc55SCy Schubert 	struct event close_listener_event;
819*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
820*a466cc55SCy Schubert 	struct evconnlistener *lev = NULL;
821*a466cc55SCy Schubert 	struct sockaddr_in localhost;
822*a466cc55SCy Schubert 	struct timeval close_timeout = { 0, 300000 };
823*a466cc55SCy Schubert 	ev_socklen_t slen = sizeof(localhost);
824*a466cc55SCy Schubert 	evutil_socket_t fake_listener = -1;
825*a466cc55SCy Schubert 	int r;
826*a466cc55SCy Schubert 
827*a466cc55SCy Schubert 	fake_listener = fake_listener_create(&localhost);
828*a466cc55SCy Schubert 
829*a466cc55SCy Schubert 	tt_int_op(n_events_invoked, ==, 0);
830*a466cc55SCy Schubert 
831*a466cc55SCy Schubert 	bev = bufferevent_socket_new(data->base, -1, flags);
832*a466cc55SCy Schubert 	tt_assert(bev);
833*a466cc55SCy Schubert 	bufferevent_setcb(bev, reader_readcb, reader_readcb,
834*a466cc55SCy Schubert 		reader_eventcb_simple, data->base);
835*a466cc55SCy Schubert 	bufferevent_enable(bev, EV_READ|EV_WRITE);
836*a466cc55SCy Schubert 	tt_int_op(n_events_invoked, ==, 0);
837*a466cc55SCy Schubert 	tt_int_op(n_reads_invoked, ==, 0);
838*a466cc55SCy Schubert 
839*a466cc55SCy Schubert 	/** @see also test_bufferevent_connect_fail() */
840*a466cc55SCy Schubert 	r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
841*a466cc55SCy Schubert 	/* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
842*a466cc55SCy Schubert 	 * detects the error immediately, which is not really wrong of it. */
843*a466cc55SCy Schubert 	tt_want(r == 0 || r == -1);
844*a466cc55SCy Schubert 
845*a466cc55SCy Schubert 	tt_int_op(n_events_invoked, ==, 0);
846*a466cc55SCy Schubert 	tt_int_op(n_reads_invoked, ==, 0);
847*a466cc55SCy Schubert 
848*a466cc55SCy Schubert 	/* Close the listener socket after a delay. This should trigger
849*a466cc55SCy Schubert 	   "connection refused" on some other platforms, including OSX. */
850*a466cc55SCy Schubert 	evtimer_assign(&close_listener_event, data->base, close_socket_cb,
851*a466cc55SCy Schubert 	    &fake_listener);
852*a466cc55SCy Schubert 	event_add(&close_listener_event, &close_timeout);
853*a466cc55SCy Schubert 
854*a466cc55SCy Schubert 	event_base_dispatch(data->base);
855*a466cc55SCy Schubert 	tt_int_op(n_events_invoked, ==, 1);
856*a466cc55SCy Schubert 	tt_int_op(n_reads_invoked, ==, 0);
857*a466cc55SCy Schubert 
858*a466cc55SCy Schubert end:
859*a466cc55SCy Schubert 	if (lev)
860*a466cc55SCy Schubert 		evconnlistener_free(lev);
861*a466cc55SCy Schubert 	if (bev)
862*a466cc55SCy Schubert 		bufferevent_free(bev);
863*a466cc55SCy Schubert 	if (fake_listener >= 0)
864*a466cc55SCy Schubert 		evutil_closesocket(fake_listener);
865*a466cc55SCy Schubert }
866*a466cc55SCy Schubert 
867*a466cc55SCy Schubert static void
want_fail_eventcb(struct bufferevent * bev,short what,void * ctx)8682b15cb3dSCy Schubert want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
8692b15cb3dSCy Schubert {
8702b15cb3dSCy Schubert 	struct event_base *base = ctx;
8712b15cb3dSCy Schubert 	const char *err;
8722b15cb3dSCy Schubert 	evutil_socket_t s;
8732b15cb3dSCy Schubert 
8742b15cb3dSCy Schubert 	if (what & BEV_EVENT_ERROR) {
8752b15cb3dSCy Schubert 		s = bufferevent_getfd(bev);
8762b15cb3dSCy Schubert 		err = evutil_socket_error_to_string(evutil_socket_geterror(s));
8772b15cb3dSCy Schubert 		TT_BLATHER(("connection failure on "EV_SOCK_FMT": %s",
8782b15cb3dSCy Schubert 			EV_SOCK_ARG(s), err));
8792b15cb3dSCy Schubert 		test_ok = 1;
8802b15cb3dSCy Schubert 	} else {
8812b15cb3dSCy Schubert 		TT_FAIL(("didn't fail? what %hd", what));
8822b15cb3dSCy Schubert 	}
8832b15cb3dSCy Schubert 
8842b15cb3dSCy Schubert 	event_base_loopexit(base, NULL);
8852b15cb3dSCy Schubert }
8862b15cb3dSCy Schubert 
8872b15cb3dSCy Schubert static void
test_bufferevent_connect_fail(void * arg)8882b15cb3dSCy Schubert test_bufferevent_connect_fail(void *arg)
8892b15cb3dSCy Schubert {
8902b15cb3dSCy Schubert 	struct basic_test_data *data = (struct basic_test_data *)arg;
8912b15cb3dSCy Schubert 	struct bufferevent *bev=NULL;
8922b15cb3dSCy Schubert 	struct event close_listener_event;
8932b15cb3dSCy Schubert 	int close_listener_event_added = 0;
894*a466cc55SCy Schubert 	struct timeval close_timeout = { 0, 300000 };
895*a466cc55SCy Schubert 	struct sockaddr_in localhost;
896*a466cc55SCy Schubert 	ev_socklen_t slen = sizeof(localhost);
897*a466cc55SCy Schubert 	evutil_socket_t fake_listener = -1;
8982b15cb3dSCy Schubert 	int r;
8992b15cb3dSCy Schubert 
9002b15cb3dSCy Schubert 	test_ok = 0;
9012b15cb3dSCy Schubert 
902*a466cc55SCy Schubert 	fake_listener = fake_listener_create(&localhost);
9032b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, -1,
9042b15cb3dSCy Schubert 		BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
9052b15cb3dSCy Schubert 	tt_assert(bev);
9062b15cb3dSCy Schubert 	bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
9072b15cb3dSCy Schubert 
908*a466cc55SCy Schubert 	r = bufferevent_socket_connect(bev, (struct sockaddr *)&localhost, slen);
9092b15cb3dSCy Schubert 	/* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
9102b15cb3dSCy Schubert 	 * detects the error immediately, which is not really wrong of it. */
9112b15cb3dSCy Schubert 	tt_want(r == 0 || r == -1);
9122b15cb3dSCy Schubert 
913*a466cc55SCy Schubert 	/* Close the listener socket after a delay. This should trigger
9142b15cb3dSCy Schubert 	   "connection refused" on some other platforms, including OSX. */
9152b15cb3dSCy Schubert 	evtimer_assign(&close_listener_event, data->base, close_socket_cb,
9162b15cb3dSCy Schubert 	    &fake_listener);
917*a466cc55SCy Schubert 	event_add(&close_listener_event, &close_timeout);
9182b15cb3dSCy Schubert 	close_listener_event_added = 1;
9192b15cb3dSCy Schubert 
9202b15cb3dSCy Schubert 	event_base_dispatch(data->base);
9212b15cb3dSCy Schubert 
9222b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
9232b15cb3dSCy Schubert 
9242b15cb3dSCy Schubert end:
9252b15cb3dSCy Schubert 	if (fake_listener >= 0)
9262b15cb3dSCy Schubert 		evutil_closesocket(fake_listener);
9272b15cb3dSCy Schubert 
9282b15cb3dSCy Schubert 	if (bev)
9292b15cb3dSCy Schubert 		bufferevent_free(bev);
9302b15cb3dSCy Schubert 
9312b15cb3dSCy Schubert 	if (close_listener_event_added)
9322b15cb3dSCy Schubert 		event_del(&close_listener_event);
9332b15cb3dSCy Schubert }
9342b15cb3dSCy Schubert 
9352b15cb3dSCy Schubert struct timeout_cb_result {
9362b15cb3dSCy Schubert 	struct timeval read_timeout_at;
9372b15cb3dSCy Schubert 	struct timeval write_timeout_at;
9382b15cb3dSCy Schubert 	struct timeval last_wrote_at;
939*a466cc55SCy Schubert 	struct timeval last_read_at;
9402b15cb3dSCy Schubert 	int n_read_timeouts;
9412b15cb3dSCy Schubert 	int n_write_timeouts;
9422b15cb3dSCy Schubert 	int total_calls;
9432b15cb3dSCy Schubert };
9442b15cb3dSCy Schubert 
9452b15cb3dSCy Schubert static void
bev_timeout_read_cb(struct bufferevent * bev,void * arg)946*a466cc55SCy Schubert bev_timeout_read_cb(struct bufferevent *bev, void *arg)
947*a466cc55SCy Schubert {
948*a466cc55SCy Schubert 	struct timeout_cb_result *res = arg;
949*a466cc55SCy Schubert 	evutil_gettimeofday(&res->last_read_at, NULL);
950*a466cc55SCy Schubert }
951*a466cc55SCy Schubert static void
bev_timeout_write_cb(struct bufferevent * bev,void * arg)9522b15cb3dSCy Schubert bev_timeout_write_cb(struct bufferevent *bev, void *arg)
9532b15cb3dSCy Schubert {
9542b15cb3dSCy Schubert 	struct timeout_cb_result *res = arg;
9552b15cb3dSCy Schubert 	evutil_gettimeofday(&res->last_wrote_at, NULL);
9562b15cb3dSCy Schubert }
9572b15cb3dSCy Schubert static void
bev_timeout_event_cb(struct bufferevent * bev,short what,void * arg)9582b15cb3dSCy Schubert bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
9592b15cb3dSCy Schubert {
9602b15cb3dSCy Schubert 	struct timeout_cb_result *res = arg;
9612b15cb3dSCy Schubert 	++res->total_calls;
9622b15cb3dSCy Schubert 
9632b15cb3dSCy Schubert 	if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT))
9642b15cb3dSCy Schubert 	    == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) {
9652b15cb3dSCy Schubert 		evutil_gettimeofday(&res->read_timeout_at, NULL);
9662b15cb3dSCy Schubert 		++res->n_read_timeouts;
9672b15cb3dSCy Schubert 	}
9682b15cb3dSCy Schubert 	if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT))
9692b15cb3dSCy Schubert 	    == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) {
9702b15cb3dSCy Schubert 		evutil_gettimeofday(&res->write_timeout_at, NULL);
9712b15cb3dSCy Schubert 		++res->n_write_timeouts;
9722b15cb3dSCy Schubert 	}
9732b15cb3dSCy Schubert }
9742b15cb3dSCy Schubert 
9752b15cb3dSCy Schubert static void
test_bufferevent_timeouts(void * arg)9762b15cb3dSCy Schubert test_bufferevent_timeouts(void *arg)
9772b15cb3dSCy Schubert {
9782b15cb3dSCy Schubert 	/* "arg" is a string containing "pair" and/or "filter". */
9792b15cb3dSCy Schubert 	struct bufferevent *bev1 = NULL, *bev2 = NULL;
9802b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
9812b15cb3dSCy Schubert 	int use_pair = 0, use_filter = 0;
9822b15cb3dSCy Schubert 	struct timeval tv_w, tv_r, started_at;
9832b15cb3dSCy Schubert 	struct timeout_cb_result res1, res2;
9842b15cb3dSCy Schubert 
9852b15cb3dSCy Schubert 	memset(&res1, 0, sizeof(res1));
9862b15cb3dSCy Schubert 	memset(&res2, 0, sizeof(res2));
9872b15cb3dSCy Schubert 
9882b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "pair"))
9892b15cb3dSCy Schubert 		use_pair = 1;
9902b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "filter"))
9912b15cb3dSCy Schubert 		use_filter = 1;
9922b15cb3dSCy Schubert 
9932b15cb3dSCy Schubert 	if (use_pair) {
9942b15cb3dSCy Schubert 		struct bufferevent *p[2];
9952b15cb3dSCy Schubert 		tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p));
9962b15cb3dSCy Schubert 		bev1 = p[0];
9972b15cb3dSCy Schubert 		bev2 = p[1];
9982b15cb3dSCy Schubert 	} else {
9992b15cb3dSCy Schubert 		bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
10002b15cb3dSCy Schubert 		bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
10012b15cb3dSCy Schubert 	}
10022b15cb3dSCy Schubert 	tt_assert(bev1);
10032b15cb3dSCy Schubert 	tt_assert(bev2);
10042b15cb3dSCy Schubert 
10052b15cb3dSCy Schubert 	if (use_filter) {
10062b15cb3dSCy Schubert 		struct bufferevent *bevf1, *bevf2;
10072b15cb3dSCy Schubert 		bevf1 = bufferevent_filter_new(bev1, NULL, NULL,
10082b15cb3dSCy Schubert 		    BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
10092b15cb3dSCy Schubert 		bevf2 = bufferevent_filter_new(bev2, NULL, NULL,
10102b15cb3dSCy Schubert 		    BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
10112b15cb3dSCy Schubert 		tt_assert(bevf1);
10122b15cb3dSCy Schubert 		tt_assert(bevf2);
10132b15cb3dSCy Schubert 		bev1 = bevf1;
10142b15cb3dSCy Schubert 		bev2 = bevf2;
10152b15cb3dSCy Schubert 	}
10162b15cb3dSCy Schubert 
10172b15cb3dSCy Schubert 	/* Do this nice and early. */
10182b15cb3dSCy Schubert 	bufferevent_disable(bev2, EV_READ);
10192b15cb3dSCy Schubert 
10202b15cb3dSCy Schubert 	/* bev1 will try to write and read.  Both will time out. */
10212b15cb3dSCy Schubert 	evutil_gettimeofday(&started_at, NULL);
10222b15cb3dSCy Schubert 	tv_w.tv_sec = tv_r.tv_sec = 0;
10232b15cb3dSCy Schubert 	tv_w.tv_usec = 100*1000;
10242b15cb3dSCy Schubert 	tv_r.tv_usec = 150*1000;
1025*a466cc55SCy Schubert 	bufferevent_setcb(bev1, bev_timeout_read_cb, bev_timeout_write_cb,
10262b15cb3dSCy Schubert 	    bev_timeout_event_cb, &res1);
10272b15cb3dSCy Schubert 	bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
10282b15cb3dSCy Schubert 	bufferevent_write(bev1, "ABCDEFG", 7);
10292b15cb3dSCy Schubert 	bufferevent_enable(bev1, EV_READ|EV_WRITE);
10302b15cb3dSCy Schubert 
10312b15cb3dSCy Schubert 	/* bev2 has nothing to say, and isn't listening. */
1032*a466cc55SCy Schubert 	bufferevent_setcb(bev2, bev_timeout_read_cb, bev_timeout_write_cb,
10332b15cb3dSCy Schubert 	    bev_timeout_event_cb, &res2);
10342b15cb3dSCy Schubert 	tv_w.tv_sec = tv_r.tv_sec = 0;
10352b15cb3dSCy Schubert 	tv_w.tv_usec = 200*1000;
10362b15cb3dSCy Schubert 	tv_r.tv_usec = 100*1000;
10372b15cb3dSCy Schubert 	bufferevent_set_timeouts(bev2, &tv_r, &tv_w);
10382b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_WRITE);
10392b15cb3dSCy Schubert 
10402b15cb3dSCy Schubert 	tv_r.tv_sec = 0;
10412b15cb3dSCy Schubert 	tv_r.tv_usec = 350000;
10422b15cb3dSCy Schubert 
10432b15cb3dSCy Schubert 	event_base_loopexit(data->base, &tv_r);
10442b15cb3dSCy Schubert 	event_base_dispatch(data->base);
10452b15cb3dSCy Schubert 
10462b15cb3dSCy Schubert 	/* XXXX Test that actually reading or writing a little resets the
10472b15cb3dSCy Schubert 	 * timeouts. */
10482b15cb3dSCy Schubert 
1049*a466cc55SCy Schubert 	tt_want(res1.total_calls == 2);
10502b15cb3dSCy Schubert 	tt_want(res1.n_read_timeouts == 1);
10512b15cb3dSCy Schubert 	tt_want(res1.n_write_timeouts == 1);
1052*a466cc55SCy Schubert 	tt_want(res2.total_calls == !(use_pair && !use_filter));
1053*a466cc55SCy Schubert 	tt_want(res2.n_write_timeouts == !(use_pair && !use_filter));
1054*a466cc55SCy Schubert 	tt_want(!res2.n_read_timeouts);
10552b15cb3dSCy Schubert 
10562b15cb3dSCy Schubert 	test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
10572b15cb3dSCy Schubert 	test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
10582b15cb3dSCy Schubert 
1059*a466cc55SCy Schubert #define tt_assert_timeval_empty(tv) do {  \
1060*a466cc55SCy Schubert 	tt_int_op((tv).tv_sec, ==, 0);   \
1061*a466cc55SCy Schubert 	tt_int_op((tv).tv_usec, ==, 0);  \
1062*a466cc55SCy Schubert } while(0)
1063*a466cc55SCy Schubert 	tt_assert_timeval_empty(res1.last_read_at);
1064*a466cc55SCy Schubert 	tt_assert_timeval_empty(res2.last_read_at);
1065*a466cc55SCy Schubert 	tt_assert_timeval_empty(res2.last_wrote_at);
1066*a466cc55SCy Schubert 	tt_assert_timeval_empty(res2.last_wrote_at);
1067*a466cc55SCy Schubert #undef tt_assert_timeval_empty
1068*a466cc55SCy Schubert 
10692b15cb3dSCy Schubert end:
10702b15cb3dSCy Schubert 	if (bev1)
10712b15cb3dSCy Schubert 		bufferevent_free(bev1);
10722b15cb3dSCy Schubert 	if (bev2)
10732b15cb3dSCy Schubert 		bufferevent_free(bev2);
10742b15cb3dSCy Schubert }
10752b15cb3dSCy Schubert 
10762b15cb3dSCy Schubert static void
trigger_failure_cb(evutil_socket_t fd,short what,void * ctx)10772b15cb3dSCy Schubert trigger_failure_cb(evutil_socket_t fd, short what, void *ctx)
10782b15cb3dSCy Schubert {
10792b15cb3dSCy Schubert 	TT_FAIL(("The triggered callback did not fire or the machine is really slow (try increasing timeout)."));
10802b15cb3dSCy Schubert }
10812b15cb3dSCy Schubert 
10822b15cb3dSCy Schubert static void
trigger_eventcb(struct bufferevent * bev,short what,void * ctx)10832b15cb3dSCy Schubert trigger_eventcb(struct bufferevent *bev, short what, void *ctx)
10842b15cb3dSCy Schubert {
10852b15cb3dSCy Schubert 	struct event_base *base = ctx;
10862b15cb3dSCy Schubert 	if (what == ~0) {
10872b15cb3dSCy Schubert 		TT_BLATHER(("Event successfully triggered."));
10882b15cb3dSCy Schubert 		event_base_loopexit(base, NULL);
10892b15cb3dSCy Schubert 		return;
10902b15cb3dSCy Schubert 	}
10912b15cb3dSCy Schubert 	reader_eventcb(bev, what, ctx);
10922b15cb3dSCy Schubert }
10932b15cb3dSCy Schubert 
10942b15cb3dSCy Schubert static void
trigger_readcb_triggered(struct bufferevent * bev,void * ctx)10952b15cb3dSCy Schubert trigger_readcb_triggered(struct bufferevent *bev, void *ctx)
10962b15cb3dSCy Schubert {
10972b15cb3dSCy Schubert 	TT_BLATHER(("Read successfully triggered."));
10982b15cb3dSCy Schubert 	n_reads_invoked++;
10992b15cb3dSCy Schubert 	bufferevent_trigger_event(bev, ~0, bufferevent_trigger_test_flags);
11002b15cb3dSCy Schubert }
11012b15cb3dSCy Schubert 
11022b15cb3dSCy Schubert static void
trigger_readcb(struct bufferevent * bev,void * ctx)11032b15cb3dSCy Schubert trigger_readcb(struct bufferevent *bev, void *ctx)
11042b15cb3dSCy Schubert {
11052b15cb3dSCy Schubert 	struct timeval timeout = { 30, 0 };
11062b15cb3dSCy Schubert 	struct event_base *base = ctx;
11072b15cb3dSCy Schubert 	size_t low, high, len;
11082b15cb3dSCy Schubert 	int expected_reads;
11092b15cb3dSCy Schubert 
11102b15cb3dSCy Schubert 	TT_BLATHER(("Read invoked on %d.", (int)bufferevent_getfd(bev)));
11112b15cb3dSCy Schubert 	expected_reads = ++n_reads_invoked;
11122b15cb3dSCy Schubert 
11132b15cb3dSCy Schubert 	bufferevent_setcb(bev, trigger_readcb_triggered, NULL, trigger_eventcb, ctx);
11142b15cb3dSCy Schubert 
11152b15cb3dSCy Schubert 	bufferevent_getwatermark(bev, EV_READ, &low, &high);
11162b15cb3dSCy Schubert 	len = evbuffer_get_length(bufferevent_get_input(bev));
11172b15cb3dSCy Schubert 
11182b15cb3dSCy Schubert 	bufferevent_setwatermark(bev, EV_READ, len + 1, 0);
11192b15cb3dSCy Schubert 	bufferevent_trigger(bev, EV_READ, bufferevent_trigger_test_flags);
11202b15cb3dSCy Schubert 	/* no callback expected */
11212b15cb3dSCy Schubert 	tt_int_op(n_reads_invoked, ==, expected_reads);
11222b15cb3dSCy Schubert 
11232b15cb3dSCy Schubert 	if ((bufferevent_trigger_test_flags & BEV_TRIG_DEFER_CALLBACKS) ||
11242b15cb3dSCy Schubert 	    (bufferevent_connect_test_flags & BEV_OPT_DEFER_CALLBACKS)) {
11252b15cb3dSCy Schubert 		/* will be deferred */
11262b15cb3dSCy Schubert 	} else {
11272b15cb3dSCy Schubert 		expected_reads++;
11282b15cb3dSCy Schubert 	}
11292b15cb3dSCy Schubert 
11302b15cb3dSCy Schubert 	event_base_once(base, -1, EV_TIMEOUT, trigger_failure_cb, NULL, &timeout);
11312b15cb3dSCy Schubert 
11322b15cb3dSCy Schubert 	bufferevent_trigger(bev, EV_READ,
11332b15cb3dSCy Schubert 	    bufferevent_trigger_test_flags | BEV_TRIG_IGNORE_WATERMARKS);
11342b15cb3dSCy Schubert 	tt_int_op(n_reads_invoked, ==, expected_reads);
11352b15cb3dSCy Schubert 
11362b15cb3dSCy Schubert 	bufferevent_setwatermark(bev, EV_READ, low, high);
11372b15cb3dSCy Schubert end:
11382b15cb3dSCy Schubert 	;
11392b15cb3dSCy Schubert }
11402b15cb3dSCy Schubert 
11412b15cb3dSCy Schubert static void
test_bufferevent_trigger(void * arg)11422b15cb3dSCy Schubert test_bufferevent_trigger(void *arg)
11432b15cb3dSCy Schubert {
11442b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
11452b15cb3dSCy Schubert 	struct evconnlistener *lev=NULL;
11462b15cb3dSCy Schubert 	struct bufferevent *bev=NULL;
11472b15cb3dSCy Schubert 	struct sockaddr_in localhost;
11482b15cb3dSCy Schubert 	struct sockaddr_storage ss;
11492b15cb3dSCy Schubert 	struct sockaddr *sa;
11502b15cb3dSCy Schubert 	ev_socklen_t slen;
11512b15cb3dSCy Schubert 
11522b15cb3dSCy Schubert 	int be_flags=BEV_OPT_CLOSE_ON_FREE;
11532b15cb3dSCy Schubert 	int trig_flags=0;
11542b15cb3dSCy Schubert 
11552b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "defer")) {
11562b15cb3dSCy Schubert 		be_flags |= BEV_OPT_DEFER_CALLBACKS;
11572b15cb3dSCy Schubert 	}
11582b15cb3dSCy Schubert 	bufferevent_connect_test_flags = be_flags;
11592b15cb3dSCy Schubert 
11602b15cb3dSCy Schubert 	if (strstr((char*)data->setup_data, "postpone")) {
11612b15cb3dSCy Schubert 		trig_flags |= BEV_TRIG_DEFER_CALLBACKS;
11622b15cb3dSCy Schubert 	}
11632b15cb3dSCy Schubert 	bufferevent_trigger_test_flags = trig_flags;
11642b15cb3dSCy Schubert 
11652b15cb3dSCy Schubert 	memset(&localhost, 0, sizeof(localhost));
11662b15cb3dSCy Schubert 
11672b15cb3dSCy Schubert 	localhost.sin_port = 0; /* pick-a-port */
11682b15cb3dSCy Schubert 	localhost.sin_addr.s_addr = htonl(0x7f000001L);
11692b15cb3dSCy Schubert 	localhost.sin_family = AF_INET;
11702b15cb3dSCy Schubert 	sa = (struct sockaddr *)&localhost;
11712b15cb3dSCy Schubert 	lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
11722b15cb3dSCy Schubert 	    LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
11732b15cb3dSCy Schubert 	    16, sa, sizeof(localhost));
11742b15cb3dSCy Schubert 	tt_assert(lev);
11752b15cb3dSCy Schubert 
11762b15cb3dSCy Schubert 	sa = (struct sockaddr *)&ss;
11772b15cb3dSCy Schubert 	slen = sizeof(ss);
11782b15cb3dSCy Schubert 	if (regress_get_listener_addr(lev, sa, &slen) < 0) {
11792b15cb3dSCy Schubert 		tt_abort_perror("getsockname");
11802b15cb3dSCy Schubert 	}
11812b15cb3dSCy Schubert 
11822b15cb3dSCy Schubert 	tt_assert(!evconnlistener_enable(lev));
11832b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, -1, be_flags);
11842b15cb3dSCy Schubert 	tt_assert(bev);
11852b15cb3dSCy Schubert 	bufferevent_setcb(bev, trigger_readcb, NULL, trigger_eventcb, data->base);
11862b15cb3dSCy Schubert 
11872b15cb3dSCy Schubert 	bufferevent_enable(bev, EV_READ);
11882b15cb3dSCy Schubert 
11892b15cb3dSCy Schubert 	tt_want(!bufferevent_socket_connect(bev, sa, sizeof(localhost)));
11902b15cb3dSCy Schubert 
11912b15cb3dSCy Schubert 	event_base_dispatch(data->base);
11922b15cb3dSCy Schubert 
11932b15cb3dSCy Schubert 	tt_int_op(n_reads_invoked, ==, 2);
11942b15cb3dSCy Schubert end:
11952b15cb3dSCy Schubert 	if (lev)
11962b15cb3dSCy Schubert 		evconnlistener_free(lev);
11972b15cb3dSCy Schubert 
11982b15cb3dSCy Schubert 	if (bev)
11992b15cb3dSCy Schubert 		bufferevent_free(bev);
12002b15cb3dSCy Schubert }
12012b15cb3dSCy Schubert 
1202*a466cc55SCy Schubert static void
test_bufferevent_socket_filter_inactive(void * arg)1203*a466cc55SCy Schubert test_bufferevent_socket_filter_inactive(void *arg)
1204*a466cc55SCy Schubert {
1205*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
1206*a466cc55SCy Schubert 	struct bufferevent *bev = NULL, *bevf = NULL;
1207*a466cc55SCy Schubert 
1208*a466cc55SCy Schubert 	bev = bufferevent_socket_new(data->base, -1, 0);
1209*a466cc55SCy Schubert 	tt_assert(bev);
1210*a466cc55SCy Schubert 	bevf = bufferevent_filter_new(bev, NULL, NULL, 0, NULL, NULL);
1211*a466cc55SCy Schubert 	tt_assert(bevf);
1212*a466cc55SCy Schubert 
1213*a466cc55SCy Schubert end:
1214*a466cc55SCy Schubert 	if (bevf)
1215*a466cc55SCy Schubert 		bufferevent_free(bevf);
1216*a466cc55SCy Schubert 	if (bev)
1217*a466cc55SCy Schubert 		bufferevent_free(bev);
1218*a466cc55SCy Schubert }
1219*a466cc55SCy Schubert 
1220*a466cc55SCy Schubert static void
pair_flush_eventcb(struct bufferevent * bev,short what,void * ctx)1221*a466cc55SCy Schubert pair_flush_eventcb(struct bufferevent *bev, short what, void *ctx)
1222*a466cc55SCy Schubert {
1223*a466cc55SCy Schubert 	int *callback_what = ctx;
1224*a466cc55SCy Schubert 	*callback_what = what;
1225*a466cc55SCy Schubert }
1226*a466cc55SCy Schubert 
1227*a466cc55SCy Schubert static void
test_bufferevent_pair_flush(void * arg)1228*a466cc55SCy Schubert test_bufferevent_pair_flush(void *arg)
1229*a466cc55SCy Schubert {
1230*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
1231*a466cc55SCy Schubert 	struct bufferevent *pair[2];
1232*a466cc55SCy Schubert 	struct bufferevent *bev1 = NULL;
1233*a466cc55SCy Schubert 	struct bufferevent *bev2 = NULL;
1234*a466cc55SCy Schubert 	int callback_what = 0;
1235*a466cc55SCy Schubert 
1236*a466cc55SCy Schubert 	tt_assert(0 == bufferevent_pair_new(data->base, 0, pair));
1237*a466cc55SCy Schubert 	bev1 = pair[0];
1238*a466cc55SCy Schubert 	bev2 = pair[1];
1239*a466cc55SCy Schubert 	tt_assert(0 == bufferevent_enable(bev1, EV_WRITE));
1240*a466cc55SCy Schubert 	tt_assert(0 == bufferevent_enable(bev2, EV_READ));
1241*a466cc55SCy Schubert 
1242*a466cc55SCy Schubert 	bufferevent_setcb(bev2, NULL, NULL, pair_flush_eventcb, &callback_what);
1243*a466cc55SCy Schubert 
1244*a466cc55SCy Schubert 	bufferevent_flush(bev1, EV_WRITE, BEV_FINISHED);
1245*a466cc55SCy Schubert 
1246*a466cc55SCy Schubert 	event_base_loop(data->base, EVLOOP_ONCE);
1247*a466cc55SCy Schubert 
1248*a466cc55SCy Schubert 	tt_assert(callback_what == (BEV_EVENT_READING | BEV_EVENT_EOF));
1249*a466cc55SCy Schubert 
1250*a466cc55SCy Schubert end:
1251*a466cc55SCy Schubert 	if (bev1)
1252*a466cc55SCy Schubert 		bufferevent_free(bev1);
1253*a466cc55SCy Schubert 	if (bev2)
1254*a466cc55SCy Schubert 		bufferevent_free(bev2);
1255*a466cc55SCy Schubert }
1256*a466cc55SCy Schubert 
1257*a466cc55SCy Schubert struct bufferevent_filter_data_stuck {
1258*a466cc55SCy Schubert 	size_t header_size;
1259*a466cc55SCy Schubert 	size_t total_read;
1260*a466cc55SCy Schubert };
1261*a466cc55SCy Schubert 
1262*a466cc55SCy Schubert static void
bufferevent_filter_data_stuck_readcb(struct bufferevent * bev,void * arg)1263*a466cc55SCy Schubert bufferevent_filter_data_stuck_readcb(struct bufferevent *bev, void *arg)
1264*a466cc55SCy Schubert {
1265*a466cc55SCy Schubert 	struct bufferevent_filter_data_stuck *filter_data = arg;
1266*a466cc55SCy Schubert 	struct evbuffer *input = bufferevent_get_input(bev);
1267*a466cc55SCy Schubert 	size_t read_size = evbuffer_get_length(input);
1268*a466cc55SCy Schubert 	evbuffer_drain(input, read_size);
1269*a466cc55SCy Schubert 	filter_data->total_read += read_size;
1270*a466cc55SCy Schubert }
1271*a466cc55SCy Schubert 
1272*a466cc55SCy Schubert /**
1273*a466cc55SCy Schubert  * This filter prepends header once before forwarding data.
1274*a466cc55SCy Schubert  */
1275*a466cc55SCy Schubert static enum bufferevent_filter_result
bufferevent_filter_data_stuck_inputcb(struct evbuffer * src,struct evbuffer * dst,ev_ssize_t dst_limit,enum bufferevent_flush_mode mode,void * ctx)1276*a466cc55SCy Schubert bufferevent_filter_data_stuck_inputcb(
1277*a466cc55SCy Schubert     struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,
1278*a466cc55SCy Schubert     enum bufferevent_flush_mode mode, void *ctx)
1279*a466cc55SCy Schubert {
1280*a466cc55SCy Schubert 	struct bufferevent_filter_data_stuck *filter_data = ctx;
1281*a466cc55SCy Schubert 	static int header_inserted = 0;
1282*a466cc55SCy Schubert 	size_t payload_size;
1283*a466cc55SCy Schubert 	size_t header_size = 0;
1284*a466cc55SCy Schubert 
1285*a466cc55SCy Schubert 	if (!header_inserted) {
1286*a466cc55SCy Schubert 		char *header = calloc(filter_data->header_size, 1);
1287*a466cc55SCy Schubert 		evbuffer_add(dst, header, filter_data->header_size);
1288*a466cc55SCy Schubert 		free(header);
1289*a466cc55SCy Schubert 		header_size = filter_data->header_size;
1290*a466cc55SCy Schubert 		header_inserted = 1;
1291*a466cc55SCy Schubert 	}
1292*a466cc55SCy Schubert 
1293*a466cc55SCy Schubert 	payload_size = evbuffer_get_length(src);
1294*a466cc55SCy Schubert 	if (payload_size > dst_limit - header_size) {
1295*a466cc55SCy Schubert 		payload_size = dst_limit - header_size;
1296*a466cc55SCy Schubert 	}
1297*a466cc55SCy Schubert 
1298*a466cc55SCy Schubert 	tt_int_op(payload_size, ==, evbuffer_remove_buffer(src, dst, payload_size));
1299*a466cc55SCy Schubert 
1300*a466cc55SCy Schubert end:
1301*a466cc55SCy Schubert 	return BEV_OK;
1302*a466cc55SCy Schubert }
1303*a466cc55SCy Schubert 
1304*a466cc55SCy Schubert static void
test_bufferevent_filter_data_stuck(void * arg)1305*a466cc55SCy Schubert test_bufferevent_filter_data_stuck(void *arg)
1306*a466cc55SCy Schubert {
1307*a466cc55SCy Schubert 	const size_t read_high_wm = 4096;
1308*a466cc55SCy Schubert 	struct bufferevent_filter_data_stuck filter_data;
1309*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
1310*a466cc55SCy Schubert 	struct bufferevent *pair[2];
1311*a466cc55SCy Schubert 	struct bufferevent *filter = NULL;
1312*a466cc55SCy Schubert 
1313*a466cc55SCy Schubert 	int options = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS;
1314*a466cc55SCy Schubert 
1315*a466cc55SCy Schubert 	char payload[4096];
1316*a466cc55SCy Schubert 	int payload_size = sizeof(payload);
1317*a466cc55SCy Schubert 
1318*a466cc55SCy Schubert 	memset(&filter_data, 0, sizeof(filter_data));
1319*a466cc55SCy Schubert 	filter_data.header_size = 20;
1320*a466cc55SCy Schubert 
1321*a466cc55SCy Schubert 	tt_assert(bufferevent_pair_new(data->base, options, pair) == 0);
1322*a466cc55SCy Schubert 
1323*a466cc55SCy Schubert 	bufferevent_setwatermark(pair[0], EV_READ, 0, read_high_wm);
1324*a466cc55SCy Schubert 	bufferevent_setwatermark(pair[1], EV_READ, 0, read_high_wm);
1325*a466cc55SCy Schubert 
1326*a466cc55SCy Schubert 	tt_assert(
1327*a466cc55SCy Schubert 		filter =
1328*a466cc55SCy Schubert 		 bufferevent_filter_new(pair[1],
1329*a466cc55SCy Schubert 		 bufferevent_filter_data_stuck_inputcb,
1330*a466cc55SCy Schubert 		 NULL,
1331*a466cc55SCy Schubert 		 options,
1332*a466cc55SCy Schubert 		 NULL,
1333*a466cc55SCy Schubert 		 &filter_data));
1334*a466cc55SCy Schubert 
1335*a466cc55SCy Schubert 	bufferevent_setcb(filter,
1336*a466cc55SCy Schubert 		bufferevent_filter_data_stuck_readcb,
1337*a466cc55SCy Schubert 		NULL,
1338*a466cc55SCy Schubert 		NULL,
1339*a466cc55SCy Schubert 		&filter_data);
1340*a466cc55SCy Schubert 
1341*a466cc55SCy Schubert 	tt_assert(bufferevent_enable(filter, EV_READ|EV_WRITE) == 0);
1342*a466cc55SCy Schubert 
1343*a466cc55SCy Schubert 	bufferevent_setwatermark(filter, EV_READ, 0, read_high_wm);
1344*a466cc55SCy Schubert 
1345*a466cc55SCy Schubert 	tt_assert(bufferevent_write(pair[0], payload, sizeof(payload)) == 0);
1346*a466cc55SCy Schubert 
1347*a466cc55SCy Schubert 	event_base_dispatch(data->base);
1348*a466cc55SCy Schubert 
1349*a466cc55SCy Schubert 	tt_int_op(filter_data.total_read, ==, payload_size + filter_data.header_size);
1350*a466cc55SCy Schubert end:
1351*a466cc55SCy Schubert 	if (pair[0])
1352*a466cc55SCy Schubert 		bufferevent_free(pair[0]);
1353*a466cc55SCy Schubert 	if (filter)
1354*a466cc55SCy Schubert 		bufferevent_free(filter);
1355*a466cc55SCy Schubert }
1356*a466cc55SCy Schubert 
13572b15cb3dSCy Schubert struct testcase_t bufferevent_testcases[] = {
13582b15cb3dSCy Schubert 
13592b15cb3dSCy Schubert 	LEGACY(bufferevent, TT_ISOLATED),
13602b15cb3dSCy Schubert 	LEGACY(bufferevent_pair, TT_ISOLATED),
1361*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_normal, TT_ISOLATED),
1362*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_flush, TT_ISOLATED),
1363*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_finished, TT_ISOLATED),
1364*a466cc55SCy Schubert 	LEGACY(bufferevent_pair_flush_normal, TT_ISOLATED),
1365*a466cc55SCy Schubert 	LEGACY(bufferevent_pair_flush_flush, TT_ISOLATED),
1366*a466cc55SCy Schubert 	LEGACY(bufferevent_pair_flush_finished, TT_ISOLATED),
1367*a466cc55SCy Schubert #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) && !defined(__SANITIZE_ADDRESS__)
1368a25439b6SCy Schubert 	{ "bufferevent_pair_release_lock", test_bufferevent_pair_release_lock,
1369*a466cc55SCy Schubert 	  TT_FORK|TT_ISOLATED|TT_NEED_THREADS|TT_NEED_BASE|TT_LEGACY|TT_NO_LOGS,
1370a25439b6SCy Schubert 	  &basic_setup, NULL },
1371a25439b6SCy Schubert #endif
13722b15cb3dSCy Schubert 	LEGACY(bufferevent_watermarks, TT_ISOLATED),
13732b15cb3dSCy Schubert 	LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
13742b15cb3dSCy Schubert 	LEGACY(bufferevent_filters, TT_ISOLATED),
13752b15cb3dSCy Schubert 	LEGACY(bufferevent_pair_filters, TT_ISOLATED),
1376*a466cc55SCy Schubert 	LEGACY(bufferevent_filters_disable, TT_ISOLATED),
1377*a466cc55SCy Schubert 	LEGACY(bufferevent_pair_filters_disable, TT_ISOLATED),
13782b15cb3dSCy Schubert 	{ "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
13792b15cb3dSCy Schubert 	  &basic_setup, (void*)"" },
13802b15cb3dSCy Schubert 	{ "bufferevent_connect_defer", test_bufferevent_connect,
13812b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
13822b15cb3dSCy Schubert 	{ "bufferevent_connect_lock", test_bufferevent_connect,
13832b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" },
13842b15cb3dSCy Schubert 	{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
13852b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
13862b15cb3dSCy Schubert 	  (void*)"defer lock" },
13872b15cb3dSCy Schubert 	{ "bufferevent_connect_unlocked_cbs", test_bufferevent_connect,
13882b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
13892b15cb3dSCy Schubert 	  (void*)"lock defer unlocked" },
13902b15cb3dSCy Schubert 	{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
13912b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
13922b15cb3dSCy Schubert 	{ "bufferevent_timeout", test_bufferevent_timeouts,
1393*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"" },
13942b15cb3dSCy Schubert 	{ "bufferevent_timeout_pair", test_bufferevent_timeouts,
13952b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
13962b15cb3dSCy Schubert 	{ "bufferevent_timeout_filter", test_bufferevent_timeouts,
13972b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
13982b15cb3dSCy Schubert 	{ "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
13992b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
14002b15cb3dSCy Schubert 	{ "bufferevent_trigger", test_bufferevent_trigger, TT_FORK|TT_NEED_BASE,
14012b15cb3dSCy Schubert 	  &basic_setup, (void*)"" },
14022b15cb3dSCy Schubert 	{ "bufferevent_trigger_defer", test_bufferevent_trigger,
14032b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
14042b15cb3dSCy Schubert 	{ "bufferevent_trigger_postpone", test_bufferevent_trigger,
14052b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
14062b15cb3dSCy Schubert 	  (void*)"postpone" },
14072b15cb3dSCy Schubert 	{ "bufferevent_trigger_defer_postpone", test_bufferevent_trigger,
14082b15cb3dSCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
14092b15cb3dSCy Schubert 	  (void*)"defer postpone" },
14102b15cb3dSCy Schubert #ifdef EVENT__HAVE_LIBZ
14112b15cb3dSCy Schubert 	LEGACY(bufferevent_zlib, TT_ISOLATED),
14122b15cb3dSCy Schubert #else
14132b15cb3dSCy Schubert 	{ "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
14142b15cb3dSCy Schubert #endif
14152b15cb3dSCy Schubert 
1416*a466cc55SCy Schubert 	{ "bufferevent_connect_fail_eventcb_defer",
1417*a466cc55SCy Schubert 	  test_bufferevent_connect_fail_eventcb,
1418*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS },
1419*a466cc55SCy Schubert 	{ "bufferevent_connect_fail_eventcb",
1420*a466cc55SCy Schubert 	  test_bufferevent_connect_fail_eventcb,
1421*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
1422*a466cc55SCy Schubert 
1423*a466cc55SCy Schubert 	{ "bufferevent_socket_filter_inactive",
1424*a466cc55SCy Schubert 	  test_bufferevent_socket_filter_inactive,
1425*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
1426*a466cc55SCy Schubert 	{ "bufferevent_pair_flush",
1427*a466cc55SCy Schubert 	  test_bufferevent_pair_flush,
1428*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
1429*a466cc55SCy Schubert 	{ "bufferevent_filter_data_stuck",
1430*a466cc55SCy Schubert 	  test_bufferevent_filter_data_stuck,
1431*a466cc55SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
1432*a466cc55SCy Schubert 
14332b15cb3dSCy Schubert 	END_OF_TESTCASES,
14342b15cb3dSCy Schubert };
14352b15cb3dSCy Schubert 
1436*a466cc55SCy Schubert #define TT_IOCP (TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP)
1437*a466cc55SCy Schubert #define TT_IOCP_LEGACY (TT_ISOLATED|TT_ENABLE_IOCP)
14382b15cb3dSCy Schubert struct testcase_t bufferevent_iocp_testcases[] = {
1439*a466cc55SCy Schubert 	LEGACY(bufferevent, TT_IOCP_LEGACY),
1440*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_normal, TT_ISOLATED),
1441*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_flush, TT_ISOLATED),
1442*a466cc55SCy Schubert 	LEGACY(bufferevent_flush_finished, TT_ISOLATED),
1443*a466cc55SCy Schubert 	LEGACY(bufferevent_watermarks, TT_IOCP_LEGACY),
1444*a466cc55SCy Schubert 	LEGACY(bufferevent_filters, TT_IOCP_LEGACY),
1445*a466cc55SCy Schubert 	LEGACY(bufferevent_filters_disable, TT_IOCP_LEGACY),
14462b15cb3dSCy Schubert 
14472b15cb3dSCy Schubert 	{ "bufferevent_connect", test_bufferevent_connect,
1448*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)"" },
14492b15cb3dSCy Schubert 	{ "bufferevent_connect_defer", test_bufferevent_connect,
1450*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)"defer" },
14512b15cb3dSCy Schubert 	{ "bufferevent_connect_lock", test_bufferevent_connect,
1452*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)"lock" },
14532b15cb3dSCy Schubert 	{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
1454*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)"defer lock" },
14552b15cb3dSCy Schubert 	{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
1456*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, NULL },
14572b15cb3dSCy Schubert 	{ "bufferevent_connect_nonblocking", test_bufferevent_connect,
1458*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)"unset_connectex" },
1459*a466cc55SCy Schubert 
1460*a466cc55SCy Schubert 	{ "bufferevent_connect_fail_eventcb_defer",
1461*a466cc55SCy Schubert 	  test_bufferevent_connect_fail_eventcb,
1462*a466cc55SCy Schubert 	  TT_IOCP, &basic_setup, (void*)BEV_OPT_DEFER_CALLBACKS },
1463*a466cc55SCy Schubert 	{ "bufferevent_connect_fail_eventcb",
1464*a466cc55SCy Schubert 	  test_bufferevent_connect_fail_eventcb, TT_IOCP, &basic_setup, NULL },
14652b15cb3dSCy Schubert 
14662b15cb3dSCy Schubert 	END_OF_TESTCASES,
14672b15cb3dSCy Schubert };
1468