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