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