1 /* $NetBSD: regress_iocp.c,v 1.1.1.2 2017/01/31 21:14:53 christos Exp $ */ 2 /* 3 * Copyright (c) 2009-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 #include <stdlib.h> 29 #include <string.h> 30 #include "event2/event.h" 31 #include "event2/thread.h" 32 #include "event2/buffer.h" 33 #include "event2/buffer_compat.h" 34 #include "event2/bufferevent.h" 35 36 #include <winsock2.h> 37 #include <ws2tcpip.h> 38 39 #include "regress.h" 40 #include "tinytest.h" 41 #include "tinytest_macros.h" 42 43 #define WIN32_LEAN_AND_MEAN 44 #include <windows.h> 45 #include <winsock2.h> 46 #undef WIN32_LEAN_AND_MEAN 47 48 #include "iocp-internal.h" 49 #include "evbuffer-internal.h" 50 #include "evthread-internal.h" 51 52 /* FIXME remove these ones */ 53 #include <sys/queue.h> 54 #include "event2/event_struct.h" 55 #include "event-internal.h" 56 57 #define MAX_CALLS 16 58 59 static void *count_lock = NULL, *count_cond = NULL; 60 static int count = 0; 61 62 static void 63 count_init(void) 64 { 65 EVTHREAD_ALLOC_LOCK(count_lock, 0); 66 EVTHREAD_ALLOC_COND(count_cond); 67 68 tt_assert(count_lock); 69 tt_assert(count_cond); 70 71 end: 72 ; 73 } 74 75 static void 76 count_free(void) 77 { 78 EVTHREAD_FREE_LOCK(count_lock, 0); 79 EVTHREAD_FREE_COND(count_cond); 80 } 81 82 static void 83 count_incr(void) 84 { 85 EVLOCK_LOCK(count_lock, 0); 86 count++; 87 EVTHREAD_COND_BROADCAST(count_cond); 88 EVLOCK_UNLOCK(count_lock, 0); 89 } 90 91 static int 92 count_wait_for(int i, int ms) 93 { 94 struct timeval tv; 95 DWORD elapsed; 96 int rv = -1; 97 98 EVLOCK_LOCK(count_lock, 0); 99 while (ms > 0 && count != i) { 100 tv.tv_sec = 0; 101 tv.tv_usec = ms * 1000; 102 elapsed = GetTickCount(); 103 EVTHREAD_COND_WAIT_TIMED(count_cond, count_lock, &tv); 104 elapsed = GetTickCount() - elapsed; 105 ms -= elapsed; 106 } 107 if (count == i) 108 rv = 0; 109 EVLOCK_UNLOCK(count_lock, 0); 110 111 return rv; 112 } 113 114 struct dummy_overlapped { 115 struct event_overlapped eo; 116 void *lock; 117 int call_count; 118 uintptr_t keys[MAX_CALLS]; 119 ev_ssize_t sizes[MAX_CALLS]; 120 }; 121 122 static void 123 dummy_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok) 124 { 125 struct dummy_overlapped *d_o = 126 EVUTIL_UPCAST(o, struct dummy_overlapped, eo); 127 128 EVLOCK_LOCK(d_o->lock, 0); 129 if (d_o->call_count < MAX_CALLS) { 130 d_o->keys[d_o->call_count] = key; 131 d_o->sizes[d_o->call_count] = n; 132 } 133 d_o->call_count++; 134 EVLOCK_UNLOCK(d_o->lock, 0); 135 136 count_incr(); 137 } 138 139 static int 140 pair_is_in(struct dummy_overlapped *o, uintptr_t key, ev_ssize_t n) 141 { 142 int i; 143 int result = 0; 144 EVLOCK_LOCK(o->lock, 0); 145 for (i=0; i < o->call_count; ++i) { 146 if (o->keys[i] == key && o->sizes[i] == n) { 147 result = 1; 148 break; 149 } 150 } 151 EVLOCK_UNLOCK(o->lock, 0); 152 return result; 153 } 154 155 static void 156 test_iocp_port(void *ptr) 157 { 158 struct event_iocp_port *port = NULL; 159 struct dummy_overlapped o1, o2; 160 161 memset(&o1, 0, sizeof(o1)); 162 memset(&o2, 0, sizeof(o2)); 163 164 count_init(); 165 EVTHREAD_ALLOC_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 166 EVTHREAD_ALLOC_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 167 168 tt_assert(o1.lock); 169 tt_assert(o2.lock); 170 171 event_overlapped_init_(&o1.eo, dummy_cb); 172 event_overlapped_init_(&o2.eo, dummy_cb); 173 174 port = event_iocp_port_launch_(0); 175 tt_assert(port); 176 177 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 10, 100)); 178 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 20, 200)); 179 180 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 11, 101)); 181 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 21, 201)); 182 183 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 12, 102)); 184 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 22, 202)); 185 186 tt_assert(!event_iocp_activate_overlapped_(port, &o1.eo, 13, 103)); 187 tt_assert(!event_iocp_activate_overlapped_(port, &o2.eo, 23, 203)); 188 189 tt_int_op(count_wait_for(8, 2000), ==, 0); 190 191 tt_want(!event_iocp_shutdown_(port, 2000)); 192 193 tt_int_op(o1.call_count, ==, 4); 194 tt_int_op(o2.call_count, ==, 4); 195 196 tt_want(pair_is_in(&o1, 10, 100)); 197 tt_want(pair_is_in(&o1, 11, 101)); 198 tt_want(pair_is_in(&o1, 12, 102)); 199 tt_want(pair_is_in(&o1, 13, 103)); 200 201 tt_want(pair_is_in(&o2, 20, 200)); 202 tt_want(pair_is_in(&o2, 21, 201)); 203 tt_want(pair_is_in(&o2, 22, 202)); 204 tt_want(pair_is_in(&o2, 23, 203)); 205 206 end: 207 EVTHREAD_FREE_LOCK(o1.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 208 EVTHREAD_FREE_LOCK(o2.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 209 count_free(); 210 } 211 212 static struct evbuffer *rbuf = NULL, *wbuf = NULL; 213 214 static void 215 read_complete(struct event_overlapped *eo, uintptr_t key, 216 ev_ssize_t nbytes, int ok) 217 { 218 tt_assert(ok); 219 evbuffer_commit_read_(rbuf, nbytes); 220 count_incr(); 221 end: 222 ; 223 } 224 225 static void 226 write_complete(struct event_overlapped *eo, uintptr_t key, 227 ev_ssize_t nbytes, int ok) 228 { 229 tt_assert(ok); 230 evbuffer_commit_write_(wbuf, nbytes); 231 count_incr(); 232 end: 233 ; 234 } 235 236 static void 237 test_iocp_evbuffer(void *ptr) 238 { 239 struct event_overlapped rol, wol; 240 struct basic_test_data *data = ptr; 241 struct event_iocp_port *port = NULL; 242 struct evbuffer *buf=NULL; 243 struct evbuffer_chain *chain; 244 char junk[1024]; 245 int i; 246 247 count_init(); 248 event_overlapped_init_(&rol, read_complete); 249 event_overlapped_init_(&wol, write_complete); 250 251 for (i = 0; i < (int)sizeof(junk); ++i) 252 junk[i] = (char)(i); 253 254 rbuf = evbuffer_overlapped_new_(data->pair[0]); 255 wbuf = evbuffer_overlapped_new_(data->pair[1]); 256 evbuffer_enable_locking(rbuf, NULL); 257 evbuffer_enable_locking(wbuf, NULL); 258 259 port = event_iocp_port_launch_(0); 260 tt_assert(port); 261 tt_assert(rbuf); 262 tt_assert(wbuf); 263 264 tt_assert(!event_iocp_port_associate_(port, data->pair[0], 100)); 265 tt_assert(!event_iocp_port_associate_(port, data->pair[1], 100)); 266 267 for (i=0;i<10;++i) 268 evbuffer_add(wbuf, junk, sizeof(junk)); 269 270 buf = evbuffer_new(); 271 tt_assert(buf != NULL); 272 evbuffer_add(rbuf, junk, sizeof(junk)); 273 tt_assert(!evbuffer_launch_read_(rbuf, 2048, &rol)); 274 evbuffer_add_buffer(buf, rbuf); 275 tt_int_op(evbuffer_get_length(buf), ==, sizeof(junk)); 276 for (chain = buf->first; chain; chain = chain->next) 277 tt_int_op(chain->flags & EVBUFFER_MEM_PINNED_ANY, ==, 0); 278 tt_assert(!evbuffer_get_length(rbuf)); 279 tt_assert(!evbuffer_launch_write_(wbuf, 512, &wol)); 280 281 tt_int_op(count_wait_for(2, 2000), ==, 0); 282 283 tt_int_op(evbuffer_get_length(rbuf),==,512); 284 285 /* FIXME Actually test some stuff here. */ 286 287 tt_want(!event_iocp_shutdown_(port, 2000)); 288 end: 289 count_free(); 290 evbuffer_free(rbuf); 291 evbuffer_free(wbuf); 292 if (buf) evbuffer_free(buf); 293 } 294 295 static int got_readcb = 0; 296 297 static void 298 async_readcb(struct bufferevent *bev, void *arg) 299 { 300 /* Disabling read should cause the loop to quit */ 301 bufferevent_disable(bev, EV_READ); 302 got_readcb++; 303 } 304 305 static void 306 test_iocp_bufferevent_async(void *ptr) 307 { 308 struct basic_test_data *data = ptr; 309 struct event_iocp_port *port = NULL; 310 struct bufferevent *bea1=NULL, *bea2=NULL; 311 char buf[128]; 312 size_t n; 313 314 event_base_start_iocp_(data->base, 0); 315 port = event_base_get_iocp_(data->base); 316 tt_assert(port); 317 318 bea1 = bufferevent_async_new_(data->base, data->pair[0], 319 BEV_OPT_DEFER_CALLBACKS); 320 bea2 = bufferevent_async_new_(data->base, data->pair[1], 321 BEV_OPT_DEFER_CALLBACKS); 322 tt_assert(bea1); 323 tt_assert(bea2); 324 325 bufferevent_setcb(bea2, async_readcb, NULL, NULL, NULL); 326 bufferevent_enable(bea1, EV_WRITE); 327 bufferevent_enable(bea2, EV_READ); 328 329 bufferevent_write(bea1, "Hello world", strlen("Hello world")+1); 330 331 event_base_dispatch(data->base); 332 333 tt_int_op(got_readcb, ==, 1); 334 n = bufferevent_read(bea2, buf, sizeof(buf)-1); 335 buf[n]='\0'; 336 tt_str_op(buf, ==, "Hello world"); 337 338 end: 339 bufferevent_free(bea1); 340 bufferevent_free(bea2); 341 } 342 343 344 struct testcase_t iocp_testcases[] = { 345 { "port", test_iocp_port, TT_FORK|TT_NEED_THREADS, &basic_setup, NULL }, 346 { "evbuffer", test_iocp_evbuffer, 347 TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS, 348 &basic_setup, NULL }, 349 { "bufferevent_async", test_iocp_bufferevent_async, 350 TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_THREADS|TT_NEED_BASE, 351 &basic_setup, NULL }, 352 END_OF_TESTCASES 353 }; 354