1933707f3Ssthen /* 2933707f3Ssthen * util/winsock_event.h - unbound event handling for winsock on windows 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 /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains interface functions with the WinSock2 API on Windows. 40933707f3Ssthen * It uses the winsock WSAWaitForMultipleEvents interface on a number of 41933707f3Ssthen * sockets. 42933707f3Ssthen * 43933707f3Ssthen * Note that windows can only wait for max 64 events at one time. 44933707f3Ssthen * 45933707f3Ssthen * Also, file descriptors cannot be waited for. 46933707f3Ssthen * 47933707f3Ssthen * Named pipes are not easily available (and are not usable in select() ). 48933707f3Ssthen * For interprocess communication, it is possible to wait for a hEvent to 49933707f3Ssthen * be signaled by another thread. 50933707f3Ssthen * 51933707f3Ssthen * When a socket becomes readable, then it will not be flagged as 52933707f3Ssthen * readable again until you have gotten WOULDBLOCK from a recv routine. 53933707f3Ssthen * That means the event handler must store the readability (edge notify) 54933707f3Ssthen * and process the incoming data until it blocks. 55933707f3Ssthen * The function performing recv then has to inform the event handler that 56933707f3Ssthen * the socket has blocked, and the event handler can mark it as such. 57933707f3Ssthen * Thus, this file transforms the edge notify from windows to a level notify 58933707f3Ssthen * that is compatible with UNIX. 59933707f3Ssthen * The WSAEventSelect page says that it does do level notify, as long 60933707f3Ssthen * as you call a recv/write/accept at least once when it is signalled. 61933707f3Ssthen * This last bit is not true, even though documented in server2008 api docs 62933707f3Ssthen * from microsoft, it does not happen at all. Instead you have to test for 63933707f3Ssthen * WSAEWOULDBLOCK on a tcp stream, and only then retest the socket. 64933707f3Ssthen * And before that remember the previous result as still valid. 65933707f3Ssthen * 66933707f3Ssthen * To stay 'fair', instead of emptying a socket completely, the event handler 67933707f3Ssthen * can test the other (marked as blocking) sockets for new events. 68933707f3Ssthen * 69933707f3Ssthen * Additionally, TCP accept sockets get special event support. 70933707f3Ssthen * 71933707f3Ssthen * Socket numbers are not starting small, they can be any number (say 33060). 72933707f3Ssthen * Therefore, bitmaps are not used, but arrays. 73933707f3Ssthen * 74933707f3Ssthen * on winsock, you must use recv() and send() for TCP reads and writes, 75933707f3Ssthen * not read() and write(), those work only on files. 76933707f3Ssthen * 77933707f3Ssthen * Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode. 78933707f3Ssthen * 79933707f3Ssthen * When under a high load windows gives out lots of errors, from recvfrom 80933707f3Ssthen * on udp sockets for example (WSAECONNRESET). Even though the udp socket 81933707f3Ssthen * has no connection per se. 82933707f3Ssthen */ 83933707f3Ssthen 84933707f3Ssthen #ifndef UTIL_WINSOCK_EVENT_H 85933707f3Ssthen #define UTIL_WINSOCK_EVENT_H 86933707f3Ssthen 87933707f3Ssthen #ifdef USE_WINSOCK 88933707f3Ssthen 89933707f3Ssthen #ifndef HAVE_EVENT_BASE_FREE 90933707f3Ssthen #define HAVE_EVENT_BASE_FREE 91933707f3Ssthen #endif 92933707f3Ssthen 9398f3ca02Sbrad /* redefine the calls to different names so that there is no name 9498f3ca02Sbrad * collision with other code that uses libevent names. (that uses libunbound)*/ 9598f3ca02Sbrad #define event_init winsockevent_init 9698f3ca02Sbrad #define event_get_version winsockevent_get_version 9798f3ca02Sbrad #define event_get_method winsockevent_get_method 9898f3ca02Sbrad #define event_base_dispatch winsockevent_base_dispatch 9998f3ca02Sbrad #define event_base_loopexit winsockevent_base_loopexit 10098f3ca02Sbrad #define event_base_free winsockevent_base_free 10198f3ca02Sbrad #define event_set winsockevent_set 10298f3ca02Sbrad #define event_base_set winsockevent_base_set 10398f3ca02Sbrad #define event_add winsockevent_add 10498f3ca02Sbrad #define event_del winsockevent_del 10598f3ca02Sbrad #define signal_add winsocksignal_add 10698f3ca02Sbrad #define signal_del winsocksignal_del 10798f3ca02Sbrad 108933707f3Ssthen /** event timeout */ 109933707f3Ssthen #define EV_TIMEOUT 0x01 110933707f3Ssthen /** event fd readable */ 111933707f3Ssthen #define EV_READ 0x02 112933707f3Ssthen /** event fd writable */ 113933707f3Ssthen #define EV_WRITE 0x04 114933707f3Ssthen /** event signal */ 115933707f3Ssthen #define EV_SIGNAL 0x08 116933707f3Ssthen /** event must persist */ 117933707f3Ssthen #define EV_PERSIST 0x10 118933707f3Ssthen 119933707f3Ssthen /* needs our redblack tree */ 120933707f3Ssthen #include "rbtree.h" 121933707f3Ssthen 122933707f3Ssthen /** max number of signals to support */ 123933707f3Ssthen #define MAX_SIG 32 124933707f3Ssthen 125933707f3Ssthen /** The number of items that the winsock event handler can service. 126933707f3Ssthen * Windows cannot handle more anyway */ 127933707f3Ssthen #define WSK_MAX_ITEMS 64 128933707f3Ssthen 129933707f3Ssthen /** 130933707f3Ssthen * event base for winsock event handler 131933707f3Ssthen */ 132933707f3Ssthen struct event_base 133933707f3Ssthen { 134933707f3Ssthen /** sorted by timeout (absolute), ptr */ 135*77079be7Ssthen rbtree_type* times; 136933707f3Ssthen /** array (first part in use) of handles to work on */ 137933707f3Ssthen struct event** items; 138933707f3Ssthen /** number of items in use in array */ 139933707f3Ssthen int max; 140933707f3Ssthen /** capacity of array, size of array in items */ 141933707f3Ssthen int cap; 142933707f3Ssthen /** array of 0 - maxsig of ptr to event for it */ 143933707f3Ssthen struct event** signals; 144933707f3Ssthen /** if we need to exit */ 145933707f3Ssthen int need_to_exit; 146933707f3Ssthen /** where to store time in seconds */ 147229e174cSsthen time_t* time_secs; 148933707f3Ssthen /** where to store time in microseconds */ 149933707f3Ssthen struct timeval* time_tv; 150933707f3Ssthen /** 151933707f3Ssthen * TCP streams have sticky events to them, these are not 152933707f3Ssthen * reported by the windows event system anymore, we have to 153933707f3Ssthen * keep reporting those events as present until wouldblock() is 154933707f3Ssthen * signalled by the handler back to use. 155933707f3Ssthen */ 156933707f3Ssthen int tcp_stickies; 157933707f3Ssthen /** 158933707f3Ssthen * should next cycle process reinvigorated stickies, 159933707f3Ssthen * these are stickies that have been stored, but due to a new 160933707f3Ssthen * event_add a sudden interest in the event has incepted. 161933707f3Ssthen */ 162933707f3Ssthen int tcp_reinvigorated; 163933707f3Ssthen /** The list of events that is currently being processed. */ 164933707f3Ssthen WSAEVENT waitfor[WSK_MAX_ITEMS]; 165933707f3Ssthen }; 166933707f3Ssthen 167933707f3Ssthen /** 168933707f3Ssthen * Event structure. Has some of the event elements. 169933707f3Ssthen */ 170933707f3Ssthen struct event { 171933707f3Ssthen /** node in timeout rbtree */ 172*77079be7Ssthen rbnode_type node; 173933707f3Ssthen /** is event already added */ 174933707f3Ssthen int added; 175933707f3Ssthen 176933707f3Ssthen /** event base it belongs to */ 177933707f3Ssthen struct event_base *ev_base; 178933707f3Ssthen /** fd to poll or -1 for timeouts. signal number for sigs. */ 179933707f3Ssthen int ev_fd; 180933707f3Ssthen /** what events this event is interested in, see EV_.. above. */ 181933707f3Ssthen short ev_events; 182933707f3Ssthen /** timeout value */ 183933707f3Ssthen struct timeval ev_timeout; 184933707f3Ssthen 185933707f3Ssthen /** callback to call: fd, eventbits, userarg */ 186933707f3Ssthen void (*ev_callback)(int, short, void *); 187933707f3Ssthen /** callback user arg */ 188933707f3Ssthen void *ev_arg; 189933707f3Ssthen 190933707f3Ssthen /* ----- nonpublic part, for winsock_event only ----- */ 191933707f3Ssthen /** index of this event in the items array (if added) */ 192933707f3Ssthen int idx; 193933707f3Ssthen /** the event handle to wait for new events to become ready */ 194933707f3Ssthen WSAEVENT hEvent; 195933707f3Ssthen /** true if this filedes is a TCP socket and needs special attention */ 196933707f3Ssthen int is_tcp; 197933707f3Ssthen /** remembered EV_ values */ 198933707f3Ssthen short old_events; 199933707f3Ssthen /** should remembered EV_ values be used for TCP streams. 200933707f3Ssthen * Reset after WOULDBLOCK is signaled using the function. */ 201933707f3Ssthen int stick_events; 202933707f3Ssthen 203933707f3Ssthen /** true if this event is a signaling WSAEvent by the user. 2044bfc71b0Ssthen * User created and user closed WSAEvent. Only signaled/unsignaled, 205933707f3Ssthen * no read/write/distinctions needed. */ 206933707f3Ssthen int is_signal; 207933707f3Ssthen /** used during callbacks to see which events were just checked */ 208933707f3Ssthen int just_checked; 209933707f3Ssthen }; 210933707f3Ssthen 211933707f3Ssthen /** create event base */ 212229e174cSsthen void *event_init(time_t* time_secs, struct timeval* time_tv); 213933707f3Ssthen /** get version */ 214933707f3Ssthen const char *event_get_version(void); 215933707f3Ssthen /** get polling method (select,epoll) */ 216933707f3Ssthen const char *event_get_method(void); 217933707f3Ssthen /** run select in a loop */ 218933707f3Ssthen int event_base_dispatch(struct event_base *); 219933707f3Ssthen /** exit that loop */ 220933707f3Ssthen int event_base_loopexit(struct event_base *, struct timeval *); 221933707f3Ssthen /** free event base. Free events yourself */ 222933707f3Ssthen void event_base_free(struct event_base *); 223933707f3Ssthen /** set content of event */ 224933707f3Ssthen void event_set(struct event *, int, short, void (*)(int, short, void *), void *); 225933707f3Ssthen 226933707f3Ssthen /** add event to a base. You *must* call this for every event. */ 227933707f3Ssthen int event_base_set(struct event_base *, struct event *); 228933707f3Ssthen /** add event to make it active. You may not change it with event_set anymore */ 229933707f3Ssthen int event_add(struct event *, struct timeval *); 230933707f3Ssthen /** remove event. You may change it again */ 231933707f3Ssthen int event_del(struct event *); 232933707f3Ssthen 233933707f3Ssthen #define evtimer_add(ev, tv) event_add(ev, tv) 234933707f3Ssthen #define evtimer_del(ev) event_del(ev) 235933707f3Ssthen 236933707f3Ssthen /* uses different implementation. Cannot mix fd/timeouts and signals inside 237933707f3Ssthen * the same struct event. create several event structs for that. */ 238933707f3Ssthen /** install signal handler */ 239933707f3Ssthen int signal_add(struct event *, struct timeval *); 240933707f3Ssthen /** set signal event contents */ 241933707f3Ssthen #define signal_set(ev, x, cb, arg) \ 242933707f3Ssthen event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 243933707f3Ssthen /** remove signal handler */ 244933707f3Ssthen int signal_del(struct event *); 245933707f3Ssthen 246933707f3Ssthen /** compare events in tree, based on timevalue, ptr for uniqueness */ 247933707f3Ssthen int mini_ev_cmp(const void* a, const void* b); 248933707f3Ssthen 249933707f3Ssthen /** 250933707f3Ssthen * Routine for windows only, where the handling layer can signal that 251933707f3Ssthen * a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs 252933707f3Ssthen * retesting the event. 253933707f3Ssthen * Pass if EV_READ or EV_WRITE gave wouldblock. 254933707f3Ssthen */ 255933707f3Ssthen void winsock_tcp_wouldblock(struct event* ev, int eventbit); 256933707f3Ssthen 257933707f3Ssthen /** 258933707f3Ssthen * Routine for windows only. where you pass a signal WSAEvent that 259933707f3Ssthen * you wait for. When the event is signaled, the callback gets called. 260933707f3Ssthen * The callback has to WSAResetEvent to disable the signal. 261933707f3Ssthen * @param base: the event base. 262933707f3Ssthen * @param ev: the event structure for data storage 263933707f3Ssthen * can be passed uninitialised. 264933707f3Ssthen * @param wsaevent: the WSAEvent that gets signaled. 265933707f3Ssthen * @param cb: callback routine. 266933707f3Ssthen * @param arg: user argument to callback routine. 267933707f3Ssthen * @return false on error. 268933707f3Ssthen */ 269933707f3Ssthen int winsock_register_wsaevent(struct event_base* base, struct event* ev, 270933707f3Ssthen WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); 271933707f3Ssthen 272933707f3Ssthen /** 273933707f3Ssthen * Unregister a wsaevent. User has to close the WSAEVENT itself. 274933707f3Ssthen * @param ev: event data storage. 275933707f3Ssthen */ 276933707f3Ssthen void winsock_unregister_wsaevent(struct event* ev); 277933707f3Ssthen 278933707f3Ssthen #endif /* USE_WINSOCK */ 279933707f3Ssthen #endif /* UTIL_WINSOCK_EVENT_H */ 280