xref: /freebsd/contrib/unbound/util/winsock_event.c (revision 3b8f08459569bf0faa21473e5cec2491e95c9349)
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 
47 int 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 */
67 static int
68 settime(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  */
88 static int
89 find_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 */
101 static void
102 zero_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 
111 void *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 
148 const char *event_get_version(void)
149 {
150 	return "winsock-event-"PACKAGE_VERSION;
151 }
152 
153 const 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 */
159 static 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 */
199 static 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 */
226 static 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 
424 int 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 
445 int 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 
453 void 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 
467 void 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 
480 int 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 
489 int 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 
570 int 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 */
608 static struct event_base* signal_base = NULL;
609 /** signal handler */
610 static 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 
622 int 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 
635 int 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 
644 void 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 
657 int 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 
676 void 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 */
691 int winsock_unused_symbol = 1;
692 #endif /* USE_WINSOCK */
693