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