1238106Sdes/* 2238106Sdes * util/winsock_event.h - unbound event handling for winsock on windows 3238106Sdes * 4238106Sdes * Copyright (c) 2008, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains interface functions with the WinSock2 API on Windows. 40238106Sdes * It uses the winsock WSAWaitForMultipleEvents interface on a number of 41238106Sdes * sockets. 42238106Sdes * 43238106Sdes * Note that windows can only wait for max 64 events at one time. 44238106Sdes * 45238106Sdes * Also, file descriptors cannot be waited for. 46238106Sdes * 47238106Sdes * Named pipes are not easily available (and are not usable in select() ). 48238106Sdes * For interprocess communication, it is possible to wait for a hEvent to 49238106Sdes * be signaled by another thread. 50238106Sdes * 51238106Sdes * When a socket becomes readable, then it will not be flagged as 52238106Sdes * readable again until you have gotten WOULDBLOCK from a recv routine. 53238106Sdes * That means the event handler must store the readability (edge notify) 54238106Sdes * and process the incoming data until it blocks. 55238106Sdes * The function performing recv then has to inform the event handler that 56238106Sdes * the socket has blocked, and the event handler can mark it as such. 57238106Sdes * Thus, this file transforms the edge notify from windows to a level notify 58238106Sdes * that is compatible with UNIX. 59238106Sdes * The WSAEventSelect page says that it does do level notify, as long 60238106Sdes * as you call a recv/write/accept at least once when it is signalled. 61238106Sdes * This last bit is not true, even though documented in server2008 api docs 62238106Sdes * from microsoft, it does not happen at all. Instead you have to test for 63238106Sdes * WSAEWOULDBLOCK on a tcp stream, and only then retest the socket. 64238106Sdes * And before that remember the previous result as still valid. 65238106Sdes * 66238106Sdes * To stay 'fair', instead of emptying a socket completely, the event handler 67238106Sdes * can test the other (marked as blocking) sockets for new events. 68238106Sdes * 69238106Sdes * Additionally, TCP accept sockets get special event support. 70238106Sdes * 71238106Sdes * Socket numbers are not starting small, they can be any number (say 33060). 72238106Sdes * Therefore, bitmaps are not used, but arrays. 73238106Sdes * 74238106Sdes * on winsock, you must use recv() and send() for TCP reads and writes, 75238106Sdes * not read() and write(), those work only on files. 76238106Sdes * 77238106Sdes * Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode. 78238106Sdes * 79238106Sdes * When under a high load windows gives out lots of errors, from recvfrom 80238106Sdes * on udp sockets for example (WSAECONNRESET). Even though the udp socket 81238106Sdes * has no connection per se. 82238106Sdes */ 83238106Sdes 84238106Sdes#ifndef UTIL_WINSOCK_EVENT_H 85238106Sdes#define UTIL_WINSOCK_EVENT_H 86238106Sdes 87238106Sdes#ifdef USE_WINSOCK 88238106Sdes 89238106Sdes#ifndef HAVE_EVENT_BASE_FREE 90238106Sdes#define HAVE_EVENT_BASE_FREE 91238106Sdes#endif 92238106Sdes 93285206Sdes/* redefine the calls to different names so that there is no name 94285206Sdes * collision with other code that uses libevent names. (that uses libunbound)*/ 95285206Sdes#define event_init winsockevent_init 96285206Sdes#define event_get_version winsockevent_get_version 97285206Sdes#define event_get_method winsockevent_get_method 98285206Sdes#define event_base_dispatch winsockevent_base_dispatch 99285206Sdes#define event_base_loopexit winsockevent_base_loopexit 100285206Sdes#define event_base_free winsockevent_base_free 101285206Sdes#define event_set winsockevent_set 102285206Sdes#define event_base_set winsockevent_base_set 103285206Sdes#define event_add winsockevent_add 104285206Sdes#define event_del winsockevent_del 105285206Sdes#define signal_add winsocksignal_add 106285206Sdes#define signal_del winsocksignal_del 107285206Sdes 108238106Sdes/** event timeout */ 109238106Sdes#define EV_TIMEOUT 0x01 110238106Sdes/** event fd readable */ 111238106Sdes#define EV_READ 0x02 112238106Sdes/** event fd writable */ 113238106Sdes#define EV_WRITE 0x04 114238106Sdes/** event signal */ 115238106Sdes#define EV_SIGNAL 0x08 116238106Sdes/** event must persist */ 117238106Sdes#define EV_PERSIST 0x10 118238106Sdes 119238106Sdes/* needs our redblack tree */ 120238106Sdes#include "rbtree.h" 121238106Sdes 122238106Sdes/** max number of signals to support */ 123238106Sdes#define MAX_SIG 32 124238106Sdes 125238106Sdes/** The number of items that the winsock event handler can service. 126238106Sdes * Windows cannot handle more anyway */ 127238106Sdes#define WSK_MAX_ITEMS 64 128238106Sdes 129238106Sdes/** 130238106Sdes * event base for winsock event handler 131238106Sdes */ 132238106Sdesstruct event_base 133238106Sdes{ 134238106Sdes /** sorted by timeout (absolute), ptr */ 135238106Sdes rbtree_t* times; 136238106Sdes /** array (first part in use) of handles to work on */ 137238106Sdes struct event** items; 138238106Sdes /** number of items in use in array */ 139238106Sdes int max; 140238106Sdes /** capacity of array, size of array in items */ 141238106Sdes int cap; 142238106Sdes /** array of 0 - maxsig of ptr to event for it */ 143238106Sdes struct event** signals; 144238106Sdes /** if we need to exit */ 145238106Sdes int need_to_exit; 146238106Sdes /** where to store time in seconds */ 147269257Sdes time_t* time_secs; 148238106Sdes /** where to store time in microseconds */ 149238106Sdes struct timeval* time_tv; 150238106Sdes /** 151238106Sdes * TCP streams have sticky events to them, these are not 152238106Sdes * reported by the windows event system anymore, we have to 153238106Sdes * keep reporting those events as present until wouldblock() is 154238106Sdes * signalled by the handler back to use. 155238106Sdes */ 156238106Sdes int tcp_stickies; 157238106Sdes /** 158238106Sdes * should next cycle process reinvigorated stickies, 159238106Sdes * these are stickies that have been stored, but due to a new 160238106Sdes * event_add a sudden interest in the event has incepted. 161238106Sdes */ 162238106Sdes int tcp_reinvigorated; 163238106Sdes /** The list of events that is currently being processed. */ 164238106Sdes WSAEVENT waitfor[WSK_MAX_ITEMS]; 165238106Sdes}; 166238106Sdes 167238106Sdes/** 168238106Sdes * Event structure. Has some of the event elements. 169238106Sdes */ 170238106Sdesstruct event { 171238106Sdes /** node in timeout rbtree */ 172238106Sdes rbnode_t node; 173238106Sdes /** is event already added */ 174238106Sdes int added; 175238106Sdes 176238106Sdes /** event base it belongs to */ 177238106Sdes struct event_base *ev_base; 178238106Sdes /** fd to poll or -1 for timeouts. signal number for sigs. */ 179238106Sdes int ev_fd; 180238106Sdes /** what events this event is interested in, see EV_.. above. */ 181238106Sdes short ev_events; 182238106Sdes /** timeout value */ 183238106Sdes struct timeval ev_timeout; 184238106Sdes 185238106Sdes /** callback to call: fd, eventbits, userarg */ 186238106Sdes void (*ev_callback)(int, short, void *); 187238106Sdes /** callback user arg */ 188238106Sdes void *ev_arg; 189238106Sdes 190238106Sdes /* ----- nonpublic part, for winsock_event only ----- */ 191238106Sdes /** index of this event in the items array (if added) */ 192238106Sdes int idx; 193238106Sdes /** the event handle to wait for new events to become ready */ 194238106Sdes WSAEVENT hEvent; 195238106Sdes /** true if this filedes is a TCP socket and needs special attention */ 196238106Sdes int is_tcp; 197238106Sdes /** remembered EV_ values */ 198238106Sdes short old_events; 199238106Sdes /** should remembered EV_ values be used for TCP streams. 200238106Sdes * Reset after WOULDBLOCK is signaled using the function. */ 201238106Sdes int stick_events; 202238106Sdes 203238106Sdes /** true if this event is a signaling WSAEvent by the user. 204238106Sdes * User created and user closed WSAEvent. Only signaled/unsigneled, 205238106Sdes * no read/write/distinctions needed. */ 206238106Sdes int is_signal; 207238106Sdes /** used during callbacks to see which events were just checked */ 208238106Sdes int just_checked; 209238106Sdes}; 210238106Sdes 211238106Sdes/** create event base */ 212269257Sdesvoid *event_init(time_t* time_secs, struct timeval* time_tv); 213238106Sdes/** get version */ 214238106Sdesconst char *event_get_version(void); 215238106Sdes/** get polling method (select,epoll) */ 216238106Sdesconst char *event_get_method(void); 217238106Sdes/** run select in a loop */ 218238106Sdesint event_base_dispatch(struct event_base *); 219238106Sdes/** exit that loop */ 220238106Sdesint event_base_loopexit(struct event_base *, struct timeval *); 221238106Sdes/** free event base. Free events yourself */ 222238106Sdesvoid event_base_free(struct event_base *); 223238106Sdes/** set content of event */ 224238106Sdesvoid event_set(struct event *, int, short, void (*)(int, short, void *), void *); 225238106Sdes 226238106Sdes/** add event to a base. You *must* call this for every event. */ 227238106Sdesint event_base_set(struct event_base *, struct event *); 228238106Sdes/** add event to make it active. You may not change it with event_set anymore */ 229238106Sdesint event_add(struct event *, struct timeval *); 230238106Sdes/** remove event. You may change it again */ 231238106Sdesint event_del(struct event *); 232238106Sdes 233238106Sdes#define evtimer_add(ev, tv) event_add(ev, tv) 234238106Sdes#define evtimer_del(ev) event_del(ev) 235238106Sdes 236238106Sdes/* uses different implementation. Cannot mix fd/timeouts and signals inside 237238106Sdes * the same struct event. create several event structs for that. */ 238238106Sdes/** install signal handler */ 239238106Sdesint signal_add(struct event *, struct timeval *); 240238106Sdes/** set signal event contents */ 241238106Sdes#define signal_set(ev, x, cb, arg) \ 242238106Sdes event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) 243238106Sdes/** remove signal handler */ 244238106Sdesint signal_del(struct event *); 245238106Sdes 246238106Sdes/** compare events in tree, based on timevalue, ptr for uniqueness */ 247238106Sdesint mini_ev_cmp(const void* a, const void* b); 248238106Sdes 249238106Sdes/** 250238106Sdes * Routine for windows only, where the handling layer can signal that 251238106Sdes * a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs 252238106Sdes * retesting the event. 253238106Sdes * Pass if EV_READ or EV_WRITE gave wouldblock. 254238106Sdes */ 255238106Sdesvoid winsock_tcp_wouldblock(struct event* ev, int eventbit); 256238106Sdes 257238106Sdes/** 258238106Sdes * Routine for windows only. where you pass a signal WSAEvent that 259238106Sdes * you wait for. When the event is signaled, the callback gets called. 260238106Sdes * The callback has to WSAResetEvent to disable the signal. 261238106Sdes * @param base: the event base. 262238106Sdes * @param ev: the event structure for data storage 263238106Sdes * can be passed uninitialised. 264238106Sdes * @param wsaevent: the WSAEvent that gets signaled. 265238106Sdes * @param cb: callback routine. 266238106Sdes * @param arg: user argument to callback routine. 267238106Sdes * @return false on error. 268238106Sdes */ 269238106Sdesint winsock_register_wsaevent(struct event_base* base, struct event* ev, 270238106Sdes WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); 271238106Sdes 272238106Sdes/** 273238106Sdes * Unregister a wsaevent. User has to close the WSAEVENT itself. 274238106Sdes * @param ev: event data storage. 275238106Sdes */ 276238106Sdesvoid winsock_unregister_wsaevent(struct event* ev); 277238106Sdes 278238106Sdes#endif /* USE_WINSOCK */ 279238106Sdes#endif /* UTIL_WINSOCK_EVENT_H */ 280