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 24*5d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25*5d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26*5d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27*5d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28*5d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29*5d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30*5d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31*5d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32*5d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33*5d76a658Ssthen * 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> 44*5d76a658Ssthen #ifdef HAVE_TIME_H 45*5d76a658Ssthen #include <time.h> 46*5d76a658Ssthen #endif 47*5d76a658Ssthen #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 172933707f3Ssthen while((rbnode_t*)(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 } 188*5d76a658Ssthen 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); 265933707f3Ssthen verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%x " 266933707f3Ssthen "timeout=%d", base->max, numwait, (int)wait, (int)timeout); 267933707f3Ssthen 268933707f3Ssthen /* do the wait */ 269933707f3Ssthen if(numwait == 0) { 270933707f3Ssthen /* WSAWaitFor.. doesn't like 0 event objects */ 271933707f3Ssthen if(wait) { 272933707f3Ssthen Sleep(timeout); 273933707f3Ssthen } 274933707f3Ssthen was_timeout = 1; 275933707f3Ssthen } else { 276933707f3Ssthen ret = WSAWaitForMultipleEvents(numwait, base->waitfor, 277933707f3Ssthen 0 /* do not wait for all, just one will do */, 278933707f3Ssthen wait?timeout:WSA_INFINITE, 279933707f3Ssthen 0); /* we are not alertable (IO completion events) */ 280933707f3Ssthen if(ret == WSA_WAIT_IO_COMPLETION) { 281933707f3Ssthen log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); 282933707f3Ssthen return -1; 283933707f3Ssthen } else if(ret == WSA_WAIT_FAILED) { 284933707f3Ssthen log_err("WSAWaitForMultipleEvents failed: %s", 285933707f3Ssthen wsa_strerror(WSAGetLastError())); 286933707f3Ssthen return -1; 287933707f3Ssthen } else if(ret == WSA_WAIT_TIMEOUT) { 288933707f3Ssthen was_timeout = 1; 289933707f3Ssthen } else 290933707f3Ssthen startidx = ret - WSA_WAIT_EVENT_0; 291933707f3Ssthen } 292933707f3Ssthen verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", 293933707f3Ssthen was_timeout, startidx); 294933707f3Ssthen 295933707f3Ssthen /* get new time after wait */ 296933707f3Ssthen if(settime(base) < 0) 297933707f3Ssthen return -1; 298933707f3Ssthen 299933707f3Ssthen /* callbacks */ 300933707f3Ssthen if(base->tcp_stickies) 301933707f3Ssthen startidx = 0; /* process all events, some are sticky */ 302933707f3Ssthen for(i=startidx; i<numwait; i++) 303933707f3Ssthen eventlist[i]->just_checked = 1; 304933707f3Ssthen 305933707f3Ssthen verbose(VERB_CLIENT, "winsock_event signals"); 306933707f3Ssthen for(i=startidx; i<numwait; i++) { 307933707f3Ssthen if(!base->waitfor[i]) 308933707f3Ssthen continue; /* was deleted */ 309933707f3Ssthen if(eventlist[i]->is_signal) { 310933707f3Ssthen eventlist[i]->just_checked = 0; 311933707f3Ssthen handle_signal(eventlist[i]); 312933707f3Ssthen } 313933707f3Ssthen } 314933707f3Ssthen /* early exit - do not process network, exit quickly */ 315933707f3Ssthen if(base->need_to_exit) 316933707f3Ssthen return 0; 317933707f3Ssthen 318933707f3Ssthen verbose(VERB_CLIENT, "winsock_event net"); 319933707f3Ssthen for(i=startidx; i<numwait; i++) { 320933707f3Ssthen short bits = 0; 321933707f3Ssthen /* eventlist[i] fired */ 322933707f3Ssthen /* see if eventlist[i] is still valid and just checked from 323933707f3Ssthen * WSAWaitForEvents */ 324933707f3Ssthen if(!base->waitfor[i]) 325933707f3Ssthen continue; /* was deleted */ 326933707f3Ssthen if(!eventlist[i]->just_checked) 327933707f3Ssthen continue; /* added by other callback */ 328933707f3Ssthen if(eventlist[i]->is_signal) 329933707f3Ssthen continue; /* not a network event at all */ 330933707f3Ssthen eventlist[i]->just_checked = 0; 331933707f3Ssthen 332933707f3Ssthen if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, 333933707f3Ssthen base->waitfor[i], /* reset the event handle */ 334933707f3Ssthen /*NULL,*/ /* do not reset the event handle */ 335933707f3Ssthen &netev) != 0) { 336933707f3Ssthen log_err("WSAEnumNetworkEvents failed: %s", 337933707f3Ssthen wsa_strerror(WSAGetLastError())); 338933707f3Ssthen return -1; 339933707f3Ssthen } 340933707f3Ssthen if((netev.lNetworkEvents & FD_READ)) { 341933707f3Ssthen if(netev.iErrorCode[FD_READ_BIT] != 0) 342933707f3Ssthen verbose(VERB_ALGO, "FD_READ_BIT error: %s", 343933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_READ_BIT])); 344933707f3Ssthen bits |= EV_READ; 345933707f3Ssthen } 346933707f3Ssthen if((netev.lNetworkEvents & FD_WRITE)) { 347933707f3Ssthen if(netev.iErrorCode[FD_WRITE_BIT] != 0) 348933707f3Ssthen verbose(VERB_ALGO, "FD_WRITE_BIT error: %s", 349933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); 350933707f3Ssthen bits |= EV_WRITE; 351933707f3Ssthen } 352933707f3Ssthen if((netev.lNetworkEvents & FD_CONNECT)) { 353933707f3Ssthen if(netev.iErrorCode[FD_CONNECT_BIT] != 0) 354933707f3Ssthen verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s", 355933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); 356933707f3Ssthen bits |= EV_READ; 357933707f3Ssthen bits |= EV_WRITE; 358933707f3Ssthen } 359933707f3Ssthen if((netev.lNetworkEvents & FD_ACCEPT)) { 360933707f3Ssthen if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) 361933707f3Ssthen verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s", 362933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); 363933707f3Ssthen bits |= EV_READ; 364933707f3Ssthen } 365933707f3Ssthen if((netev.lNetworkEvents & FD_CLOSE)) { 366933707f3Ssthen if(netev.iErrorCode[FD_CLOSE_BIT] != 0) 367933707f3Ssthen verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s", 368933707f3Ssthen wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); 369933707f3Ssthen bits |= EV_READ; 370933707f3Ssthen bits |= EV_WRITE; 371933707f3Ssthen } 372933707f3Ssthen if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { 373933707f3Ssthen verbose(VERB_ALGO, "winsock %d pass sticky %s%s", 374933707f3Ssthen eventlist[i]->ev_fd, 375933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 376933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 377933707f3Ssthen bits |= eventlist[i]->old_events; 378933707f3Ssthen } 379933707f3Ssthen if(eventlist[i]->is_tcp && bits) { 380933707f3Ssthen eventlist[i]->old_events = bits; 381933707f3Ssthen eventlist[i]->stick_events = 1; 382933707f3Ssthen if((eventlist[i]->ev_events & bits)) { 383933707f3Ssthen newstickies = 1; 384933707f3Ssthen } 385933707f3Ssthen verbose(VERB_ALGO, "winsock %d store sticky %s%s", 386933707f3Ssthen eventlist[i]->ev_fd, 387933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 388933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 389933707f3Ssthen } 390933707f3Ssthen if((bits & eventlist[i]->ev_events)) { 391933707f3Ssthen verbose(VERB_ALGO, "winsock event callback %p fd=%d " 392933707f3Ssthen "%s%s%s%s%s ; %s%s%s", 393933707f3Ssthen eventlist[i], eventlist[i]->ev_fd, 394933707f3Ssthen (netev.lNetworkEvents&FD_READ)?" FD_READ":"", 395933707f3Ssthen (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", 396933707f3Ssthen (netev.lNetworkEvents&FD_CONNECT)? 397933707f3Ssthen " FD_CONNECT":"", 398933707f3Ssthen (netev.lNetworkEvents&FD_ACCEPT)? 399933707f3Ssthen " FD_ACCEPT":"", 400933707f3Ssthen (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", 401933707f3Ssthen (bits&EV_READ)?" EV_READ":"", 402933707f3Ssthen (bits&EV_WRITE)?" EV_WRITE":"", 403933707f3Ssthen (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); 404933707f3Ssthen 405933707f3Ssthen fptr_ok(fptr_whitelist_event( 406933707f3Ssthen eventlist[i]->ev_callback)); 407933707f3Ssthen (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, 408933707f3Ssthen bits & eventlist[i]->ev_events, 409933707f3Ssthen eventlist[i]->ev_arg); 410933707f3Ssthen } 411933707f3Ssthen if(eventlist[i]->is_tcp && bits) 412933707f3Ssthen verbose(VERB_ALGO, "winsock %d got sticky %s%s", 413933707f3Ssthen eventlist[i]->ev_fd, 414933707f3Ssthen (eventlist[i]->old_events&EV_READ)?"EV_READ":"", 415933707f3Ssthen (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); 416933707f3Ssthen } 417933707f3Ssthen verbose(VERB_CLIENT, "winsock_event net"); 418933707f3Ssthen if(base->tcp_reinvigorated) { 419933707f3Ssthen verbose(VERB_CLIENT, "winsock_event reinvigorated"); 420933707f3Ssthen base->tcp_reinvigorated = 0; 421933707f3Ssthen newstickies = 1; 422933707f3Ssthen } 423933707f3Ssthen base->tcp_stickies = newstickies; 424933707f3Ssthen verbose(VERB_CLIENT, "winsock_event handle_select end"); 425933707f3Ssthen return 0; 426933707f3Ssthen } 427933707f3Ssthen 428933707f3Ssthen int event_base_dispatch(struct event_base *base) 429933707f3Ssthen { 430933707f3Ssthen struct timeval wait; 431933707f3Ssthen if(settime(base) < 0) 432933707f3Ssthen return -1; 433933707f3Ssthen while(!base->need_to_exit) 434933707f3Ssthen { 435933707f3Ssthen /* see if timeouts need handling */ 436933707f3Ssthen handle_timeouts(base, base->time_tv, &wait); 437933707f3Ssthen if(base->need_to_exit) 438933707f3Ssthen return 0; 439933707f3Ssthen /* do select */ 440933707f3Ssthen if(handle_select(base, &wait) < 0) { 441933707f3Ssthen if(base->need_to_exit) 442933707f3Ssthen return 0; 443933707f3Ssthen return -1; 444933707f3Ssthen } 445933707f3Ssthen } 446933707f3Ssthen return 0; 447933707f3Ssthen } 448933707f3Ssthen 449933707f3Ssthen int event_base_loopexit(struct event_base *base, 450933707f3Ssthen struct timeval * ATTR_UNUSED(tv)) 451933707f3Ssthen { 452933707f3Ssthen verbose(VERB_CLIENT, "winsock_event loopexit"); 453933707f3Ssthen base->need_to_exit = 1; 454933707f3Ssthen return 0; 455933707f3Ssthen } 456933707f3Ssthen 457933707f3Ssthen void event_base_free(struct event_base *base) 458933707f3Ssthen { 459933707f3Ssthen verbose(VERB_CLIENT, "winsock_event event_base_free"); 460933707f3Ssthen if(!base) 461933707f3Ssthen return; 462933707f3Ssthen if(base->items) 463933707f3Ssthen free(base->items); 464933707f3Ssthen if(base->times) 465933707f3Ssthen free(base->times); 466933707f3Ssthen if(base->signals) 467933707f3Ssthen free(base->signals); 468933707f3Ssthen free(base); 469933707f3Ssthen } 470933707f3Ssthen 471933707f3Ssthen void event_set(struct event *ev, int fd, short bits, 472933707f3Ssthen void (*cb)(int, short, void *), void *arg) 473933707f3Ssthen { 474933707f3Ssthen ev->node.key = ev; 475933707f3Ssthen ev->ev_fd = fd; 476933707f3Ssthen ev->ev_events = bits; 477933707f3Ssthen ev->ev_callback = cb; 478933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback)); 479933707f3Ssthen ev->ev_arg = arg; 480933707f3Ssthen ev->just_checked = 0; 481933707f3Ssthen ev->added = 0; 482933707f3Ssthen } 483933707f3Ssthen 484933707f3Ssthen int event_base_set(struct event_base *base, struct event *ev) 485933707f3Ssthen { 486933707f3Ssthen ev->ev_base = base; 487933707f3Ssthen ev->old_events = 0; 488933707f3Ssthen ev->stick_events = 0; 489933707f3Ssthen ev->added = 0; 490933707f3Ssthen return 0; 491933707f3Ssthen } 492933707f3Ssthen 493933707f3Ssthen int event_add(struct event *ev, struct timeval *tv) 494933707f3Ssthen { 495*5d76a658Ssthen verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 496933707f3Ssthen ev, ev->added, ev->ev_fd, 497229e174cSsthen (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), 498933707f3Ssthen (ev->ev_events&EV_READ)?" EV_READ":"", 499933707f3Ssthen (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 500933707f3Ssthen (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 501933707f3Ssthen if(ev->added) 502933707f3Ssthen event_del(ev); 503933707f3Ssthen log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1); 504933707f3Ssthen ev->is_tcp = 0; 505933707f3Ssthen ev->is_signal = 0; 506933707f3Ssthen ev->just_checked = 0; 507933707f3Ssthen 508933707f3Ssthen if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 509933707f3Ssthen BOOL b=0; 510933707f3Ssthen int t, l; 511933707f3Ssthen long events = 0; 512933707f3Ssthen 513933707f3Ssthen if(ev->ev_base->max == ev->ev_base->cap) 514933707f3Ssthen return -1; 515933707f3Ssthen ev->idx = ev->ev_base->max++; 516933707f3Ssthen ev->ev_base->items[ev->idx] = ev; 517933707f3Ssthen 518933707f3Ssthen if( (ev->ev_events&EV_READ) ) 519933707f3Ssthen events |= FD_READ; 520933707f3Ssthen if( (ev->ev_events&EV_WRITE) ) 521933707f3Ssthen events |= FD_WRITE; 522933707f3Ssthen l = sizeof(t); 523933707f3Ssthen if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, 524933707f3Ssthen (void*)&t, &l) != 0) 525933707f3Ssthen log_err("getsockopt(SO_TYPE) failed: %s", 526933707f3Ssthen wsa_strerror(WSAGetLastError())); 527933707f3Ssthen if(t == SOCK_STREAM) { 528933707f3Ssthen /* TCP socket */ 529933707f3Ssthen ev->is_tcp = 1; 530933707f3Ssthen events |= FD_CLOSE; 531933707f3Ssthen if( (ev->ev_events&EV_WRITE) ) 532933707f3Ssthen events |= FD_CONNECT; 533933707f3Ssthen l = sizeof(b); 534933707f3Ssthen if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, 535933707f3Ssthen (void*)&b, &l) != 0) 536933707f3Ssthen log_err("getsockopt(SO_ACCEPTCONN) failed: %s", 537933707f3Ssthen wsa_strerror(WSAGetLastError())); 538933707f3Ssthen if(b) /* TCP accept socket */ 539933707f3Ssthen events |= FD_ACCEPT; 540933707f3Ssthen } 541933707f3Ssthen ev->hEvent = WSACreateEvent(); 542933707f3Ssthen if(ev->hEvent == WSA_INVALID_EVENT) 543933707f3Ssthen log_err("WSACreateEvent failed: %s", 544933707f3Ssthen wsa_strerror(WSAGetLastError())); 545933707f3Ssthen /* automatically sets fd to nonblocking mode. 546933707f3Ssthen * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ 547933707f3Ssthen if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { 548933707f3Ssthen log_err("WSAEventSelect failed: %s", 549933707f3Ssthen wsa_strerror(WSAGetLastError())); 550933707f3Ssthen } 551933707f3Ssthen if(ev->is_tcp && ev->stick_events && 552933707f3Ssthen (ev->ev_events & ev->old_events)) { 553933707f3Ssthen /* go to processing the sticky event right away */ 554933707f3Ssthen ev->ev_base->tcp_reinvigorated = 1; 555933707f3Ssthen } 556933707f3Ssthen } 557933707f3Ssthen 558933707f3Ssthen if(tv && (ev->ev_events&EV_TIMEOUT)) { 559933707f3Ssthen #ifndef S_SPLINT_S 560933707f3Ssthen struct timeval *now = ev->ev_base->time_tv; 561933707f3Ssthen ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; 562933707f3Ssthen ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; 563933707f3Ssthen while(ev->ev_timeout.tv_usec > 1000000) { 564933707f3Ssthen ev->ev_timeout.tv_usec -= 1000000; 565933707f3Ssthen ev->ev_timeout.tv_sec++; 566933707f3Ssthen } 567933707f3Ssthen #endif 568933707f3Ssthen (void)rbtree_insert(ev->ev_base->times, &ev->node); 569933707f3Ssthen } 570933707f3Ssthen ev->added = 1; 571933707f3Ssthen return 0; 572933707f3Ssthen } 573933707f3Ssthen 574933707f3Ssthen int event_del(struct event *ev) 575933707f3Ssthen { 576*5d76a658Ssthen verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 577933707f3Ssthen ev, ev->added, ev->ev_fd, 578229e174cSsthen (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ 579229e174cSsthen (long long)ev->ev_timeout.tv_usec/1000:-1, 580933707f3Ssthen (ev->ev_events&EV_READ)?" EV_READ":"", 581933707f3Ssthen (ev->ev_events&EV_WRITE)?" EV_WRITE":"", 582933707f3Ssthen (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); 583933707f3Ssthen if(!ev->added) 584933707f3Ssthen return 0; 585933707f3Ssthen log_assert(ev->added); 586933707f3Ssthen if((ev->ev_events&EV_TIMEOUT)) 587933707f3Ssthen (void)rbtree_delete(ev->ev_base->times, &ev->node); 588933707f3Ssthen if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { 589933707f3Ssthen log_assert(ev->ev_base->max > 0); 590933707f3Ssthen /* remove item and compact the list */ 591933707f3Ssthen ev->ev_base->items[ev->idx] = 592933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1]; 593933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1] = NULL; 594933707f3Ssthen ev->ev_base->max--; 595933707f3Ssthen if(ev->idx < ev->ev_base->max) 596933707f3Ssthen ev->ev_base->items[ev->idx]->idx = ev->idx; 597933707f3Ssthen zero_waitfor(ev->ev_base->waitfor, ev->hEvent); 598933707f3Ssthen 599933707f3Ssthen if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) 600933707f3Ssthen log_err("WSAEventSelect(disable) failed: %s", 601933707f3Ssthen wsa_strerror(WSAGetLastError())); 602933707f3Ssthen if(!WSACloseEvent(ev->hEvent)) 603933707f3Ssthen log_err("WSACloseEvent failed: %s", 604933707f3Ssthen wsa_strerror(WSAGetLastError())); 605933707f3Ssthen } 606933707f3Ssthen ev->just_checked = 0; 607933707f3Ssthen ev->added = 0; 608933707f3Ssthen return 0; 609933707f3Ssthen } 610933707f3Ssthen 611933707f3Ssthen /** which base gets to handle signals */ 612933707f3Ssthen static struct event_base* signal_base = NULL; 613933707f3Ssthen /** signal handler */ 614933707f3Ssthen static RETSIGTYPE sigh(int sig) 615933707f3Ssthen { 616933707f3Ssthen struct event* ev; 617933707f3Ssthen if(!signal_base || sig < 0 || sig >= MAX_SIG) 618933707f3Ssthen return; 619933707f3Ssthen ev = signal_base->signals[sig]; 620933707f3Ssthen if(!ev) 621933707f3Ssthen return; 622933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback)); 623933707f3Ssthen (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); 624933707f3Ssthen } 625933707f3Ssthen 626933707f3Ssthen int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv)) 627933707f3Ssthen { 628933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 629933707f3Ssthen return -1; 630933707f3Ssthen signal_base = ev->ev_base; 631933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = ev; 632933707f3Ssthen ev->added = 1; 633933707f3Ssthen if(signal(ev->ev_fd, sigh) == SIG_ERR) { 634933707f3Ssthen return -1; 635933707f3Ssthen } 636933707f3Ssthen return 0; 637933707f3Ssthen } 638933707f3Ssthen 639933707f3Ssthen int signal_del(struct event *ev) 640933707f3Ssthen { 641933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) 642933707f3Ssthen return -1; 643933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = NULL; 644933707f3Ssthen ev->added = 0; 645933707f3Ssthen return 0; 646933707f3Ssthen } 647933707f3Ssthen 648933707f3Ssthen void winsock_tcp_wouldblock(struct event* ev, int eventbits) 649933707f3Ssthen { 650933707f3Ssthen verbose(VERB_ALGO, "winsock: tcp wouldblock %s", 651933707f3Ssthen eventbits==EV_READ?"EV_READ":"EV_WRITE"); 652933707f3Ssthen ev->old_events &= (~eventbits); 653933707f3Ssthen if(ev->old_events == 0) 654933707f3Ssthen ev->stick_events = 0; 655933707f3Ssthen /* in case this is the last sticky event, we could 656933707f3Ssthen * possibly run an empty handler loop to reset the base 657933707f3Ssthen * tcp_stickies variable 658933707f3Ssthen */ 659933707f3Ssthen } 660933707f3Ssthen 661933707f3Ssthen int winsock_register_wsaevent(struct event_base* base, struct event* ev, 662933707f3Ssthen WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) 663933707f3Ssthen { 664933707f3Ssthen if(base->max == base->cap) 665933707f3Ssthen return 0; 666933707f3Ssthen memset(ev, 0, sizeof(*ev)); 667933707f3Ssthen ev->ev_fd = -1; 668933707f3Ssthen ev->ev_events = EV_READ; 669933707f3Ssthen ev->ev_callback = cb; 670933707f3Ssthen ev->ev_arg = arg; 671933707f3Ssthen ev->is_signal = 1; 672933707f3Ssthen ev->hEvent = wsaevent; 673933707f3Ssthen ev->added = 1; 674933707f3Ssthen ev->ev_base = base; 675933707f3Ssthen ev->idx = ev->ev_base->max++; 676933707f3Ssthen ev->ev_base->items[ev->idx] = ev; 677933707f3Ssthen return 1; 678933707f3Ssthen } 679933707f3Ssthen 680933707f3Ssthen void winsock_unregister_wsaevent(struct event* ev) 681933707f3Ssthen { 682933707f3Ssthen if(!ev || !ev->added) return; 683933707f3Ssthen log_assert(ev->added && ev->ev_base->max > 0) 684933707f3Ssthen /* remove item and compact the list */ 685933707f3Ssthen ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; 686933707f3Ssthen ev->ev_base->items[ev->ev_base->max-1] = NULL; 687933707f3Ssthen ev->ev_base->max--; 688933707f3Ssthen if(ev->idx < ev->ev_base->max) 689933707f3Ssthen ev->ev_base->items[ev->idx]->idx = ev->idx; 690933707f3Ssthen ev->added = 0; 691933707f3Ssthen } 692933707f3Ssthen 693933707f3Ssthen #else /* USE_WINSOCK */ 694933707f3Ssthen /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */ 695933707f3Ssthen int winsock_unused_symbol = 1; 696933707f3Ssthen #endif /* USE_WINSOCK */ 697