1275970Scy/*
2275970Scy * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
3275970Scy *
4275970Scy * Redistribution and use in source and binary forms, with or without
5275970Scy * modification, are permitted provided that the following conditions
6275970Scy * are met:
7275970Scy * 1. Redistributions of source code must retain the above copyright
8275970Scy *    notice, this list of conditions and the following disclaimer.
9275970Scy * 2. Redistributions in binary form must reproduce the above copyright
10275970Scy *    notice, this list of conditions and the following disclaimer in the
11275970Scy *    documentation and/or other materials provided with the distribution.
12275970Scy * 3. The name of the author may not be used to endorse or promote products
13275970Scy *    derived from this software without specific prior written permission.
14275970Scy *
15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25275970Scy */
26275970Scy
27275970Scy#include <stdlib.h>
28275970Scy#include <string.h>
29275970Scy#include "event2/event.h"
30275970Scy#include "event2/thread.h"
31275970Scy#include "event2/buffer.h"
32275970Scy#include "event2/buffer_compat.h"
33275970Scy#include "event2/bufferevent.h"
34275970Scy
35275970Scy#include <winsock2.h>
36275970Scy#include <ws2tcpip.h>
37275970Scy
38275970Scy#include "regress.h"
39275970Scy#include "tinytest.h"
40275970Scy#include "tinytest_macros.h"
41275970Scy
42275970Scy#define WIN32_LEAN_AND_MEAN
43275970Scy#include <windows.h>
44275970Scy#include <winsock2.h>
45275970Scy#undef WIN32_LEAN_AND_MEAN
46275970Scy
47275970Scy#include "iocp-internal.h"
48275970Scy#include "evbuffer-internal.h"
49275970Scy#include "evthread-internal.h"
50275970Scy
51275970Scy/* FIXME remove these ones */
52275970Scy#include <sys/queue.h>
53275970Scy#include "event2/event_struct.h"
54275970Scy#include "event-internal.h"
55275970Scy
56275970Scy#define MAX_CALLS 16
57275970Scy
58275970Scystatic void *count_lock = NULL, *count_cond = NULL;
59275970Scystatic int count = 0;
60275970Scy
61275970Scystatic void
62275970Scycount_init(void)
63275970Scy{
64275970Scy	EVTHREAD_ALLOC_LOCK(count_lock, 0);
65275970Scy	EVTHREAD_ALLOC_COND(count_cond);
66275970Scy
67275970Scy	tt_assert(count_lock);
68275970Scy	tt_assert(count_cond);
69275970Scy
70275970Scyend:
71275970Scy	;
72275970Scy}
73275970Scy
74275970Scystatic void
75275970Scycount_free(void)
76275970Scy{
77275970Scy	EVTHREAD_FREE_LOCK(count_lock, 0);
78275970Scy	EVTHREAD_FREE_COND(count_cond);
79275970Scy}
80275970Scy
81275970Scystatic void
82275970Scycount_incr(void)
83275970Scy{
84275970Scy	EVLOCK_LOCK(count_lock, 0);
85275970Scy	count++;
86275970Scy	EVTHREAD_COND_BROADCAST(count_cond);
87275970Scy	EVLOCK_UNLOCK(count_lock, 0);
88275970Scy}
89275970Scy
90275970Scystatic int
91275970Scycount_wait_for(int i, int ms)
92275970Scy{
93275970Scy	struct timeval tv;
94275970Scy	DWORD elapsed;
95275970Scy	int rv = -1;
96275970Scy
97275970Scy	EVLOCK_LOCK(count_lock, 0);
98275970Scy	while (ms > 0 && count != i) {
99275970Scy		tv.tv_sec = 0;
100275970Scy		tv.tv_usec = ms * 1000;
101275970Scy		elapsed = GetTickCount();
102275970Scy		EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv);
103275970Scy		elapsed = GetTickCount() - elapsed;
104275970Scy		ms -= elapsed;
105275970Scy	}
106275970Scy	if (count == i)
107275970Scy		rv = 0;
108275970Scy	EVLOCK_UNLOCK(count_lock, 0);
109275970Scy
110275970Scy	return rv;
111275970Scy}
112275970Scy
113275970Scystruct dummy_overlapped {
114275970Scy	struct event_overlapped eo;
115275970Scy	void *lock;
116275970Scy	int call_count;
117275970Scy	uintptr_t keys[MAX_CALLS];
118275970Scy	ev_ssize_t sizes[MAX_CALLS];
119275970Scy};
120275970Scy
121275970Scystatic void
122275970Scydummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok)
123275970Scy{
124275970Scy	struct dummy_overlapped *d_o =
125275970Scy	    EVUTIL_UPCAST(o, struct dummy_overlapped, eo);
126275970Scy
127275970Scy	EVLOCK_LOCK(d_o->lock, 0);
128275970Scy	if (d_o->call_count < MAX_CALLS) {
129275970Scy		d_o->keys[d_o->call_count] = key;
130275970Scy		d_o->sizes[d_o->call_count] = n;
131275970Scy	}
132275970Scy	d_o->call_count++;
133275970Scy	EVLOCK_UNLOCK(d_o->lock, 0);
134275970Scy
135275970Scy	count_incr();
136275970Scy}
137275970Scy
138275970Scystatic int
139275970Scypair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n)
140275970Scy{
141275970Scy	int i;
142275970Scy	int result = 0;
143275970Scy	EVLOCK_LOCK(o->lock, 0);
144275970Scy	for (i=0; i < o->call_count; ++i) {
145275970Scy		if (o->keys[i] == key && o->sizes[i] == n) {
146275970Scy			result = 1;
147275970Scy			break;
148275970Scy		}
149275970Scy	}
150275970Scy	EVLOCK_UNLOCK(o->lock, 0);
151275970Scy	return result;
152275970Scy}
153275970Scy
154275970Scystatic void
155275970Scytest_iocp_port(void *ptr)
156275970Scy{
157275970Scy	struct event_iocp_port *port = NULL;
158275970Scy	struct dummy_overlapped o1, o2;
159275970Scy
160275970Scy	memset(&o1, 0, sizeof(o1));
161275970Scy	memset(&o2, 0, sizeof(o2));
162275970Scy
163275970Scy	count_init();
164275970Scy	EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
165275970Scy	EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
166275970Scy
167275970Scy	tt_assert(o1.lock);
168275970Scy	tt_assert(o2.lock);
169275970Scy
170275970Scy	event_overlapped_init_(&o1.eo, dummy_cb);
171275970Scy	event_overlapped_init_(&o2.eo, dummy_cb);
172275970Scy
173275970Scy	port = event_iocp_port_launch_(0);
174275970Scy	tt_assert(port);
175275970Scy
176275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 10, 100));
177275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 20, 200));
178275970Scy
179275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 11, 101));
180275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 21, 201));
181275970Scy
182275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 12, 102));
183275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 22, 202));
184275970Scy
185275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 13, 103));
186275970Scy	tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 23, 203));
187275970Scy
188275970Scy	tt_int_op(count_wait_for(8, 2000), ==, 0);
189275970Scy
190275970Scy	tt_want(!event_iocp_shutdown_(port, 2000));
191275970Scy
192275970Scy	tt_int_op(o1.call_count, ==, 4);
193275970Scy	tt_int_op(o2.call_count, ==, 4);
194275970Scy
195275970Scy	tt_want(pair_is_in(&o1, 10, 100));
196275970Scy	tt_want(pair_is_in(&o1, 11, 101));
197275970Scy	tt_want(pair_is_in(&o1, 12, 102));
198275970Scy	tt_want(pair_is_in(&o1, 13, 103));
199275970Scy
200275970Scy	tt_want(pair_is_in(&o2, 20, 200));
201275970Scy	tt_want(pair_is_in(&o2, 21, 201));
202275970Scy	tt_want(pair_is_in(&o2, 22, 202));
203275970Scy	tt_want(pair_is_in(&o2, 23, 203));
204275970Scy
205275970Scyend:
206275970Scy	EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
207275970Scy	EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
208275970Scy	count_free();
209275970Scy}
210275970Scy
211275970Scystatic struct evbuffer *rbuf = NULL, *wbuf = NULL;
212275970Scy
213275970Scystatic void
214275970Scyread_complete(struct event_overlapped *eo, uintptr_t key,
215275970Scy    ev_ssize_t nbytes, int ok)
216275970Scy{
217275970Scy	tt_assert(ok);
218275970Scy	evbuffer_commit_read_(rbuf, nbytes);
219275970Scy	count_incr();
220275970Scyend:
221275970Scy	;
222275970Scy}
223275970Scy
224275970Scystatic void
225275970Scywrite_complete(struct event_overlapped *eo, uintptr_t key,
226275970Scy    ev_ssize_t nbytes, int ok)
227275970Scy{
228275970Scy	tt_assert(ok);
229275970Scy	evbuffer_commit_write_(wbuf, nbytes);
230275970Scy	count_incr();
231275970Scyend:
232275970Scy	;
233275970Scy}
234275970Scy
235275970Scystatic void
236275970Scytest_iocp_evbuffer(void *ptr)
237275970Scy{
238275970Scy	struct event_overlapped rol, wol;
239275970Scy	struct basic_test_data *data = ptr;
240275970Scy	struct event_iocp_port *port = NULL;
241275970Scy	struct evbuffer *buf=NULL;
242275970Scy	struct evbuffer_chain *chain;
243275970Scy	char junk[1024];
244275970Scy	int i;
245275970Scy
246275970Scy	count_init();
247275970Scy	event_overlapped_init_(&rol, read_complete);
248275970Scy	event_overlapped_init_(&wol, write_complete);
249275970Scy
250275970Scy	for (i = 0; i < (int)sizeof(junk); ++i)
251275970Scy		junk[i] = (char)(i);
252275970Scy
253275970Scy	rbuf = evbuffer_overlapped_new_(data->pair[0]);
254275970Scy	wbuf = evbuffer_overlapped_new_(data->pair[1]);
255275970Scy	evbuffer_enable_locking(rbuf, NULL);
256275970Scy	evbuffer_enable_locking(wbuf, NULL);
257275970Scy
258275970Scy	port = event_iocp_port_launch_(0);
259275970Scy	tt_assert(port);
260275970Scy	tt_assert(rbuf);
261275970Scy	tt_assert(wbuf);
262275970Scy
263275970Scy	tt_assert(!event_iocp_port_associate_(port, data->pair[0], 100));
264275970Scy	tt_assert(!event_iocp_port_associate_(port, data->pair[1], 100));
265275970Scy
266275970Scy	for (i=0;i<10;++i)
267275970Scy		evbuffer_add(wbuf, junk, sizeof(junk));
268275970Scy
269275970Scy	buf = evbuffer_new();
270275970Scy	tt_assert(buf != NULL);
271275970Scy	evbuffer_add(rbuf, junk, sizeof(junk));
272275970Scy	tt_assert(!evbuffer_launch_read_(rbuf, 2048, &rol));
273275970Scy	evbuffer_add_buffer(buf, rbuf);
274275970Scy	tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk));
275275970Scy	for (chain = buf->first; chain; chain = chain->next)
276275970Scy		tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0);
277275970Scy	tt_assert(!evbuffer_get_length(rbuf));
278275970Scy	tt_assert(!evbuffer_launch_write_(wbuf, 512, &wol));
279275970Scy
280275970Scy	tt_int_op(count_wait_for(2, 2000), ==, 0);
281275970Scy
282275970Scy	tt_int_op(evbuffer_get_length(rbuf),==,512);
283275970Scy
284275970Scy	/* FIXME Actually test some stuff here. */
285275970Scy
286275970Scy	tt_want(!event_iocp_shutdown_(port, 2000));
287275970Scyend:
288275970Scy	count_free();
289275970Scy	evbuffer_free(rbuf);
290275970Scy	evbuffer_free(wbuf);
291275970Scy	if (buf) evbuffer_free(buf);
292275970Scy}
293275970Scy
294275970Scystatic int got_readcb = 0;
295275970Scy
296275970Scystatic void
297275970Scyasync_readcb(struct bufferevent *bev, void *arg)
298275970Scy{
299275970Scy	/* Disabling read should cause the loop to quit */
300275970Scy	bufferevent_disable(bev, EV_READ);
301275970Scy	got_readcb++;
302275970Scy}
303275970Scy
304275970Scystatic void
305275970Scytest_iocp_bufferevent_async(void *ptr)
306275970Scy{
307275970Scy	struct basic_test_data *data = ptr;
308275970Scy	struct event_iocp_port *port = NULL;
309275970Scy	struct bufferevent *bea1=NULL, *bea2=NULL;
310275970Scy	char buf[128];
311275970Scy	size_t n;
312275970Scy
313275970Scy	event_base_start_iocp_(data->base, 0);
314275970Scy	port = event_base_get_iocp_(data->base);
315275970Scy	tt_assert(port);
316275970Scy
317275970Scy	bea1 = bufferevent_async_new_(data->base, data->pair[0],
318275970Scy	    BEV_OPT_DEFER_CALLBACKS);
319275970Scy	bea2 = bufferevent_async_new_(data->base, data->pair[1],
320275970Scy	    BEV_OPT_DEFER_CALLBACKS);
321275970Scy	tt_assert(bea1);
322275970Scy	tt_assert(bea2);
323275970Scy
324275970Scy	bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL);
325275970Scy	bufferevent_enable(bea1, EV_WRITE);
326275970Scy	bufferevent_enable(bea2, EV_READ);
327275970Scy
328275970Scy	bufferevent_write(bea1, "Hello world", strlen("Hello world")+1);
329275970Scy
330275970Scy	event_base_dispatch(data->base);
331275970Scy
332275970Scy	tt_int_op(got_readcb, ==, 1);
333275970Scy	n = bufferevent_read(bea2, buf, sizeof(buf)-1);
334275970Scy	buf[n]='\0';
335275970Scy	tt_str_op(buf, ==, "Hello world");
336275970Scy
337275970Scyend:
338275970Scy	bufferevent_free(bea1);
339275970Scy	bufferevent_free(bea2);
340275970Scy}
341275970Scy
342275970Scy
343275970Scystruct testcase_t iocp_testcases[] = {
344275970Scy	{ "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL },
345275970Scy	{ "evbuffer", test_iocp_evbuffer,
346275970Scy	  TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS,
347275970Scy	  &basic_setup, NULL },
348275970Scy	{ "bufferevent_async", test_iocp_bufferevent_async,
349275970Scy	  TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE,
350275970Scy	  &basic_setup, NULL },
351275970Scy	END_OF_TESTCASES
352275970Scy};
353