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