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