1/*
2 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* The old tests here need assertions to work. */
29#undef NDEBUG
30
31#ifdef WIN32
32#include <winsock2.h>
33#include <windows.h>
34#endif
35
36#include "event2/event-config.h"
37
38#include <sys/types.h>
39#include <sys/stat.h>
40#ifdef _EVENT_HAVE_SYS_TIME_H
41#include <sys/time.h>
42#endif
43#include <sys/queue.h>
44#ifndef WIN32
45#include <sys/socket.h>
46#include <sys/wait.h>
47#include <signal.h>
48#include <unistd.h>
49#include <netdb.h>
50#include <netinet/in.h>
51#endif
52#include <fcntl.h>
53#include <signal.h>
54#include <stdlib.h>
55#include <stdio.h>
56#include <string.h>
57#include <errno.h>
58#include <assert.h>
59
60#ifdef _EVENT_HAVE_ARPA_INET_H
61#include <arpa/inet.h>
62#endif
63
64#include "event2/event-config.h"
65#include "event2/event.h"
66#include "event2/event_struct.h"
67#include "event2/event_compat.h"
68#include "event2/tag.h"
69#include "event2/buffer.h"
70#include "event2/bufferevent.h"
71#include "event2/bufferevent_compat.h"
72#include "event2/bufferevent_struct.h"
73#include "event2/listener.h"
74#include "event2/util.h"
75
76#include "bufferevent-internal.h"
77#ifdef WIN32
78#include "iocp-internal.h"
79#endif
80
81#include "regress.h"
82#include "regress_testutils.h"
83
84/*
85 * simple bufferevent test
86 */
87
88static void
89readcb(struct bufferevent *bev, void *arg)
90{
91	if (evbuffer_get_length(bev->input) == 8333) {
92		struct evbuffer *evbuf = evbuffer_new();
93		assert(evbuf != NULL);
94
95		/* gratuitous test of bufferevent_read_buffer */
96		bufferevent_read_buffer(bev, evbuf);
97
98		bufferevent_disable(bev, EV_READ);
99
100		if (evbuffer_get_length(evbuf) == 8333) {
101			test_ok++;
102		}
103
104		evbuffer_free(evbuf);
105	}
106}
107
108static void
109writecb(struct bufferevent *bev, void *arg)
110{
111	if (evbuffer_get_length(bev->output) == 0) {
112		test_ok++;
113	}
114}
115
116static void
117errorcb(struct bufferevent *bev, short what, void *arg)
118{
119	test_ok = -2;
120}
121
122static void
123test_bufferevent_impl(int use_pair)
124{
125	struct bufferevent *bev1 = NULL, *bev2 = NULL;
126	char buffer[8333];
127	int i;
128
129	if (use_pair) {
130		struct bufferevent *pair[2];
131		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
132		bev1 = pair[0];
133		bev2 = pair[1];
134		bufferevent_setcb(bev1, readcb, writecb, errorcb, NULL);
135		bufferevent_setcb(bev2, readcb, writecb, errorcb, NULL);
136		tt_int_op(bufferevent_getfd(bev1), ==, -1);
137		tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
138		tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, bev2);
139		tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, bev1);
140	} else {
141		bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
142		bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
143		tt_int_op(bufferevent_getfd(bev1), ==, pair[0]);
144		tt_ptr_op(bufferevent_get_underlying(bev1), ==, NULL);
145		tt_ptr_op(bufferevent_pair_get_partner(bev1), ==, NULL);
146		tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
147	}
148
149	bufferevent_disable(bev1, EV_READ);
150	bufferevent_enable(bev2, EV_READ);
151
152	tt_int_op(bufferevent_get_enabled(bev1), ==, EV_WRITE);
153	tt_int_op(bufferevent_get_enabled(bev2), ==, EV_WRITE|EV_READ);
154
155	for (i = 0; i < (int)sizeof(buffer); i++)
156		buffer[i] = i;
157
158	bufferevent_write(bev1, buffer, sizeof(buffer));
159
160	event_dispatch();
161
162	bufferevent_free(bev1);
163	tt_ptr_op(bufferevent_pair_get_partner(bev2), ==, NULL);
164	bufferevent_free(bev2);
165
166	if (test_ok != 2)
167		test_ok = 0;
168end:
169	;
170}
171
172static void
173test_bufferevent(void)
174{
175	test_bufferevent_impl(0);
176}
177
178static void
179test_bufferevent_pair(void)
180{
181	test_bufferevent_impl(1);
182}
183
184/*
185 * test watermarks and bufferevent
186 */
187
188static void
189wm_readcb(struct bufferevent *bev, void *arg)
190{
191	struct evbuffer *evbuf = evbuffer_new();
192	int len = (int)evbuffer_get_length(bev->input);
193	static int nread;
194
195	assert(len >= 10 && len <= 20);
196
197	assert(evbuf != NULL);
198
199	/* gratuitous test of bufferevent_read_buffer */
200	bufferevent_read_buffer(bev, evbuf);
201
202	nread += len;
203	if (nread == 65000) {
204		bufferevent_disable(bev, EV_READ);
205		test_ok++;
206	}
207
208	evbuffer_free(evbuf);
209}
210
211static void
212wm_writecb(struct bufferevent *bev, void *arg)
213{
214	assert(evbuffer_get_length(bev->output) <= 100);
215	if (evbuffer_get_length(bev->output) == 0) {
216		evbuffer_drain(bev->output, evbuffer_get_length(bev->output));
217		test_ok++;
218	}
219}
220
221static void
222wm_errorcb(struct bufferevent *bev, short what, void *arg)
223{
224	test_ok = -2;
225}
226
227static void
228test_bufferevent_watermarks_impl(int use_pair)
229{
230	struct bufferevent *bev1 = NULL, *bev2 = NULL;
231	char buffer[65000];
232	int i;
233	test_ok = 0;
234
235	if (use_pair) {
236		struct bufferevent *pair[2];
237		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
238		bev1 = pair[0];
239		bev2 = pair[1];
240		bufferevent_setcb(bev1, NULL, wm_writecb, errorcb, NULL);
241		bufferevent_setcb(bev2, wm_readcb, NULL, errorcb, NULL);
242	} else {
243		bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
244		bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
245	}
246	tt_assert(bev1);
247	tt_assert(bev2);
248	bufferevent_disable(bev1, EV_READ);
249	bufferevent_enable(bev2, EV_READ);
250
251	for (i = 0; i < (int)sizeof(buffer); i++)
252		buffer[i] = (char)i;
253
254	/* limit the reading on the receiving bufferevent */
255	bufferevent_setwatermark(bev2, EV_READ, 10, 20);
256
257	/* Tell the sending bufferevent not to notify us till it's down to
258	   100 bytes. */
259	bufferevent_setwatermark(bev1, EV_WRITE, 100, 2000);
260
261	bufferevent_write(bev1, buffer, sizeof(buffer));
262
263	event_dispatch();
264
265	tt_int_op(test_ok, ==, 2);
266
267	/* The write callback drained all the data from outbuf, so we
268	 * should have removed the write event... */
269	tt_assert(!event_pending(&bev2->ev_write, EV_WRITE, NULL));
270
271end:
272	if (bev1)
273		bufferevent_free(bev1);
274	if (bev2)
275		bufferevent_free(bev2);
276}
277
278static void
279test_bufferevent_watermarks(void)
280{
281	test_bufferevent_watermarks_impl(0);
282}
283
284static void
285test_bufferevent_pair_watermarks(void)
286{
287	test_bufferevent_watermarks_impl(1);
288}
289
290/*
291 * Test bufferevent filters
292 */
293
294/* strip an 'x' from each byte */
295
296static enum bufferevent_filter_result
297bufferevent_input_filter(struct evbuffer *src, struct evbuffer *dst,
298    ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
299{
300	const unsigned char *buffer;
301	unsigned i;
302
303	buffer = evbuffer_pullup(src, evbuffer_get_length(src));
304	for (i = 0; i < evbuffer_get_length(src); i += 2) {
305		assert(buffer[i] == 'x');
306		evbuffer_add(dst, buffer + i + 1, 1);
307
308		if (i + 2 > evbuffer_get_length(src))
309			break;
310	}
311
312	evbuffer_drain(src, i);
313	return (BEV_OK);
314}
315
316/* add an 'x' before each byte */
317
318static enum bufferevent_filter_result
319bufferevent_output_filter(struct evbuffer *src, struct evbuffer *dst,
320    ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx)
321{
322	const unsigned char *buffer;
323	unsigned i;
324
325	buffer = evbuffer_pullup(src, evbuffer_get_length(src));
326	for (i = 0; i < evbuffer_get_length(src); ++i) {
327		evbuffer_add(dst, "x", 1);
328		evbuffer_add(dst, buffer + i, 1);
329	}
330
331	evbuffer_drain(src, evbuffer_get_length(src));
332	return (BEV_OK);
333}
334
335static void
336test_bufferevent_filters_impl(int use_pair)
337{
338	struct bufferevent *bev1 = NULL, *bev2 = NULL;
339	struct bufferevent *bev1_base = NULL, *bev2_base = NULL;
340	char buffer[8333];
341	int i;
342
343	test_ok = 0;
344
345	if (use_pair) {
346		struct bufferevent *pair[2];
347		tt_assert(0 == bufferevent_pair_new(NULL, 0, pair));
348		bev1 = pair[0];
349		bev2 = pair[1];
350	} else {
351		bev1 = bufferevent_socket_new(NULL, pair[0], 0);
352		bev2 = bufferevent_socket_new(NULL, pair[1], 0);
353	}
354	bev1_base = bev1;
355	bev2_base = bev2;
356
357	for (i = 0; i < (int)sizeof(buffer); i++)
358		buffer[i] = i;
359
360	bev1 = bufferevent_filter_new(bev1, NULL, bufferevent_output_filter,
361				      BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
362
363	bev2 = bufferevent_filter_new(bev2, bufferevent_input_filter,
364				      NULL, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
365	bufferevent_setcb(bev1, NULL, writecb, errorcb, NULL);
366	bufferevent_setcb(bev2, readcb, NULL, errorcb, NULL);
367
368	tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev1_base);
369	tt_ptr_op(bufferevent_get_underlying(bev2), ==, bev2_base);
370	tt_int_op(bufferevent_getfd(bev1), ==, -1);
371	tt_int_op(bufferevent_getfd(bev2), ==, -1);
372
373	bufferevent_disable(bev1, EV_READ);
374	bufferevent_enable(bev2, EV_READ);
375	/* insert some filters */
376	bufferevent_write(bev1, buffer, sizeof(buffer));
377
378	event_dispatch();
379
380	if (test_ok != 2)
381		test_ok = 0;
382
383end:
384	if (bev1)
385		bufferevent_free(bev1);
386	if (bev2)
387		bufferevent_free(bev2);
388
389}
390
391static void
392test_bufferevent_filters(void)
393{
394	test_bufferevent_filters_impl(0);
395}
396
397static void
398test_bufferevent_pair_filters(void)
399{
400	test_bufferevent_filters_impl(1);
401}
402
403
404static void
405sender_writecb(struct bufferevent *bev, void *ctx)
406{
407	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
408		bufferevent_disable(bev,EV_READ|EV_WRITE);
409		bufferevent_free(bev);
410	}
411}
412
413static void
414sender_errorcb(struct bufferevent *bev, short what, void *ctx)
415{
416	TT_FAIL(("Got sender error %d",(int)what));
417}
418
419static int bufferevent_connect_test_flags = 0;
420static int n_strings_read = 0;
421static int n_reads_invoked = 0;
422
423#define TEST_STR "Now is the time for all good events to signal for " \
424	"the good of their protocol"
425static void
426listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
427    struct sockaddr *sa, int socklen, void *arg)
428{
429	struct event_base *base = arg;
430	struct bufferevent *bev;
431	const char s[] = TEST_STR;
432	TT_BLATHER(("Got a request on socket %d", (int)fd ));
433	bev = bufferevent_socket_new(base, fd, bufferevent_connect_test_flags);
434	tt_assert(bev);
435	bufferevent_setcb(bev, NULL, sender_writecb, sender_errorcb, NULL);
436	bufferevent_write(bev, s, sizeof(s));
437end:
438	;
439}
440
441static void
442reader_eventcb(struct bufferevent *bev, short what, void *ctx)
443{
444	struct event_base *base = ctx;
445	if (what & BEV_EVENT_ERROR) {
446		perror("foobar");
447		TT_FAIL(("got connector error %d", (int)what));
448		return;
449	}
450	if (what & BEV_EVENT_CONNECTED) {
451		bufferevent_enable(bev, EV_READ);
452	}
453	if (what & BEV_EVENT_EOF) {
454		char buf[512];
455		size_t n;
456		n = bufferevent_read(bev, buf, sizeof(buf)-1);
457		buf[n] = '\0';
458		tt_str_op(buf, ==, TEST_STR);
459		if (++n_strings_read == 2)
460			event_base_loopexit(base, NULL);
461	}
462end:
463	;
464}
465
466static void
467reader_readcb(struct bufferevent *bev, void *ctx)
468{
469	n_reads_invoked++;
470}
471
472static void
473test_bufferevent_connect(void *arg)
474{
475	struct basic_test_data *data = arg;
476	struct evconnlistener *lev=NULL;
477	struct bufferevent *bev1=NULL, *bev2=NULL;
478	struct sockaddr_in localhost;
479	struct sockaddr_storage ss;
480	struct sockaddr *sa;
481	ev_socklen_t slen;
482
483	int be_flags=BEV_OPT_CLOSE_ON_FREE;
484
485	if (strstr((char*)data->setup_data, "defer")) {
486		be_flags |= BEV_OPT_DEFER_CALLBACKS;
487	}
488	if (strstr((char*)data->setup_data, "unlocked")) {
489		be_flags |= BEV_OPT_UNLOCK_CALLBACKS;
490	}
491	if (strstr((char*)data->setup_data, "lock")) {
492		be_flags |= BEV_OPT_THREADSAFE;
493	}
494	bufferevent_connect_test_flags = be_flags;
495#ifdef WIN32
496	if (!strcmp((char*)data->setup_data, "unset_connectex")) {
497		struct win32_extension_fns *ext =
498		    (struct win32_extension_fns *)
499		    event_get_win32_extension_fns();
500		ext->ConnectEx = NULL;
501	}
502#endif
503
504	memset(&localhost, 0, sizeof(localhost));
505
506	localhost.sin_port = 0; /* pick-a-port */
507	localhost.sin_addr.s_addr = htonl(0x7f000001L);
508	localhost.sin_family = AF_INET;
509	sa = (struct sockaddr *)&localhost;
510	lev = evconnlistener_new_bind(data->base, listen_cb, data->base,
511	    LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
512	    16, sa, sizeof(localhost));
513	tt_assert(lev);
514
515	sa = (struct sockaddr *)&ss;
516	slen = sizeof(ss);
517	if (regress_get_listener_addr(lev, sa, &slen) < 0) {
518		tt_abort_perror("getsockname");
519	}
520
521	tt_assert(!evconnlistener_enable(lev));
522	bev1 = bufferevent_socket_new(data->base, -1, be_flags);
523	bev2 = bufferevent_socket_new(data->base, -1, be_flags);
524	tt_assert(bev1);
525	tt_assert(bev2);
526	bufferevent_setcb(bev1, reader_readcb,NULL, reader_eventcb, data->base);
527	bufferevent_setcb(bev2, reader_readcb,NULL, reader_eventcb, data->base);
528
529	bufferevent_enable(bev1, EV_READ);
530	bufferevent_enable(bev2, EV_READ);
531
532	tt_want(!bufferevent_socket_connect(bev1, sa, sizeof(localhost)));
533	tt_want(!bufferevent_socket_connect(bev2, sa, sizeof(localhost)));
534
535	event_base_dispatch(data->base);
536
537	tt_int_op(n_strings_read, ==, 2);
538	tt_int_op(n_reads_invoked, >=, 2);
539end:
540	if (lev)
541		evconnlistener_free(lev);
542
543	if (bev1)
544		bufferevent_free(bev1);
545
546	if (bev2)
547		bufferevent_free(bev2);
548}
549
550static void
551want_fail_eventcb(struct bufferevent *bev, short what, void *ctx)
552{
553	struct event_base *base = ctx;
554	const char *err;
555	evutil_socket_t s;
556
557	if (what & BEV_EVENT_ERROR) {
558		s = bufferevent_getfd(bev);
559		err = evutil_socket_error_to_string(evutil_socket_geterror(s));
560		TT_BLATHER(("connection failure on %d: %s", s, err));
561		test_ok = 1;
562	} else {
563		TT_FAIL(("didn't fail? what %hd", what));
564	}
565
566	event_base_loopexit(base, NULL);
567}
568
569static void
570close_socket_cb(evutil_socket_t fd, short what, void *arg)
571{
572	evutil_socket_t *fdp = arg;
573	if (*fdp >= 0) {
574		evutil_closesocket(*fdp);
575		*fdp = -1;
576	}
577}
578
579static void
580test_bufferevent_connect_fail(void *arg)
581{
582	struct basic_test_data *data = arg;
583	struct bufferevent *bev=NULL;
584	struct sockaddr_in localhost;
585	struct sockaddr *sa = (struct sockaddr*)&localhost;
586	evutil_socket_t fake_listener = -1;
587	ev_socklen_t slen = sizeof(localhost);
588	struct event close_listener_event;
589	int close_listener_event_added = 0;
590	struct timeval one_second = { 1, 0 };
591	int r;
592
593	test_ok = 0;
594
595	memset(&localhost, 0, sizeof(localhost));
596	localhost.sin_port = 0; /* have the kernel pick a port */
597	localhost.sin_addr.s_addr = htonl(0x7f000001L);
598	localhost.sin_family = AF_INET;
599
600	/* bind, but don't listen or accept. should trigger
601	   "Connection refused" reliably on most platforms. */
602	fake_listener = socket(localhost.sin_family, SOCK_STREAM, 0);
603	tt_assert(fake_listener >= 0);
604	tt_assert(bind(fake_listener, sa, slen) == 0);
605	tt_assert(getsockname(fake_listener, sa, &slen) == 0);
606	bev = bufferevent_socket_new(data->base, -1,
607		BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
608	tt_assert(bev);
609	bufferevent_setcb(bev, NULL, NULL, want_fail_eventcb, data->base);
610
611	r = bufferevent_socket_connect(bev, sa, slen);
612	/* XXXX we'd like to test the '0' case everywhere, but FreeBSD tells
613	 * detects the error immediately, which is not really wrong of it. */
614	tt_want(r == 0 || r == -1);
615
616	/* Close the listener socket after a second. This should trigger
617	   "connection refused" on some other platforms, including OSX. */
618	evtimer_assign(&close_listener_event, data->base, close_socket_cb,
619	    &fake_listener);
620	event_add(&close_listener_event, &one_second);
621	close_listener_event_added = 1;
622
623	event_base_dispatch(data->base);
624
625	tt_int_op(test_ok, ==, 1);
626
627end:
628	if (fake_listener >= 0)
629		evutil_closesocket(fake_listener);
630
631	if (bev)
632		bufferevent_free(bev);
633
634	if (close_listener_event_added)
635		event_del(&close_listener_event);
636}
637
638struct timeout_cb_result {
639	struct timeval read_timeout_at;
640	struct timeval write_timeout_at;
641	struct timeval last_wrote_at;
642	int n_read_timeouts;
643	int n_write_timeouts;
644	int total_calls;
645};
646
647static void
648bev_timeout_write_cb(struct bufferevent *bev, void *arg)
649{
650	struct timeout_cb_result *res = arg;
651	evutil_gettimeofday(&res->last_wrote_at, NULL);
652}
653
654static void
655bev_timeout_event_cb(struct bufferevent *bev, short what, void *arg)
656{
657	struct timeout_cb_result *res = arg;
658	++res->total_calls;
659
660	if ((what & (BEV_EVENT_READING|BEV_EVENT_TIMEOUT))
661	    == (BEV_EVENT_READING|BEV_EVENT_TIMEOUT)) {
662		evutil_gettimeofday(&res->read_timeout_at, NULL);
663		++res->n_read_timeouts;
664	}
665	if ((what & (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT))
666	    == (BEV_EVENT_WRITING|BEV_EVENT_TIMEOUT)) {
667		evutil_gettimeofday(&res->write_timeout_at, NULL);
668		++res->n_write_timeouts;
669	}
670}
671
672static void
673test_bufferevent_timeouts(void *arg)
674{
675	/* "arg" is a string containing "pair" and/or "filter". */
676	struct bufferevent *bev1 = NULL, *bev2 = NULL;
677	struct basic_test_data *data = arg;
678	int use_pair = 0, use_filter = 0;
679	struct timeval tv_w, tv_r, started_at;
680	struct timeout_cb_result res1, res2;
681	char buf[1024];
682
683	memset(&res1, 0, sizeof(res1));
684	memset(&res2, 0, sizeof(res2));
685
686	if (strstr((char*)data->setup_data, "pair"))
687		use_pair = 1;
688	if (strstr((char*)data->setup_data, "filter"))
689		use_filter = 1;
690
691	if (use_pair) {
692		struct bufferevent *p[2];
693		tt_int_op(0, ==, bufferevent_pair_new(data->base, 0, p));
694		bev1 = p[0];
695		bev2 = p[1];
696	} else {
697		bev1 = bufferevent_socket_new(data->base, data->pair[0], 0);
698		bev2 = bufferevent_socket_new(data->base, data->pair[1], 0);
699	}
700
701	tt_assert(bev1);
702	tt_assert(bev2);
703
704	if (use_filter) {
705		struct bufferevent *bevf1, *bevf2;
706		bevf1 = bufferevent_filter_new(bev1, NULL, NULL,
707		    BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
708		bevf2 = bufferevent_filter_new(bev2, NULL, NULL,
709		    BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
710		tt_assert(bevf1);
711		tt_assert(bevf2);
712		bev1 = bevf1;
713		bev2 = bevf2;
714	}
715
716	/* Do this nice and early. */
717	bufferevent_disable(bev2, EV_READ);
718
719	/* bev1 will try to write and read.  Both will time out. */
720	evutil_gettimeofday(&started_at, NULL);
721	tv_w.tv_sec = tv_r.tv_sec = 0;
722	tv_w.tv_usec = 100*1000;
723	tv_r.tv_usec = 150*1000;
724	bufferevent_setcb(bev1, NULL, bev_timeout_write_cb,
725	    bev_timeout_event_cb, &res1);
726	bufferevent_setwatermark(bev1, EV_WRITE, 1024*1024+10, 0);
727	bufferevent_set_timeouts(bev1, &tv_r, &tv_w);
728	if (use_pair) {
729		/* For a pair, the fact that the other side isn't reading
730		 * makes the writer stall */
731		bufferevent_write(bev1, "ABCDEFG", 7);
732	} else {
733		/* For a real socket, the kernel's TCP buffers can eat a
734		 * fair number of bytes; make sure that at some point we
735		 * have some bytes that will stall. */
736		struct evbuffer *output = bufferevent_get_output(bev1);
737		int i;
738		memset(buf, 0xbb, sizeof(buf));
739		for (i=0;i<1024;++i) {
740			evbuffer_add_reference(output, buf, sizeof(buf),
741			    NULL, NULL);
742		}
743	}
744	bufferevent_enable(bev1, EV_READ|EV_WRITE);
745
746	/* bev2 has nothing to say, and isn't listening. */
747	bufferevent_setcb(bev2, NULL,  bev_timeout_write_cb,
748	    bev_timeout_event_cb, &res2);
749	tv_w.tv_sec = tv_r.tv_sec = 0;
750	tv_w.tv_usec = 200*1000;
751	tv_r.tv_usec = 100*1000;
752	bufferevent_set_timeouts(bev2, &tv_r, &tv_w);
753	bufferevent_enable(bev2, EV_WRITE);
754
755	tv_r.tv_sec = 1;
756	tv_r.tv_usec = 0;
757
758	event_base_loopexit(data->base, &tv_r);
759	event_base_dispatch(data->base);
760
761	/* XXXX Test that actually reading or writing a little resets the
762	 * timeouts. */
763
764	/* Each buf1 timeout happens, and happens only once. */
765	tt_want(res1.n_read_timeouts);
766	tt_want(res1.n_write_timeouts);
767	tt_want(res1.n_read_timeouts == 1);
768	tt_want(res1.n_write_timeouts == 1);
769
770	test_timeval_diff_eq(&started_at, &res1.read_timeout_at, 150);
771	test_timeval_diff_eq(&started_at, &res1.write_timeout_at, 100);
772
773end:
774	if (bev1)
775		bufferevent_free(bev1);
776	if (bev2)
777		bufferevent_free(bev2);
778}
779
780struct testcase_t bufferevent_testcases[] = {
781
782	LEGACY(bufferevent, TT_ISOLATED),
783	LEGACY(bufferevent_pair, TT_ISOLATED),
784	LEGACY(bufferevent_watermarks, TT_ISOLATED),
785	LEGACY(bufferevent_pair_watermarks, TT_ISOLATED),
786	LEGACY(bufferevent_filters, TT_ISOLATED),
787	LEGACY(bufferevent_pair_filters, TT_ISOLATED),
788	{ "bufferevent_connect", test_bufferevent_connect, TT_FORK|TT_NEED_BASE,
789	  &basic_setup, (void*)"" },
790	{ "bufferevent_connect_defer", test_bufferevent_connect,
791	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"defer" },
792	{ "bufferevent_connect_lock", test_bufferevent_connect,
793	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup, (void*)"lock" },
794	{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
795	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
796	  (void*)"defer lock" },
797	{ "bufferevent_connect_unlocked_cbs", test_bufferevent_connect,
798	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS, &basic_setup,
799	  (void*)"lock defer unlocked" },
800	{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
801	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
802	{ "bufferevent_timeout", test_bufferevent_timeouts,
803	  TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (void*)"" },
804	{ "bufferevent_timeout_pair", test_bufferevent_timeouts,
805	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"pair" },
806	{ "bufferevent_timeout_filter", test_bufferevent_timeouts,
807	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter" },
808	{ "bufferevent_timeout_filter_pair", test_bufferevent_timeouts,
809	  TT_FORK|TT_NEED_BASE, &basic_setup, (void*)"filter pair" },
810#ifdef _EVENT_HAVE_LIBZ
811	LEGACY(bufferevent_zlib, TT_ISOLATED),
812#else
813	{ "bufferevent_zlib", NULL, TT_SKIP, NULL, NULL },
814#endif
815
816	END_OF_TESTCASES,
817};
818
819struct testcase_t bufferevent_iocp_testcases[] = {
820
821	LEGACY(bufferevent, TT_ISOLATED|TT_ENABLE_IOCP),
822	LEGACY(bufferevent_watermarks, TT_ISOLATED|TT_ENABLE_IOCP),
823	LEGACY(bufferevent_filters, TT_ISOLATED|TT_ENABLE_IOCP),
824	{ "bufferevent_connect", test_bufferevent_connect,
825	  TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"" },
826	{ "bufferevent_connect_defer", test_bufferevent_connect,
827	  TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, (void*)"defer" },
828	{ "bufferevent_connect_lock", test_bufferevent_connect,
829	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
830	  (void*)"lock" },
831	{ "bufferevent_connect_lock_defer", test_bufferevent_connect,
832	  TT_FORK|TT_NEED_BASE|TT_NEED_THREADS|TT_ENABLE_IOCP, &basic_setup,
833	  (void*)"defer lock" },
834	{ "bufferevent_connect_fail", test_bufferevent_connect_fail,
835	  TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
836	{ "bufferevent_connect_nonblocking", test_bufferevent_connect,
837	  TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup,
838	  (void*)"unset_connectex" },
839
840	END_OF_TESTCASES,
841};
842