1933707f3Ssthen /* 2933707f3Ssthen * util/winsock_event.c - implementation of the unbound winsock event handler. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen /** 36933707f3Ssthen * \file 37933707f3Ssthen * Implementation of the unbound WinSock2 API event notification handler 38933707f3Ssthen * for the Windows port. 39933707f3Ssthen */ 40933707f3Ssthen 41933707f3Ssthen #include "config.h" 42933707f3Ssthen #ifdef USE_WINSOCK 43933707f3Ssthen #include <signal.h> 445d76a658Ssthen #ifdef HAVE_TIME_H 455d76a658Ssthen #include <time.h> 465d76a658Ssthen #endif 475d76a658Ssthen #include <sys/time.h> 48933707f3Ssthen #include "util/winsock_event.h" 49933707f3Ssthen #include "util/fptr_wlist.h" 50933707f3Ssthen 51933707f3Ssthen int mini_ev_cmp(const void* a, const void* b) 52933707f3Ssthen { 53933707f3Ssthen const struct event *e = (const struct event*)a; 54933707f3Ssthen const struct event *f = (const struct event*)b; 55933707f3Ssthen if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) 56933707f3Ssthen return -1; 57933707f3Ssthen if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) 58933707f3Ssthen return 1; 59933707f3Ssthen if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) 60933707f3Ssthen return -1; 61933707f3Ssthen if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) 62933707f3Ssthen return 1; 63933707f3Ssthen if(e < f) 64933707f3Ssthen return -1; 65933707f3Ssthen if(e > f) 66933707f3Ssthen return 1; 67933707f3Ssthen return 0; 68933707f3Ssthen } 69933707f3Ssthen 70933707f3Ssthen /** set time */ 71933707f3Ssthen static int 72933707f3Ssthen settime(struct event_base* base) 73933707f3Ssthen { 74933707f3Ssthen if(gettimeofday(base->time_tv, NULL) < 0) { 75933707f3Ssthen return -1; 76933707f3Ssthen } 77933707f3Ssthen #ifndef S_SPLINT_S 78229e174cSsthen *base->time_secs = (time_t)base->time_tv->tv_sec; 79933707f3Ssthen #endif 80933707f3Ssthen return 0; 81933707f3Ssthen } 82933707f3Ssthen 83933707f3Ssthen #ifdef UNBOUND_DEBUG 84933707f3Ssthen /** 85933707f3Ssthen * Find a fd in the list of items. 86933707f3Ssthen * Note that not all items have a fd associated (those are -1). 87933707f3Ssthen * Signals are stored separately, and not searched. 88933707f3Ssthen * @param base: event base to look in. 89933707f3Ssthen * @param fd: what socket to look for. 90933707f3Ssthen * @return the index in the array, or -1 on failure. 91933707f3Ssthen */ 92933707f3Ssthen static int 93933707f3Ssthen find_fd(struct event_base* base, int fd) 94933707f3Ssthen { 95933707f3Ssthen int i; 96933707f3Ssthen for(i=0; i<base->max; i++) { 97933707f3Ssthen if(base->items[i]->ev_fd == fd) 98933707f3Ssthen return i; 99933707f3Ssthen } 100933707f3Ssthen return -1; 101933707f3Ssthen } 102933707f3Ssthen #endif 103933707f3Ssthen 104933707f3Ssthen /** Find ptr in base array */ 105933707f3Ssthen static void 106933707f3Ssthen zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) 107933707f3Ssthen { 108933707f3Ssthen int i; 109933707f3Ssthen for(i=0; i<WSK_MAX_ITEMS; i++) { 110933707f3Ssthen if(waitfor[i] == x) 111933707f3Ssthen waitfor[i] = 0; 112933707f3Ssthen } 113933707f3Ssthen } 114933707f3Ssthen 115229e174cSsthen void *event_init(time_t* time_secs, struct timeval* time_tv) 116933707f3Ssthen { 117933707f3Ssthen struct event_base* base = (struct event_base*)malloc( 118933707f3Ssthen sizeof(struct event_base)); 119933707f3Ssthen if(!base) 120933707f3Ssthen return NULL; 121933707f3Ssthen memset(base, 0, sizeof(*base)); 122933707f3Ssthen base->time_secs = time_secs; 123933707f3Ssthen base->time_tv = time_tv; 124933707f3Ssthen if(settime(base) < 0) { 125933707f3Ssthen event_base_free(base); 126933707f3Ssthen return NULL; 127933707f3Ssthen } 128933707f3Ssthen base->items = (struct event**)calloc(WSK_MAX_ITEMS, 129933707f3Ssthen sizeof(struct event*)); 130933707f3Ssthen if(!base->items) { 131933707f3Ssthen event_base_free(base); 132933707f3Ssthen return NULL; 133933707f3Ssthen } 134933707f3Ssthen base->cap = WSK_MAX_ITEMS; 135933707f3Ssthen base->max = 0; 136933707f3Ssthen base->times = rbtree_create(mini_ev_cmp); 137933707f3Ssthen if(!base->times) { 138933707f3Ssthen event_base_free(base); 139933707f3Ssthen return NULL; 140933707f3Ssthen } 141933707f3Ssthen base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); 142933707f3Ssthen if(!base->signals) { 143933707f3Ssthen event_base_free(base); 144933707f3Ssthen return NULL; 145933707f3Ssthen } 146933707f3Ssthen base->tcp_stickies = 0; 147933707f3Ssthen base->tcp_reinvigorated = 0; 148933707f3Ssthen verbose(VERB_CLIENT, "winsock_event inited"); 149933707f3Ssthen return base; 150933707f3Ssthen } 151933707f3Ssthen 152933707f3Ssthen const char *event_get_version(void) 153933707f3Ssthen { 154933707f3Ssthen return "winsock-event-"PACKAGE_VERSION; 155933707f3Ssthen } 156933707f3Ssthen 157933707f3Ssthen const char *event_get_method(void) 158933707f3Ssthen { 159933707f3Ssthen return "WSAWaitForMultipleEvents"; 160933707f3Ssthen } 161933707f3Ssthen 162933707f3Ssthen /** call timeouts handlers, and return how long to wait for next one or -1 */ 163933707f3Ssthen static void handle_timeouts(struct event_base* base, struct timeval* now, 164933707f3Ssthen struct timeval* wait) 165933707f3Ssthen { 166933707f3Ssthen struct event* p; 167933707f3Ssthen #ifndef S_SPLINT_S 168933707f3Ssthen wait->tv_sec = (time_t)-1; 169933707f3Ssthen #endif 170933707f3Ssthen verbose(VERB_CLIENT, "winsock_event handle_timeouts"); 171933707f3Ssthen 172*77079be7Ssthen while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) 173933707f3Ssthen !=RBTREE_NULL) { 174933707f3Ssthen #ifndef S_SPLINT_S 175933707f3Ssthen if(p->ev_timeout.tv_sec > now->tv_sec || 176933707f3Ssthen (p->ev_timeout.tv_sec==now->tv_sec && 177933707f3Ssthen p->ev_timeout.tv_usec > now->tv_usec)) { 178933707f3Ssthen /* there is a next larger timeout. wait for it */ 179933707f3Ssthen wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; 180933707f3Ssthen if(now->tv_usec > p->ev_timeout.tv_usec) { 181933707f3Ssthen wait->tv_sec--; 182933707f3Ssthen wait->tv_usec = 1000000 - (now->tv_usec - 183933707f3Ssthen p->ev_timeout.tv_usec); 184933707f3Ssthen } else { 185933707f3Ssthen wait->tv_usec = p->ev_timeout.tv_usec 186933707f3Ssthen - now->tv_usec; 187933707f3Ssthen } 1885d76a658Ssthen verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", 189229e174cSsthen (long long)wait->tv_sec, (int)wait->tv_usec); 190933707f3Ssthen return; 191933707f3Ssthen } 192933707f3Ssthen #endif 193933707f3Ssthen /* event times out, remove it */ 194933707f3Ssthen (void)rbtree_delete(base->times, p); 195933707f3Ssthen p->ev_events &= ~EV_TIMEOUT; 196933707f3Ssthen fptr_ok(fptr_whitelist_event(p->ev_callback)); 197933707f3Ssthen (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); 198933707f3Ssthen } 199933707f3Ssthen verbose(VERB_CLIENT, "winsock_event wait=(-1)"); 200933707f3Ssthen } 201933707f3Ssthen 202933707f3Ssthen /** handle is_signal events and see if signalled */ 203933707f3Ssthen static void handle_signal(struct event* ev) 204933707f3Ssthen { 205933707f3Ssthen DWORD ret; 206933707f3Ssthen log_assert(ev->is_signal && ev->hEvent); 207933707f3Ssthen /* see if the event is signalled */ 208933707f3Ssthen ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, 209933707f3Ssthen 0 /* return immediately */, 0 /* not alertable for IOcomple*/); 210933707f3Ssthen if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { 211933707f3Ssthen log_err("WSAWaitForMultipleEvents(signal) failed: %s", 212933707f3Ssthen wsa_strerror(WSAGetLastError())); 213933707f3Ssthen return; 214933707f3Ssthen } 215933707f3Ssthen if(ret == WSA_WAIT_TIMEOUT) { 216933707f3Ssthen /* not signalled */ 217933707f3Ssthen return; 218933707f3Ssthen } 219933707f3Ssthen 220933707f3Ssthen /* reset the signal */ 221933707f3Ssthen if(!WSAResetEvent(ev->hEvent)) 222933707f3Ssthen log_err("WSAResetEvent failed: %s", 223933707f3Ssthen wsa_strerror(WSAGetLastError())); 224933707f3Ssthen /* do the callback (which may set the signal again) */ 225933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback)); 226933707f3Ssthen (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); 227933707f3Ssthen } 228933707f3Ssthen 229933707f3Ssthen /** call select and callbacks for that */ 230933707f3Ssthen static int handle_select(struct event_base* base, struct timeval* wait) 231933707f3Ssthen { 232933707f3Ssthen DWORD timeout = 0; /* in milliseconds */ 233933707f3Ssthen DWORD ret; 234933707f3Ssthen struct event* eventlist[WSK_MAX_ITEMS]; 235933707f3Ssthen WSANETWORKEVENTS netev; 236933707f3Ssthen int i, numwait = 0, startidx = 0, was_timeout = 0; 237933707f3Ssthen int newstickies = 0; 238933707f3Ssthen struct timeval nultm; 239933707f3Ssthen 240933707f3Ssthen verbose(VERB_CLIENT, "winsock_event handle_select"); 241933707f3Ssthen 242933707f3Ssthen #ifndef S_SPLINT_S 243933707f3Ssthen if(wait->tv_sec==(time_t)-1) 244933707f3Ssthen wait = NULL; 245933707f3Ssthen if(wait) 246933707f3Ssthen timeout = wait->tv_sec*1000 + wait->tv_usec/1000; 247933707f3Ssthen if(base->tcp_stickies) { 248933707f3Ssthen wait = &nultm; 249933707f3Ssthen nultm.tv_sec = 0; 250933707f3Ssthen nultm.tv_usec = 0; 251933707f3Ssthen timeout = 0; /* no waiting, we have sticky events */ 252933707f3Ssthen } 253933707f3Ssthen #endif 254933707f3Ssthen 255933707f3Ssthen /* prepare event array */ 256933707f3Ssthen for(i=0; i<base->max; i++) { 257933707f3Ssthen if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) 258933707f3Ssthen continue; /* skip timer only events */ 259933707f3Ssthen eventlist[numwait] = base->items[i]; 260933707f3Ssthen base->waitfor[numwait++] = base->items[i]->hEvent; 261933707f3Ssthen if(numwait == WSK_MAX_ITEMS) 262933707f3Ssthen break; /* sanity check */ 263933707f3Ssthen } 264933707f3Ssthen log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); 265*77079be7Ssthen verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%s " 266*77079be7Ssthen "timeout=%d", base->max, numwait, (wait?"<wait>":"<null>"), 267*77079be7Ssthen (int)timeout); 268933707f3Ssthen 269933707f3Ssthen /* do the wait */ 270933707f3Ssthen if(numwait == 0) { 271933707f3Ssthen /* WSAWaitFor.. doesn't like 0 event objects */ 272933707f3Ssthen if(wait) { 273933707f3Ssthen Sleep(timeout); 274933707f3Ssthen } 275933707f3Ssthen was_timeout = 1; 276933707f3Ssthen } else { 277933707f3Ssthen ret = WSAWaitForMultipleEvents(numwait, base->waitfor, 278933707f3Ssthen 0 /* do not wait for all, just one will do */, 279933707f3Ssthen wait?timeout:WSA_INFINITE, 280933707f3Ssthen 0); /* we are not alertable (IO completion events) */ 281933707f3Ssthen if(ret == WSA_WAIT_IO_COMPLETION) { 282933707f3Ssthen log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); 283933707f3Ssthen return -1; 284933707f3Ssthen } else if(ret == WSA_WAIT_FAILED) { 285933707f3Ssthen log_err("WSAWaitForMultipleEvents failed: %s", 286933707f3Ssthen wsa_strerror(WSAGetLastError())); 287933707f3Ssthen return -1; 288933707f3Ssthen } else if(ret == WSA_WAIT_TIMEOUT) { 289933707f3Ssthen was_timeout = 1; 290933707f3Ssthen } else 291933707f3Ssthen startidx = ret - WSA_WAIT_EVENT_0; 292933707f3Ssthen } 293933707f3Ssthen verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", 294933707f3Ssthen was_timeout, startidx); 295933707f3Ssthen 296933707f3Ssthen /* get new time after wait */ 297933707f3Ssthen if(settime(base) < 0) 298933707f3Ssthen return -1; 299933707f3Ssthen 300933707f3Ssthen /* callbacks */ 301933707f3Ssthen if(base->tcp_stickies) 302933707f3Ssthen startidx = 0; /* process all events, some are sticky */ 303933707f3Ssthen for(i=startidx; i<numwait; i++) 304933707f3Ssthen eventlist[i]->just_checked = 1; 305933707f3Ssthen 306933707f3Ssthen verbose(VERB_CLIENT, "winsock_event signals"); 307933707f3Ssthen for(i=startidx; i<numwait; i++) { 308933707f3Ssthen if(!base->waitfor[i]) 309933707f3Ssthen continue; /* was deleted */ 310933707f3Ssthen if(eventlist[i]->is_signal) { 311933707f3Ssthen eventlist[i]->just_checked = 0; 312933707f3Ssthen handle_signal(eventlist[i]); 313933707f3Ssthen } 314933707f3Ssthen } 315933707f3Ssthen /* early exit - do not process network, exit quickly */ 316933707f3Ssthen if(base->need_to_exit) 317933707f3Ssthen return 0; 318933707f3Ssthen 319933707f3Ssthen verbose(VERB_CLIENT, "winsock_event net"); 320933707f3Ssthen for(i=startidx; i<numwait; i++) { 321933707f3Ssthen short bits = 0; 322933707f3Ssthen /* eventlist[i] fired */ 323933707f3Ssthen /* see if eventlist[i] is still valid and just checked from 324933707f3Ssthen * WSAWaitForEvents */ 325933707f3Ssthen if(!base->waitfor[i]) 326933707f3Ssthen continue; /* was deleted */ 327933707f3Ssthen if(!eventlist[i]->just_checked) 328933707f3Ssthen continue; /* added by other callback */ 329933707f3Ssthen if(eventlist[i]->is_signal) 330933707f3Ssthen continue; /* not a network event at all */ 331933707f3Ssthen eventlist[i]->just_checked = 0; 332933707f3Ssthen 333933707f3Ssthen if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, 334933707f3Ssthen base->waitfor[i], /* reset the event handle */ 335933707f3Ssthen /*NULL,*/ /* do not reset the event handle */ 336933707f3Ssthen &netev) != 0) { 337933707f3Ssthen log_err("WSAEnumNetworkEvents failed: %s", 338933707f3Ssthen wsa_strerror(WSAGetLastError())); 339933707f3Ssthen return -1; 340933707f3Ssthen } 341933707f3Ssthen if((netev.lNetworkEvents & FD_READ)) { 342933707f3Ssthen if(netev.iErrorCode[FD_READ_BIT] != 0) 343933707f3Ssthen verbose(VERB_ALGO, "FD_READ_BIT error: %s", 344933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_READ_BIT])); 345933707f3Ssthen bits |= EV_READ; 346933707f3Ssthen } 347933707f3Ssthen if((netev.lNetworkEvents & FD_WRITE)) { 348933707f3Ssthen if(netev.iErrorCode[FD_WRITE_BIT] != 0) 349933707f3Ssthen verbose(VERB_ALGO, "FD_WRITE_BIT error: %s", 350933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); 351933707f3Ssthen bits |= EV_WRITE; 352933707f3Ssthen } 353933707f3Ssthen if((netev.lNetworkEvents & FD_CONNECT)) { 354933707f3Ssthen if(netev.iErrorCode[FD_CONNECT_BIT] != 0) 355933707f3Ssthen verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s", 356933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); 357933707f3Ssthen bits |= EV_READ; 358933707f3Ssthen bits |= EV_WRITE; 359933707f3Ssthen } 360933707f3Ssthen if((netev.lNetworkEvents & FD_ACCEPT)) { 361933707f3Ssthen if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) 362933707f3Ssthen verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s", 363933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); 364933707f3Ssthen bits |= EV_READ; 365933707f3Ssthen } 366933707f3Ssthen if((netev.lNetworkEvents & FD_CLOSE)) { 367933707f3Ssthen if(netev.iErrorCode[FD_CLOSE_BIT] != 0) 368933707f3Ssthen verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s", 369933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); 370933707f3Ssthen bits |= EV_READ; 371933707f3Ssthen bits |= EV_WRITE; 372933707f3Ssthen } 373933707f3Ssthen if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { 374933707f3Ssthen verbose(VERB_ALGO, "winsock %d pass sticky %s%s", 375933707f3Ssthen eventlist[i]->ev_fd, 376933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 377933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 378933707f3Ssthen bits |= eventlist[i]->old_events; 379933707f3Ssthen } 380933707f3Ssthen if(eventlist[i]->is_tcp && bits) { 381933707f3Ssthen eventlist[i]->old_events = bits; 382933707f3Ssthen eventlist[i]->stick_events = 1; 383933707f3Ssthen if((eventlist[i]->ev_events & bits)) { 384933707f3Ssthen newstickies = 1; 385933707f3Ssthen } 386933707f3Ssthen verbose(VERB_ALGO, "winsock %d store sticky %s%s", 387933707f3Ssthen eventlist[i]->ev_fd, 388933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 389933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 390933707f3Ssthen } 391933707f3Ssthen if((bits & eventlist[i]->ev_events)) { 392933707f3Ssthen verbose(VERB_ALGO, "winsock event callback %p fd=%d " 393933707f3Ssthen "%s%s%s%s%s ; %s%s%s", 394933707f3Ssthen eventlist[i], eventlist[i]->ev_fd, 395933707f3Ssthen (netev.lNetworkEvents&FD_READ)?" FD_READ":"", 396933707f3Ssthen (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", 397933707f3Ssthen (netev.lNetworkEvents&FD_CONNECT)? 398933707f3Ssthen " FD_CONNECT":"", 399933707f3Ssthen (netev.lNetworkEvents&FD_ACCEPT)? 400933707f3Ssthen " FD_ACCEPT":"", 401933707f3Ssthen (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", 402933707f3Ssthen (bits&EV_READ)?" EV_READ":"", 403933707f3Ssthen (bits&EV_WRITE)?" EV_WRITE":"", 404933707f3Ssthen (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); 405933707f3Ssthen 406933707f3Ssthen fptr_ok(fptr_whitelist_event( 407933707f3Ssthen eventlist[i]->ev_callback)); 408933707f3Ssthen (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, 409933707f3Ssthen bits & eventlist[i]->ev_events, 410933707f3Ssthen eventlist[i]->ev_arg); 411933707f3Ssthen } 412933707f3Ssthen if(eventlist[i]->is_tcp && bits) 413933707f3Ssthen verbose(VERB_ALGO, "winsock %d got sticky %s%s", 414933707f3Ssthen eventlist[i]->ev_fd, 415933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 416933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 417933707f3Ssthen } 418933707f3Ssthen verbose(VERB_CLIENT, "winsock_event net"); 419933707f3Ssthen if(base->tcp_reinvigorated) { 420933707f3Ssthen verbose(VERB_CLIENT, "winsock_event reinvigorated"); 421933707f3Ssthen base->tcp_reinvigorated = 0; 422933707f3Ssthen newstickies = 1; 423933707f3Ssthen } 424933707f3Ssthen base->tcp_stickies = newstickies; 425933707f3Ssthen verbose(VERB_CLIENT, "winsock_event handle_select end"); 426933707f3Ssthen return 0; 427933707f3Ssthen } 428933707f3Ssthen 429933707f3Ssthen int event_base_dispatch(struct event_base *base) 430933707f3Ssthen { 431933707f3Ssthen struct timeval wait; 432933707f3Ssthen if(settime(base) < 0) 433933707f3Ssthen return -1; 434933707f3Ssthen while(!base->need_to_exit) 435933707f3Ssthen { 436933707f3Ssthen /* see if timeouts need handling */ 437933707f3Ssthen handle_timeouts(base, base->time_tv, &wait); 438933707f3Ssthen if(base->need_to_exit) 439933707f3Ssthen return 0; 440933707f3Ssthen /* do select */ 441933707f3Ssthen if(handle_select(base, &wait) < 0) { 442933707f3Ssthen if(base->need_to_exit) 443933707f3Ssthen return 0; 444933707f3Ssthen return -1; 445933707f3Ssthen } 446933707f3Ssthen } 447933707f3Ssthen return 0; 448933707f3Ssthen } 449933707f3Ssthen 450933707f3Ssthen int event_base_loopexit(struct event_base *base, 451933707f3Ssthen struct timeval * ATTR_UNUSED(tv)) 452933707f3Ssthen { 453933707f3Ssthen verbose(VERB_CLIENT, "winsock_event loopexit"); 454933707f3Ssthen base->need_to_exit = 1; 455933707f3Ssthen return 0; 456933707f3Ssthen } 457933707f3Ssthen 458933707f3Ssthen void event_base_free(struct event_base *base) 459933707f3Ssthen { 460933707f3Ssthen verbose(VERB_CLIENT, "winsock_event event_base_free"); 461933707f3Ssthen if(!base) 462933707f3Ssthen return; 463933707f3Ssthen free(base->items); 464933707f3Ssthen free(base->times); 465933707f3Ssthen free(base->signals); 466933707f3Ssthen free(base); 467933707f3Ssthen } 468933707f3Ssthen 469933707f3Ssthen void event_set(struct event *ev, int fd, short bits, 470933707f3Ssthen void (*cb)(int, short, void *), void *arg) 471933707f3Ssthen { 472933707f3Ssthen ev->node.key = ev; 473933707f3Ssthen ev->ev_fd = fd; 474933707f3Ssthen ev->ev_events = bits; 475933707f3Ssthen ev->ev_callback = cb; 476933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback)); 477933707f3Ssthen ev->ev_arg = arg; 478933707f3Ssthen ev->just_checked = 0; 479933707f3Ssthen ev->added = 0; 480933707f3Ssthen } 481933707f3Ssthen 482933707f3Ssthen int event_base_set(struct event_base *base, struct event *ev) 483933707f3Ssthen { 484933707f3Ssthen ev->ev_base = base; 485933707f3Ssthen ev->old_events = 0; 486933707f3Ssthen ev->stick_events = 0; 487933707f3Ssthen ev->added = 0; 488933707f3Ssthen return 0; 489933707f3Ssthen } 490933707f3Ssthen 491933707f3Ssthen int event_add(struct event *ev, struct timeval *tv) 492933707f3Ssthen { 4935d76a658Ssthen verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 494933707f3Ssthen ev, ev->added, ev->ev_fd, 495229e174cSsthen (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), 496933707f3Ssthen (ev->ev_events&EV_READ)?" EV_READ":"", 497933707f3Ssthen (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 498933707f3Ssthen (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 499933707f3Ssthen if(ev->added) 500933707f3Ssthen event_del(ev); 501933707f3Ssthen log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1); 502933707f3Ssthen ev->is_tcp = 0; 503933707f3Ssthen ev->is_signal = 0; 504933707f3Ssthen ev->just_checked = 0; 505933707f3Ssthen 506933707f3Ssthen if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 507933707f3Ssthen BOOL b=0; 508933707f3Ssthen int t, l; 509933707f3Ssthen long events = 0; 510933707f3Ssthen 511933707f3Ssthen if(ev->ev_base->max == ev->ev_base->cap) 512933707f3Ssthen return -1; 513933707f3Ssthen ev->idx = ev->ev_base->max++; 514933707f3Ssthen ev->ev_base->items[ev->idx] = ev; 515933707f3Ssthen 516933707f3Ssthen if( (ev->ev_events&EV_READ) ) 517933707f3Ssthen events |= FD_READ; 518933707f3Ssthen if( (ev->ev_events&EV_WRITE) ) 519933707f3Ssthen events |= FD_WRITE; 520933707f3Ssthen l = sizeof(t); 521933707f3Ssthen if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, 522933707f3Ssthen (void*)&t, &l) != 0) 523933707f3Ssthen log_err("getsockopt(SO_TYPE) failed: %s", 524933707f3Ssthen wsa_strerror(WSAGetLastError())); 525933707f3Ssthen if(t == SOCK_STREAM) { 526933707f3Ssthen /* TCP socket */ 527933707f3Ssthen ev->is_tcp = 1; 528933707f3Ssthen events |= FD_CLOSE; 529933707f3Ssthen if( (ev->ev_events&EV_WRITE) ) 530933707f3Ssthen events |= FD_CONNECT; 531933707f3Ssthen l = sizeof(b); 532933707f3Ssthen if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, 533933707f3Ssthen (void*)&b, &l) != 0) 534933707f3Ssthen log_err("getsockopt(SO_ACCEPTCONN) failed: %s", 535933707f3Ssthen wsa_strerror(WSAGetLastError())); 536933707f3Ssthen if(b) /* TCP accept socket */ 537933707f3Ssthen events |= FD_ACCEPT; 538933707f3Ssthen } 539933707f3Ssthen ev->hEvent = WSACreateEvent(); 540933707f3Ssthen if(ev->hEvent == WSA_INVALID_EVENT) 541933707f3Ssthen log_err("WSACreateEvent failed: %s", 542933707f3Ssthen wsa_strerror(WSAGetLastError())); 543933707f3Ssthen /* automatically sets fd to nonblocking mode. 544933707f3Ssthen * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ 545933707f3Ssthen if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { 546933707f3Ssthen log_err("WSAEventSelect failed: %s", 547933707f3Ssthen wsa_strerror(WSAGetLastError())); 548933707f3Ssthen } 549933707f3Ssthen if(ev->is_tcp && ev->stick_events && 550933707f3Ssthen (ev->ev_events & ev->old_events)) { 551933707f3Ssthen /* go to processing the sticky event right away */ 552933707f3Ssthen ev->ev_base->tcp_reinvigorated = 1; 553933707f3Ssthen } 554933707f3Ssthen } 555933707f3Ssthen 556933707f3Ssthen if(tv && (ev->ev_events&EV_TIMEOUT)) { 557933707f3Ssthen #ifndef S_SPLINT_S 558933707f3Ssthen struct timeval *now = ev->ev_base->time_tv; 559933707f3Ssthen ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 560933707f3Ssthen ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 561933707f3Ssthen while(ev->ev_timeout.tv_usec > 1000000) { 562933707f3Ssthen ev->ev_timeout.tv_usec -= 1000000; 563933707f3Ssthen ev->ev_timeout.tv_sec++; 564933707f3Ssthen } 565933707f3Ssthen #endif 566933707f3Ssthen (void)rbtree_insert(ev->ev_base->times, &ev->node); 567933707f3Ssthen } 568933707f3Ssthen ev->added = 1; 569933707f3Ssthen return 0; 570933707f3Ssthen } 571933707f3Ssthen 572933707f3Ssthen int event_del(struct event *ev) 573933707f3Ssthen { 5745d76a658Ssthen verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 575933707f3Ssthen ev, ev->added, ev->ev_fd, 576229e174cSsthen (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ 577229e174cSsthen (long long)ev->ev_timeout.tv_usec/1000:-1, 578933707f3Ssthen (ev->ev_events&EV_READ)?" EV_READ":"", 579933707f3Ssthen (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 580933707f3Ssthen (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 581933707f3Ssthen if(!ev->added) 582933707f3Ssthen return 0; 583933707f3Ssthen log_assert(ev->added); 584933707f3Ssthen if((ev->ev_events&EV_TIMEOUT)) 585933707f3Ssthen (void)rbtree_delete(ev->ev_base->times, &ev->node); 586933707f3Ssthen if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 587933707f3Ssthen log_assert(ev->ev_base->max > 0); 588933707f3Ssthen /* remove item and compact the list */ 589933707f3Ssthen ev->ev_base->items[ev->idx] = 590933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1]; 591933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1] = NULL; 592933707f3Ssthen ev->ev_base->max--; 593933707f3Ssthen if(ev->idx < ev->ev_base->max) 594933707f3Ssthen ev->ev_base->items[ev->idx]->idx = ev->idx; 595933707f3Ssthen zero_waitfor(ev->ev_base->waitfor, ev->hEvent); 596933707f3Ssthen 597933707f3Ssthen if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) 598933707f3Ssthen log_err("WSAEventSelect(disable) failed: %s", 599933707f3Ssthen wsa_strerror(WSAGetLastError())); 600933707f3Ssthen if(!WSACloseEvent(ev->hEvent)) 601933707f3Ssthen log_err("WSACloseEvent failed: %s", 602933707f3Ssthen wsa_strerror(WSAGetLastError())); 603933707f3Ssthen } 604933707f3Ssthen ev->just_checked = 0; 605933707f3Ssthen ev->added = 0; 606933707f3Ssthen return 0; 607933707f3Ssthen } 608933707f3Ssthen 609933707f3Ssthen /** which base gets to handle signals */ 610933707f3Ssthen static struct event_base* signal_base = NULL; 611933707f3Ssthen /** signal handler */ 612933707f3Ssthen static RETSIGTYPE sigh(int sig) 613933707f3Ssthen { 614933707f3Ssthen struct event* ev; 615933707f3Ssthen if(!signal_base || sig < 0 || sig >= MAX_SIG) 616933707f3Ssthen return; 617933707f3Ssthen ev = signal_base->signals[sig]; 618933707f3Ssthen if(!ev) 619933707f3Ssthen return; 620933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback)); 621933707f3Ssthen (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 622933707f3Ssthen } 623933707f3Ssthen 624933707f3Ssthen int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv)) 625933707f3Ssthen { 626933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 627933707f3Ssthen return -1; 628933707f3Ssthen signal_base = ev->ev_base; 629933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = ev; 630933707f3Ssthen ev->added = 1; 631933707f3Ssthen if(signal(ev->ev_fd, sigh) == SIG_ERR) { 632933707f3Ssthen return -1; 633933707f3Ssthen } 634933707f3Ssthen return 0; 635933707f3Ssthen } 636933707f3Ssthen 637933707f3Ssthen int signal_del(struct event *ev) 638933707f3Ssthen { 639933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 640933707f3Ssthen return -1; 641933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = NULL; 642933707f3Ssthen ev->added = 0; 643933707f3Ssthen return 0; 644933707f3Ssthen } 645933707f3Ssthen 646933707f3Ssthen void winsock_tcp_wouldblock(struct event* ev, int eventbits) 647933707f3Ssthen { 648933707f3Ssthen verbose(VERB_ALGO, "winsock: tcp wouldblock %s", 649933707f3Ssthen eventbits==EV_READ?"EV_READ":"EV_WRITE"); 650933707f3Ssthen ev->old_events &= (~eventbits); 651933707f3Ssthen if(ev->old_events == 0) 652933707f3Ssthen ev->stick_events = 0; 653933707f3Ssthen /* in case this is the last sticky event, we could 654933707f3Ssthen * possibly run an empty handler loop to reset the base 655933707f3Ssthen * tcp_stickies variable 656933707f3Ssthen */ 657933707f3Ssthen } 658933707f3Ssthen 659933707f3Ssthen int winsock_register_wsaevent(struct event_base* base, struct event* ev, 660933707f3Ssthen WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) 661933707f3Ssthen { 662933707f3Ssthen if(base->max == base->cap) 663933707f3Ssthen return 0; 664933707f3Ssthen memset(ev, 0, sizeof(*ev)); 665933707f3Ssthen ev->ev_fd = -1; 666933707f3Ssthen ev->ev_events = EV_READ; 667933707f3Ssthen ev->ev_callback = cb; 668933707f3Ssthen ev->ev_arg = arg; 669933707f3Ssthen ev->is_signal = 1; 670933707f3Ssthen ev->hEvent = wsaevent; 671933707f3Ssthen ev->added = 1; 672933707f3Ssthen ev->ev_base = base; 673933707f3Ssthen ev->idx = ev->ev_base->max++; 674933707f3Ssthen ev->ev_base->items[ev->idx] = ev; 675933707f3Ssthen return 1; 676933707f3Ssthen } 677933707f3Ssthen 678933707f3Ssthen void winsock_unregister_wsaevent(struct event* ev) 679933707f3Ssthen { 680933707f3Ssthen if(!ev || !ev->added) return; 681933707f3Ssthen log_assert(ev->added && ev->ev_base->max > 0) 682933707f3Ssthen /* remove item and compact the list */ 683933707f3Ssthen ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; 684933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1] = NULL; 685933707f3Ssthen ev->ev_base->max--; 686933707f3Ssthen if(ev->idx < ev->ev_base->max) 687933707f3Ssthen ev->ev_base->items[ev->idx]->idx = ev->idx; 688933707f3Ssthen ev->added = 0; 689933707f3Ssthen } 690933707f3Ssthen 691933707f3Ssthen #else /* USE_WINSOCK */ 692933707f3Ssthen /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ 693933707f3Ssthen int winsock_unused_symbol = 1; 694933707f3Ssthen #endif /* USE_WINSOCK */ 695