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