1*c43e99fdSEd Maste /* 2*c43e99fdSEd Maste * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson 3*c43e99fdSEd Maste * 4*c43e99fdSEd Maste * Redistribution and use in source and binary forms, with or without 5*c43e99fdSEd Maste * modification, are permitted provided that the following conditions 6*c43e99fdSEd Maste * are met: 7*c43e99fdSEd Maste * 1. Redistributions of source code must retain the above copyright 8*c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer. 9*c43e99fdSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 10*c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer in the 11*c43e99fdSEd Maste * documentation and/or other materials provided with the distribution. 12*c43e99fdSEd Maste * 3. The name of the author may not be used to endorse or promote products 13*c43e99fdSEd Maste * derived from this software without specific prior written permission. 14*c43e99fdSEd Maste * 15*c43e99fdSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*c43e99fdSEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*c43e99fdSEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*c43e99fdSEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*c43e99fdSEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*c43e99fdSEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*c43e99fdSEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*c43e99fdSEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*c43e99fdSEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*c43e99fdSEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*c43e99fdSEd Maste */ 26*c43e99fdSEd Maste 27*c43e99fdSEd Maste #include <stdlib.h> 28*c43e99fdSEd Maste #include <string.h> 29*c43e99fdSEd Maste #include "event2/event.h" 30*c43e99fdSEd Maste #include "event2/thread.h" 31*c43e99fdSEd Maste #include "event2/buffer.h" 32*c43e99fdSEd Maste #include "event2/buffer_compat.h" 33*c43e99fdSEd Maste #include "event2/bufferevent.h" 34*c43e99fdSEd Maste 35*c43e99fdSEd Maste #include <winsock2.h> 36*c43e99fdSEd Maste #include <ws2tcpip.h> 37*c43e99fdSEd Maste 38*c43e99fdSEd Maste #include "regress.h" 39*c43e99fdSEd Maste #include "tinytest.h" 40*c43e99fdSEd Maste #include "tinytest_macros.h" 41*c43e99fdSEd Maste 42*c43e99fdSEd Maste #define WIN32_LEAN_AND_MEAN 43*c43e99fdSEd Maste #include <windows.h> 44*c43e99fdSEd Maste #include <winsock2.h> 45*c43e99fdSEd Maste #undef WIN32_LEAN_AND_MEAN 46*c43e99fdSEd Maste 47*c43e99fdSEd Maste #include "iocp-internal.h" 48*c43e99fdSEd Maste #include "evbuffer-internal.h" 49*c43e99fdSEd Maste #include "evthread-internal.h" 50*c43e99fdSEd Maste 51*c43e99fdSEd Maste /* FIXME remove these ones */ 52*c43e99fdSEd Maste #include <sys/queue.h> 53*c43e99fdSEd Maste #include "event2/event_struct.h" 54*c43e99fdSEd Maste #include "event-internal.h" 55*c43e99fdSEd Maste 56*c43e99fdSEd Maste #define MAX_CALLS 16 57*c43e99fdSEd Maste 58*c43e99fdSEd Maste static void *count_lock = NULL, *count_cond = NULL; 59*c43e99fdSEd Maste static int count = 0; 60*c43e99fdSEd Maste 61*c43e99fdSEd Maste static void 62*c43e99fdSEd Maste count_init(void) 63*c43e99fdSEd Maste { 64*c43e99fdSEd Maste EVTHREAD_ALLOC_LOCK(count_lock, 0); 65*c43e99fdSEd Maste EVTHREAD_ALLOC_COND(count_cond); 66*c43e99fdSEd Maste 67*c43e99fdSEd Maste tt_assert(count_lock); 68*c43e99fdSEd Maste tt_assert(count_cond); 69*c43e99fdSEd Maste 70*c43e99fdSEd Maste end: 71*c43e99fdSEd Maste ; 72*c43e99fdSEd Maste } 73*c43e99fdSEd Maste 74*c43e99fdSEd Maste static void 75*c43e99fdSEd Maste count_free(void) 76*c43e99fdSEd Maste { 77*c43e99fdSEd Maste EVTHREAD_FREE_LOCK(count_lock, 0); 78*c43e99fdSEd Maste EVTHREAD_FREE_COND(count_cond); 79*c43e99fdSEd Maste } 80*c43e99fdSEd Maste 81*c43e99fdSEd Maste static void 82*c43e99fdSEd Maste count_incr(void) 83*c43e99fdSEd Maste { 84*c43e99fdSEd Maste EVLOCK_LOCK(count_lock, 0); 85*c43e99fdSEd Maste count++; 86*c43e99fdSEd Maste EVTHREAD_COND_BROADCAST(count_cond); 87*c43e99fdSEd Maste EVLOCK_UNLOCK(count_lock, 0); 88*c43e99fdSEd Maste } 89*c43e99fdSEd Maste 90*c43e99fdSEd Maste static int 91*c43e99fdSEd Maste count_wait_for(int i, int ms) 92*c43e99fdSEd Maste { 93*c43e99fdSEd Maste struct timeval tv; 94*c43e99fdSEd Maste DWORD elapsed; 95*c43e99fdSEd Maste int rv = -1; 96*c43e99fdSEd Maste 97*c43e99fdSEd Maste EVLOCK_LOCK(count_lock, 0); 98*c43e99fdSEd Maste while (ms > 0 && count != i) { 99*c43e99fdSEd Maste tv.tv_sec = 0; 100*c43e99fdSEd Maste tv.tv_usec = ms * 1000; 101*c43e99fdSEd Maste elapsed = GetTickCount(); 102*c43e99fdSEd Maste EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv); 103*c43e99fdSEd Maste elapsed = GetTickCount() - elapsed; 104*c43e99fdSEd Maste ms -= elapsed; 105*c43e99fdSEd Maste } 106*c43e99fdSEd Maste if (count == i) 107*c43e99fdSEd Maste rv = 0; 108*c43e99fdSEd Maste EVLOCK_UNLOCK(count_lock, 0); 109*c43e99fdSEd Maste 110*c43e99fdSEd Maste return rv; 111*c43e99fdSEd Maste } 112*c43e99fdSEd Maste 113*c43e99fdSEd Maste struct dummy_overlapped { 114*c43e99fdSEd Maste struct event_overlapped eo; 115*c43e99fdSEd Maste void *lock; 116*c43e99fdSEd Maste int call_count; 117*c43e99fdSEd Maste uintptr_t keys[MAX_CALLS]; 118*c43e99fdSEd Maste ev_ssize_t sizes[MAX_CALLS]; 119*c43e99fdSEd Maste }; 120*c43e99fdSEd Maste 121*c43e99fdSEd Maste static void 122*c43e99fdSEd Maste dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok) 123*c43e99fdSEd Maste { 124*c43e99fdSEd Maste struct dummy_overlapped *d_o = 125*c43e99fdSEd Maste EVUTIL_UPCAST(o, struct dummy_overlapped, eo); 126*c43e99fdSEd Maste 127*c43e99fdSEd Maste EVLOCK_LOCK(d_o->lock, 0); 128*c43e99fdSEd Maste if (d_o->call_count < MAX_CALLS) { 129*c43e99fdSEd Maste d_o->keys[d_o->call_count] = key; 130*c43e99fdSEd Maste d_o->sizes[d_o->call_count] = n; 131*c43e99fdSEd Maste } 132*c43e99fdSEd Maste d_o->call_count++; 133*c43e99fdSEd Maste EVLOCK_UNLOCK(d_o->lock, 0); 134*c43e99fdSEd Maste 135*c43e99fdSEd Maste count_incr(); 136*c43e99fdSEd Maste } 137*c43e99fdSEd Maste 138*c43e99fdSEd Maste static int 139*c43e99fdSEd Maste pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n) 140*c43e99fdSEd Maste { 141*c43e99fdSEd Maste int i; 142*c43e99fdSEd Maste int result = 0; 143*c43e99fdSEd Maste EVLOCK_LOCK(o->lock, 0); 144*c43e99fdSEd Maste for (i=0; i < o->call_count; ++i) { 145*c43e99fdSEd Maste if (o->keys[i] == key && o->sizes[i] == n) { 146*c43e99fdSEd Maste result = 1; 147*c43e99fdSEd Maste break; 148*c43e99fdSEd Maste } 149*c43e99fdSEd Maste } 150*c43e99fdSEd Maste EVLOCK_UNLOCK(o->lock, 0); 151*c43e99fdSEd Maste return result; 152*c43e99fdSEd Maste } 153*c43e99fdSEd Maste 154*c43e99fdSEd Maste static void 155*c43e99fdSEd Maste test_iocp_port(void *ptr) 156*c43e99fdSEd Maste { 157*c43e99fdSEd Maste struct event_iocp_port *port = NULL; 158*c43e99fdSEd Maste struct dummy_overlapped o1, o2; 159*c43e99fdSEd Maste 160*c43e99fdSEd Maste memset(&o1, 0, sizeof(o1)); 161*c43e99fdSEd Maste memset(&o2, 0, sizeof(o2)); 162*c43e99fdSEd Maste 163*c43e99fdSEd Maste count_init(); 164*c43e99fdSEd Maste EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 165*c43e99fdSEd Maste EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 166*c43e99fdSEd Maste 167*c43e99fdSEd Maste tt_assert(o1.lock); 168*c43e99fdSEd Maste tt_assert(o2.lock); 169*c43e99fdSEd Maste 170*c43e99fdSEd Maste event_overlapped_init_(&o1.eo, dummy_cb); 171*c43e99fdSEd Maste event_overlapped_init_(&o2.eo, dummy_cb); 172*c43e99fdSEd Maste 173*c43e99fdSEd Maste port = event_iocp_port_launch_(0); 174*c43e99fdSEd Maste tt_assert(port); 175*c43e99fdSEd Maste 176*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 10, 100)); 177*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 20, 200)); 178*c43e99fdSEd Maste 179*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 11, 101)); 180*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 21, 201)); 181*c43e99fdSEd Maste 182*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 12, 102)); 183*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 22, 202)); 184*c43e99fdSEd Maste 185*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 13, 103)); 186*c43e99fdSEd Maste tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 23, 203)); 187*c43e99fdSEd Maste 188*c43e99fdSEd Maste tt_int_op(count_wait_for(8, 2000), ==, 0); 189*c43e99fdSEd Maste 190*c43e99fdSEd Maste tt_want(!event_iocp_shutdown_(port, 2000)); 191*c43e99fdSEd Maste 192*c43e99fdSEd Maste tt_int_op(o1.call_count, ==, 4); 193*c43e99fdSEd Maste tt_int_op(o2.call_count, ==, 4); 194*c43e99fdSEd Maste 195*c43e99fdSEd Maste tt_want(pair_is_in(&o1, 10, 100)); 196*c43e99fdSEd Maste tt_want(pair_is_in(&o1, 11, 101)); 197*c43e99fdSEd Maste tt_want(pair_is_in(&o1, 12, 102)); 198*c43e99fdSEd Maste tt_want(pair_is_in(&o1, 13, 103)); 199*c43e99fdSEd Maste 200*c43e99fdSEd Maste tt_want(pair_is_in(&o2, 20, 200)); 201*c43e99fdSEd Maste tt_want(pair_is_in(&o2, 21, 201)); 202*c43e99fdSEd Maste tt_want(pair_is_in(&o2, 22, 202)); 203*c43e99fdSEd Maste tt_want(pair_is_in(&o2, 23, 203)); 204*c43e99fdSEd Maste 205*c43e99fdSEd Maste end: 206*c43e99fdSEd Maste EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 207*c43e99fdSEd Maste EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 208*c43e99fdSEd Maste count_free(); 209*c43e99fdSEd Maste } 210*c43e99fdSEd Maste 211*c43e99fdSEd Maste static struct evbuffer *rbuf = NULL, *wbuf = NULL; 212*c43e99fdSEd Maste 213*c43e99fdSEd Maste static void 214*c43e99fdSEd Maste read_complete(struct event_overlapped *eo, uintptr_t key, 215*c43e99fdSEd Maste ev_ssize_t nbytes, int ok) 216*c43e99fdSEd Maste { 217*c43e99fdSEd Maste tt_assert(ok); 218*c43e99fdSEd Maste evbuffer_commit_read_(rbuf, nbytes); 219*c43e99fdSEd Maste count_incr(); 220*c43e99fdSEd Maste end: 221*c43e99fdSEd Maste ; 222*c43e99fdSEd Maste } 223*c43e99fdSEd Maste 224*c43e99fdSEd Maste static void 225*c43e99fdSEd Maste write_complete(struct event_overlapped *eo, uintptr_t key, 226*c43e99fdSEd Maste ev_ssize_t nbytes, int ok) 227*c43e99fdSEd Maste { 228*c43e99fdSEd Maste tt_assert(ok); 229*c43e99fdSEd Maste evbuffer_commit_write_(wbuf, nbytes); 230*c43e99fdSEd Maste count_incr(); 231*c43e99fdSEd Maste end: 232*c43e99fdSEd Maste ; 233*c43e99fdSEd Maste } 234*c43e99fdSEd Maste 235*c43e99fdSEd Maste static void 236*c43e99fdSEd Maste test_iocp_evbuffer(void *ptr) 237*c43e99fdSEd Maste { 238*c43e99fdSEd Maste struct event_overlapped rol, wol; 239*c43e99fdSEd Maste struct basic_test_data *data = ptr; 240*c43e99fdSEd Maste struct event_iocp_port *port = NULL; 241*c43e99fdSEd Maste struct evbuffer *buf=NULL; 242*c43e99fdSEd Maste struct evbuffer_chain *chain; 243*c43e99fdSEd Maste char junk[1024]; 244*c43e99fdSEd Maste int i; 245*c43e99fdSEd Maste 246*c43e99fdSEd Maste count_init(); 247*c43e99fdSEd Maste event_overlapped_init_(&rol, read_complete); 248*c43e99fdSEd Maste event_overlapped_init_(&wol, write_complete); 249*c43e99fdSEd Maste 250*c43e99fdSEd Maste for (i = 0; i < (int)sizeof(junk); ++i) 251*c43e99fdSEd Maste junk[i] = (char)(i); 252*c43e99fdSEd Maste 253*c43e99fdSEd Maste rbuf = evbuffer_overlapped_new_(data->pair[0]); 254*c43e99fdSEd Maste wbuf = evbuffer_overlapped_new_(data->pair[1]); 255*c43e99fdSEd Maste evbuffer_enable_locking(rbuf, NULL); 256*c43e99fdSEd Maste evbuffer_enable_locking(wbuf, NULL); 257*c43e99fdSEd Maste 258*c43e99fdSEd Maste port = event_iocp_port_launch_(0); 259*c43e99fdSEd Maste tt_assert(port); 260*c43e99fdSEd Maste tt_assert(rbuf); 261*c43e99fdSEd Maste tt_assert(wbuf); 262*c43e99fdSEd Maste 263*c43e99fdSEd Maste tt_assert(!event_iocp_port_associate_(port, data->pair[0], 100)); 264*c43e99fdSEd Maste tt_assert(!event_iocp_port_associate_(port, data->pair[1], 100)); 265*c43e99fdSEd Maste 266*c43e99fdSEd Maste for (i=0;i<10;++i) 267*c43e99fdSEd Maste evbuffer_add(wbuf, junk, sizeof(junk)); 268*c43e99fdSEd Maste 269*c43e99fdSEd Maste buf = evbuffer_new(); 270*c43e99fdSEd Maste tt_assert(buf != NULL); 271*c43e99fdSEd Maste evbuffer_add(rbuf, junk, sizeof(junk)); 272*c43e99fdSEd Maste tt_assert(!evbuffer_launch_read_(rbuf, 2048, &rol)); 273*c43e99fdSEd Maste evbuffer_add_buffer(buf, rbuf); 274*c43e99fdSEd Maste tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk)); 275*c43e99fdSEd Maste for (chain = buf->first; chain; chain = chain->next) 276*c43e99fdSEd Maste tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0); 277*c43e99fdSEd Maste tt_assert(!evbuffer_get_length(rbuf)); 278*c43e99fdSEd Maste tt_assert(!evbuffer_launch_write_(wbuf, 512, &wol)); 279*c43e99fdSEd Maste 280*c43e99fdSEd Maste tt_int_op(count_wait_for(2, 2000), ==, 0); 281*c43e99fdSEd Maste 282*c43e99fdSEd Maste tt_int_op(evbuffer_get_length(rbuf),==,512); 283*c43e99fdSEd Maste 284*c43e99fdSEd Maste /* FIXME Actually test some stuff here. */ 285*c43e99fdSEd Maste 286*c43e99fdSEd Maste tt_want(!event_iocp_shutdown_(port, 2000)); 287*c43e99fdSEd Maste end: 288*c43e99fdSEd Maste count_free(); 289*c43e99fdSEd Maste evbuffer_free(rbuf); 290*c43e99fdSEd Maste evbuffer_free(wbuf); 291*c43e99fdSEd Maste if (buf) evbuffer_free(buf); 292*c43e99fdSEd Maste } 293*c43e99fdSEd Maste 294*c43e99fdSEd Maste static int got_readcb = 0; 295*c43e99fdSEd Maste 296*c43e99fdSEd Maste static void 297*c43e99fdSEd Maste async_readcb(struct bufferevent *bev, void *arg) 298*c43e99fdSEd Maste { 299*c43e99fdSEd Maste /* Disabling read should cause the loop to quit */ 300*c43e99fdSEd Maste bufferevent_disable(bev, EV_READ); 301*c43e99fdSEd Maste got_readcb++; 302*c43e99fdSEd Maste } 303*c43e99fdSEd Maste 304*c43e99fdSEd Maste static void 305*c43e99fdSEd Maste test_iocp_bufferevent_async(void *ptr) 306*c43e99fdSEd Maste { 307*c43e99fdSEd Maste struct basic_test_data *data = ptr; 308*c43e99fdSEd Maste struct event_iocp_port *port = NULL; 309*c43e99fdSEd Maste struct bufferevent *bea1=NULL, *bea2=NULL; 310*c43e99fdSEd Maste char buf[128]; 311*c43e99fdSEd Maste size_t n; 312*c43e99fdSEd Maste 313*c43e99fdSEd Maste event_base_start_iocp_(data->base, 0); 314*c43e99fdSEd Maste port = event_base_get_iocp_(data->base); 315*c43e99fdSEd Maste tt_assert(port); 316*c43e99fdSEd Maste 317*c43e99fdSEd Maste bea1 = bufferevent_async_new_(data->base, data->pair[0], 318*c43e99fdSEd Maste BEV_OPT_DEFER_CALLBACKS); 319*c43e99fdSEd Maste bea2 = bufferevent_async_new_(data->base, data->pair[1], 320*c43e99fdSEd Maste BEV_OPT_DEFER_CALLBACKS); 321*c43e99fdSEd Maste tt_assert(bea1); 322*c43e99fdSEd Maste tt_assert(bea2); 323*c43e99fdSEd Maste 324*c43e99fdSEd Maste bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL); 325*c43e99fdSEd Maste bufferevent_enable(bea1, EV_WRITE); 326*c43e99fdSEd Maste bufferevent_enable(bea2, EV_READ); 327*c43e99fdSEd Maste 328*c43e99fdSEd Maste bufferevent_write(bea1, "Hello world", strlen("Hello world")+1); 329*c43e99fdSEd Maste 330*c43e99fdSEd Maste event_base_dispatch(data->base); 331*c43e99fdSEd Maste 332*c43e99fdSEd Maste tt_int_op(got_readcb, ==, 1); 333*c43e99fdSEd Maste n = bufferevent_read(bea2, buf, sizeof(buf)-1); 334*c43e99fdSEd Maste buf[n]='\0'; 335*c43e99fdSEd Maste tt_str_op(buf, ==, "Hello world"); 336*c43e99fdSEd Maste 337*c43e99fdSEd Maste end: 338*c43e99fdSEd Maste bufferevent_free(bea1); 339*c43e99fdSEd Maste bufferevent_free(bea2); 340*c43e99fdSEd Maste } 341*c43e99fdSEd Maste 342*c43e99fdSEd Maste 343*c43e99fdSEd Maste struct testcase_t iocp_testcases[] = { 344*c43e99fdSEd Maste { "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL }, 345*c43e99fdSEd Maste { "evbuffer", test_iocp_evbuffer, 346*c43e99fdSEd Maste TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS, 347*c43e99fdSEd Maste &basic_setup, NULL }, 348*c43e99fdSEd Maste { "bufferevent_async", test_iocp_bufferevent_async, 349*c43e99fdSEd Maste TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE, 350*c43e99fdSEd Maste &basic_setup, NULL }, 351*c43e99fdSEd Maste END_OF_TESTCASES 352*c43e99fdSEd Maste }; 353