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