1 /* 2 * util/winsock_event.c - implementation of the unbound winsock event handler. 3 * 4 * Copyright (c) 2008, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /** 36 * \file 37 * Implementation of the unbound WinSock2 API event notification handler 38 * for the Windows port. 39 */ 40 41 #include "config.h" 42 #ifdef USE_WINSOCK 43 #include <signal.h> 44 #include "util/winsock_event.h" 45 #include "util/fptr_wlist.h" 46 47 int mini_ev_cmp(const void* a, const void* b) 48 { 49 const struct event *e = (const struct event*)a; 50 const struct event *f = (const struct event*)b; 51 if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) 52 return -1; 53 if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) 54 return 1; 55 if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) 56 return -1; 57 if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) 58 return 1; 59 if(e < f) 60 return -1; 61 if(e > f) 62 return 1; 63 return 0; 64 } 65 66 /** set time */ 67 static int 68 settime(struct event_base* base) 69 { 70 if(gettimeofday(base->time_tv, NULL) < 0) { 71 return -1; 72 } 73 #ifndef S_SPLINT_S 74 *base->time_secs = (uint32_t)base->time_tv->tv_sec; 75 #endif 76 return 0; 77 } 78 79 #ifdef UNBOUND_DEBUG 80 /** 81 * Find a fd in the list of items. 82 * Note that not all items have a fd associated (those are -1). 83 * Signals are stored separately, and not searched. 84 * @param base: event base to look in. 85 * @param fd: what socket to look for. 86 * @return the index in the array, or -1 on failure. 87 */ 88 static int 89 find_fd(struct event_base* base, int fd) 90 { 91 int i; 92 for(i=0; i<base->max; i++) { 93 if(base->items[i]->ev_fd == fd) 94 return i; 95 } 96 return -1; 97 } 98 #endif 99 100 /** Find ptr in base array */ 101 static void 102 zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) 103 { 104 int i; 105 for(i=0; i<WSK_MAX_ITEMS; i++) { 106 if(waitfor[i] == x) 107 waitfor[i] = 0; 108 } 109 } 110 111 void *event_init(uint32_t* time_secs, struct timeval* time_tv) 112 { 113 struct event_base* base = (struct event_base*)malloc( 114 sizeof(struct event_base)); 115 if(!base) 116 return NULL; 117 memset(base, 0, sizeof(*base)); 118 base->time_secs = time_secs; 119 base->time_tv = time_tv; 120 if(settime(base) < 0) { 121 event_base_free(base); 122 return NULL; 123 } 124 base->items = (struct event**)calloc(WSK_MAX_ITEMS, 125 sizeof(struct event*)); 126 if(!base->items) { 127 event_base_free(base); 128 return NULL; 129 } 130 base->cap = WSK_MAX_ITEMS; 131 base->max = 0; 132 base->times = rbtree_create(mini_ev_cmp); 133 if(!base->times) { 134 event_base_free(base); 135 return NULL; 136 } 137 base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); 138 if(!base->signals) { 139 event_base_free(base); 140 return NULL; 141 } 142 base->tcp_stickies = 0; 143 base->tcp_reinvigorated = 0; 144 verbose(VERB_CLIENT, "winsock_event inited"); 145 return base; 146 } 147 148 const char *event_get_version(void) 149 { 150 return "winsock-event-"PACKAGE_VERSION; 151 } 152 153 const char *event_get_method(void) 154 { 155 return "WSAWaitForMultipleEvents"; 156 } 157 158 /** call timeouts handlers, and return how long to wait for next one or -1 */ 159 static void handle_timeouts(struct event_base* base, struct timeval* now, 160 struct timeval* wait) 161 { 162 struct event* p; 163 #ifndef S_SPLINT_S 164 wait->tv_sec = (time_t)-1; 165 #endif 166 verbose(VERB_CLIENT, "winsock_event handle_timeouts"); 167 168 while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) 169 !=RBTREE_NULL) { 170 #ifndef S_SPLINT_S 171 if(p->ev_timeout.tv_sec > now->tv_sec || 172 (p->ev_timeout.tv_sec==now->tv_sec && 173 p->ev_timeout.tv_usec > now->tv_usec)) { 174 /* there is a next larger timeout. wait for it */ 175 wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; 176 if(now->tv_usec > p->ev_timeout.tv_usec) { 177 wait->tv_sec--; 178 wait->tv_usec = 1000000 - (now->tv_usec - 179 p->ev_timeout.tv_usec); 180 } else { 181 wait->tv_usec = p->ev_timeout.tv_usec 182 - now->tv_usec; 183 } 184 verbose(VERB_CLIENT, "winsock_event wait=%d.%6.6d", 185 (int)wait->tv_sec, (int)wait->tv_usec); 186 return; 187 } 188 #endif 189 /* event times out, remove it */ 190 (void)rbtree_delete(base->times, p); 191 p->ev_events &= ~EV_TIMEOUT; 192 fptr_ok(fptr_whitelist_event(p->ev_callback)); 193 (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); 194 } 195 verbose(VERB_CLIENT, "winsock_event wait=(-1)"); 196 } 197 198 /** handle is_signal events and see if signalled */ 199 static void handle_signal(struct event* ev) 200 { 201 DWORD ret; 202 log_assert(ev->is_signal && ev->hEvent); 203 /* see if the event is signalled */ 204 ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, 205 0 /* return immediately */, 0 /* not alertable for IOcomple*/); 206 if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { 207 log_err("WSAWaitForMultipleEvents(signal) failed: %s", 208 wsa_strerror(WSAGetLastError())); 209 return; 210 } 211 if(ret == WSA_WAIT_TIMEOUT) { 212 /* not signalled */ 213 return; 214 } 215 216 /* reset the signal */ 217 if(!WSAResetEvent(ev->hEvent)) 218 log_err("WSAResetEvent failed: %s", 219 wsa_strerror(WSAGetLastError())); 220 /* do the callback (which may set the signal again) */ 221 fptr_ok(fptr_whitelist_event(ev->ev_callback)); 222 (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); 223 } 224 225 /** call select and callbacks for that */ 226 static int handle_select(struct event_base* base, struct timeval* wait) 227 { 228 DWORD timeout = 0; /* in milliseconds */ 229 DWORD ret; 230 struct event* eventlist[WSK_MAX_ITEMS]; 231 WSANETWORKEVENTS netev; 232 int i, numwait = 0, startidx = 0, was_timeout = 0; 233 int newstickies = 0; 234 struct timeval nultm; 235 236 verbose(VERB_CLIENT, "winsock_event handle_select"); 237 238 #ifndef S_SPLINT_S 239 if(wait->tv_sec==(time_t)-1) 240 wait = NULL; 241 if(wait) 242 timeout = wait->tv_sec*1000 + wait->tv_usec/1000; 243 if(base->tcp_stickies) { 244 wait = &nultm; 245 nultm.tv_sec = 0; 246 nultm.tv_usec = 0; 247 timeout = 0; /* no waiting, we have sticky events */ 248 } 249 #endif 250 251 /* prepare event array */ 252 for(i=0; i<base->max; i++) { 253 if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) 254 continue; /* skip timer only events */ 255 eventlist[numwait] = base->items[i]; 256 base->waitfor[numwait++] = base->items[i]->hEvent; 257 if(numwait == WSK_MAX_ITEMS) 258 break; /* sanity check */ 259 } 260 log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); 261 verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%x " 262 "timeout=%d", base->max, numwait, (int)wait, (int)timeout); 263 264 /* do the wait */ 265 if(numwait == 0) { 266 /* WSAWaitFor.. doesn't like 0 event objects */ 267 if(wait) { 268 Sleep(timeout); 269 } 270 was_timeout = 1; 271 } else { 272 ret = WSAWaitForMultipleEvents(numwait, base->waitfor, 273 0 /* do not wait for all, just one will do */, 274 wait?timeout:WSA_INFINITE, 275 0); /* we are not alertable (IO completion events) */ 276 if(ret == WSA_WAIT_IO_COMPLETION) { 277 log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); 278 return -1; 279 } else if(ret == WSA_WAIT_FAILED) { 280 log_err("WSAWaitForMultipleEvents failed: %s", 281 wsa_strerror(WSAGetLastError())); 282 return -1; 283 } else if(ret == WSA_WAIT_TIMEOUT) { 284 was_timeout = 1; 285 } else 286 startidx = ret - WSA_WAIT_EVENT_0; 287 } 288 verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", 289 was_timeout, startidx); 290 291 /* get new time after wait */ 292 if(settime(base) < 0) 293 return -1; 294 295 /* callbacks */ 296 if(base->tcp_stickies) 297 startidx = 0; /* process all events, some are sticky */ 298 for(i=startidx; i<numwait; i++) 299 eventlist[i]->just_checked = 1; 300 301 verbose(VERB_CLIENT, "winsock_event signals"); 302 for(i=startidx; i<numwait; i++) { 303 if(!base->waitfor[i]) 304 continue; /* was deleted */ 305 if(eventlist[i]->is_signal) { 306 eventlist[i]->just_checked = 0; 307 handle_signal(eventlist[i]); 308 } 309 } 310 /* early exit - do not process network, exit quickly */ 311 if(base->need_to_exit) 312 return 0; 313 314 verbose(VERB_CLIENT, "winsock_event net"); 315 for(i=startidx; i<numwait; i++) { 316 short bits = 0; 317 /* eventlist[i] fired */ 318 /* see if eventlist[i] is still valid and just checked from 319 * WSAWaitForEvents */ 320 if(!base->waitfor[i]) 321 continue; /* was deleted */ 322 if(!eventlist[i]->just_checked) 323 continue; /* added by other callback */ 324 if(eventlist[i]->is_signal) 325 continue; /* not a network event at all */ 326 eventlist[i]->just_checked = 0; 327 328 if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, 329 base->waitfor[i], /* reset the event handle */ 330 /*NULL,*/ /* do not reset the event handle */ 331 &netev) != 0) { 332 log_err("WSAEnumNetworkEvents failed: %s", 333 wsa_strerror(WSAGetLastError())); 334 return -1; 335 } 336 if((netev.lNetworkEvents & FD_READ)) { 337 if(netev.iErrorCode[FD_READ_BIT] != 0) 338 verbose(VERB_ALGO, "FD_READ_BIT error: %s", 339 wsa_strerror(netev.iErrorCode[FD_READ_BIT])); 340 bits |= EV_READ; 341 } 342 if((netev.lNetworkEvents & FD_WRITE)) { 343 if(netev.iErrorCode[FD_WRITE_BIT] != 0) 344 verbose(VERB_ALGO, "FD_WRITE_BIT error: %s", 345 wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); 346 bits |= EV_WRITE; 347 } 348 if((netev.lNetworkEvents & FD_CONNECT)) { 349 if(netev.iErrorCode[FD_CONNECT_BIT] != 0) 350 verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s", 351 wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); 352 bits |= EV_READ; 353 bits |= EV_WRITE; 354 } 355 if((netev.lNetworkEvents & FD_ACCEPT)) { 356 if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) 357 verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s", 358 wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); 359 bits |= EV_READ; 360 } 361 if((netev.lNetworkEvents & FD_CLOSE)) { 362 if(netev.iErrorCode[FD_CLOSE_BIT] != 0) 363 verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s", 364 wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); 365 bits |= EV_READ; 366 bits |= EV_WRITE; 367 } 368 if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { 369 verbose(VERB_ALGO, "winsock %d pass sticky %s%s", 370 eventlist[i]->ev_fd, 371 (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 372 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 373 bits |= eventlist[i]->old_events; 374 } 375 if(eventlist[i]->is_tcp && bits) { 376 eventlist[i]->old_events = bits; 377 eventlist[i]->stick_events = 1; 378 if((eventlist[i]->ev_events & bits)) { 379 newstickies = 1; 380 } 381 verbose(VERB_ALGO, "winsock %d store sticky %s%s", 382 eventlist[i]->ev_fd, 383 (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 384 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 385 } 386 if((bits & eventlist[i]->ev_events)) { 387 verbose(VERB_ALGO, "winsock event callback %p fd=%d " 388 "%s%s%s%s%s ; %s%s%s", 389 eventlist[i], eventlist[i]->ev_fd, 390 (netev.lNetworkEvents&FD_READ)?" FD_READ":"", 391 (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", 392 (netev.lNetworkEvents&FD_CONNECT)? 393 " FD_CONNECT":"", 394 (netev.lNetworkEvents&FD_ACCEPT)? 395 " FD_ACCEPT":"", 396 (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", 397 (bits&EV_READ)?" EV_READ":"", 398 (bits&EV_WRITE)?" EV_WRITE":"", 399 (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); 400 401 fptr_ok(fptr_whitelist_event( 402 eventlist[i]->ev_callback)); 403 (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, 404 bits & eventlist[i]->ev_events, 405 eventlist[i]->ev_arg); 406 } 407 if(eventlist[i]->is_tcp && bits) 408 verbose(VERB_ALGO, "winsock %d got sticky %s%s", 409 eventlist[i]->ev_fd, 410 (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 411 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 412 } 413 verbose(VERB_CLIENT, "winsock_event net"); 414 if(base->tcp_reinvigorated) { 415 verbose(VERB_CLIENT, "winsock_event reinvigorated"); 416 base->tcp_reinvigorated = 0; 417 newstickies = 1; 418 } 419 base->tcp_stickies = newstickies; 420 verbose(VERB_CLIENT, "winsock_event handle_select end"); 421 return 0; 422 } 423 424 int event_base_dispatch(struct event_base *base) 425 { 426 struct timeval wait; 427 if(settime(base) < 0) 428 return -1; 429 while(!base->need_to_exit) 430 { 431 /* see if timeouts need handling */ 432 handle_timeouts(base, base->time_tv, &wait); 433 if(base->need_to_exit) 434 return 0; 435 /* do select */ 436 if(handle_select(base, &wait) < 0) { 437 if(base->need_to_exit) 438 return 0; 439 return -1; 440 } 441 } 442 return 0; 443 } 444 445 int event_base_loopexit(struct event_base *base, 446 struct timeval * ATTR_UNUSED(tv)) 447 { 448 verbose(VERB_CLIENT, "winsock_event loopexit"); 449 base->need_to_exit = 1; 450 return 0; 451 } 452 453 void event_base_free(struct event_base *base) 454 { 455 verbose(VERB_CLIENT, "winsock_event event_base_free"); 456 if(!base) 457 return; 458 if(base->items) 459 free(base->items); 460 if(base->times) 461 free(base->times); 462 if(base->signals) 463 free(base->signals); 464 free(base); 465 } 466 467 void event_set(struct event *ev, int fd, short bits, 468 void (*cb)(int, short, void *), void *arg) 469 { 470 ev->node.key = ev; 471 ev->ev_fd = fd; 472 ev->ev_events = bits; 473 ev->ev_callback = cb; 474 fptr_ok(fptr_whitelist_event(ev->ev_callback)); 475 ev->ev_arg = arg; 476 ev->just_checked = 0; 477 ev->added = 0; 478 } 479 480 int event_base_set(struct event_base *base, struct event *ev) 481 { 482 ev->ev_base = base; 483 ev->old_events = 0; 484 ev->stick_events = 0; 485 ev->added = 0; 486 return 0; 487 } 488 489 int event_add(struct event *ev, struct timeval *tv) 490 { 491 verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=%d %s%s%s", 492 ev, ev->added, ev->ev_fd, 493 (tv?(int)tv->tv_sec*1000+(int)tv->tv_usec/1000:-1), 494 (ev->ev_events&EV_READ)?" EV_READ":"", 495 (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 496 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 497 if(ev->added) 498 event_del(ev); 499 log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1); 500 ev->is_tcp = 0; 501 ev->is_signal = 0; 502 ev->just_checked = 0; 503 504 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 505 BOOL b=0; 506 int t, l; 507 long events = 0; 508 509 if(ev->ev_base->max == ev->ev_base->cap) 510 return -1; 511 ev->idx = ev->ev_base->max++; 512 ev->ev_base->items[ev->idx] = ev; 513 514 if( (ev->ev_events&EV_READ) ) 515 events |= FD_READ; 516 if( (ev->ev_events&EV_WRITE) ) 517 events |= FD_WRITE; 518 l = sizeof(t); 519 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, 520 (void*)&t, &l) != 0) 521 log_err("getsockopt(SO_TYPE) failed: %s", 522 wsa_strerror(WSAGetLastError())); 523 if(t == SOCK_STREAM) { 524 /* TCP socket */ 525 ev->is_tcp = 1; 526 events |= FD_CLOSE; 527 if( (ev->ev_events&EV_WRITE) ) 528 events |= FD_CONNECT; 529 l = sizeof(b); 530 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, 531 (void*)&b, &l) != 0) 532 log_err("getsockopt(SO_ACCEPTCONN) failed: %s", 533 wsa_strerror(WSAGetLastError())); 534 if(b) /* TCP accept socket */ 535 events |= FD_ACCEPT; 536 } 537 ev->hEvent = WSACreateEvent(); 538 if(ev->hEvent == WSA_INVALID_EVENT) 539 log_err("WSACreateEvent failed: %s", 540 wsa_strerror(WSAGetLastError())); 541 /* automatically sets fd to nonblocking mode. 542 * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ 543 if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { 544 log_err("WSAEventSelect failed: %s", 545 wsa_strerror(WSAGetLastError())); 546 } 547 if(ev->is_tcp && ev->stick_events && 548 (ev->ev_events & ev->old_events)) { 549 /* go to processing the sticky event right away */ 550 ev->ev_base->tcp_reinvigorated = 1; 551 } 552 } 553 554 if(tv && (ev->ev_events&EV_TIMEOUT)) { 555 #ifndef S_SPLINT_S 556 struct timeval *now = ev->ev_base->time_tv; 557 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 558 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 559 while(ev->ev_timeout.tv_usec > 1000000) { 560 ev->ev_timeout.tv_usec -= 1000000; 561 ev->ev_timeout.tv_sec++; 562 } 563 #endif 564 (void)rbtree_insert(ev->ev_base->times, &ev->node); 565 } 566 ev->added = 1; 567 return 0; 568 } 569 570 int event_del(struct event *ev) 571 { 572 verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=%d %s%s%s", 573 ev, ev->added, ev->ev_fd, 574 (ev->ev_events&EV_TIMEOUT)?(int)ev->ev_timeout.tv_sec*1000+ 575 (int)ev->ev_timeout.tv_usec/1000:-1, 576 (ev->ev_events&EV_READ)?" EV_READ":"", 577 (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 578 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 579 if(!ev->added) 580 return 0; 581 log_assert(ev->added); 582 if((ev->ev_events&EV_TIMEOUT)) 583 (void)rbtree_delete(ev->ev_base->times, &ev->node); 584 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 585 log_assert(ev->ev_base->max > 0); 586 /* remove item and compact the list */ 587 ev->ev_base->items[ev->idx] = 588 ev->ev_base->items[ev->ev_base->max-1]; 589 ev->ev_base->items[ev->ev_base->max-1] = NULL; 590 ev->ev_base->max--; 591 if(ev->idx < ev->ev_base->max) 592 ev->ev_base->items[ev->idx]->idx = ev->idx; 593 zero_waitfor(ev->ev_base->waitfor, ev->hEvent); 594 595 if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) 596 log_err("WSAEventSelect(disable) failed: %s", 597 wsa_strerror(WSAGetLastError())); 598 if(!WSACloseEvent(ev->hEvent)) 599 log_err("WSACloseEvent failed: %s", 600 wsa_strerror(WSAGetLastError())); 601 } 602 ev->just_checked = 0; 603 ev->added = 0; 604 return 0; 605 } 606 607 /** which base gets to handle signals */ 608 static struct event_base* signal_base = NULL; 609 /** signal handler */ 610 static RETSIGTYPE sigh(int sig) 611 { 612 struct event* ev; 613 if(!signal_base || sig < 0 || sig >= MAX_SIG) 614 return; 615 ev = signal_base->signals[sig]; 616 if(!ev) 617 return; 618 fptr_ok(fptr_whitelist_event(ev->ev_callback)); 619 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 620 } 621 622 int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv)) 623 { 624 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 625 return -1; 626 signal_base = ev->ev_base; 627 ev->ev_base->signals[ev->ev_fd] = ev; 628 ev->added = 1; 629 if(signal(ev->ev_fd, sigh) == SIG_ERR) { 630 return -1; 631 } 632 return 0; 633 } 634 635 int signal_del(struct event *ev) 636 { 637 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 638 return -1; 639 ev->ev_base->signals[ev->ev_fd] = NULL; 640 ev->added = 0; 641 return 0; 642 } 643 644 void winsock_tcp_wouldblock(struct event* ev, int eventbits) 645 { 646 verbose(VERB_ALGO, "winsock: tcp wouldblock %s", 647 eventbits==EV_READ?"EV_READ":"EV_WRITE"); 648 ev->old_events &= (~eventbits); 649 if(ev->old_events == 0) 650 ev->stick_events = 0; 651 /* in case this is the last sticky event, we could 652 * possibly run an empty handler loop to reset the base 653 * tcp_stickies variable 654 */ 655 } 656 657 int winsock_register_wsaevent(struct event_base* base, struct event* ev, 658 WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) 659 { 660 if(base->max == base->cap) 661 return 0; 662 memset(ev, 0, sizeof(*ev)); 663 ev->ev_fd = -1; 664 ev->ev_events = EV_READ; 665 ev->ev_callback = cb; 666 ev->ev_arg = arg; 667 ev->is_signal = 1; 668 ev->hEvent = wsaevent; 669 ev->added = 1; 670 ev->ev_base = base; 671 ev->idx = ev->ev_base->max++; 672 ev->ev_base->items[ev->idx] = ev; 673 return 1; 674 } 675 676 void winsock_unregister_wsaevent(struct event* ev) 677 { 678 if(!ev || !ev->added) return; 679 log_assert(ev->added && ev->ev_base->max > 0) 680 /* remove item and compact the list */ 681 ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; 682 ev->ev_base->items[ev->ev_base->max-1] = NULL; 683 ev->ev_base->max--; 684 if(ev->idx < ev->ev_base->max) 685 ev->ev_base->items[ev->idx]->idx = ev->idx; 686 ev->added = 0; 687 } 688 689 #else /* USE_WINSOCK */ 690 /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ 691 int winsock_unused_symbol = 1; 692 #endif /* USE_WINSOCK */ 693