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