]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/winsock_event.c
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / util / winsock_event.c
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_type*)(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=%s "
266                 "timeout=%d", base->max, numwait, (wait?"<wait>":"<null>"),
267                 (int)timeout);
268
269         /* do the wait */
270         if(numwait == 0) {
271                 /* WSAWaitFor.. doesn't like 0 event objects */
272                 if(wait) {
273                         Sleep(timeout);
274                 }
275                 was_timeout = 1;
276         } else {
277                 ret = WSAWaitForMultipleEvents(numwait, base->waitfor,
278                         0 /* do not wait for all, just one will do */,
279                         wait?timeout:WSA_INFINITE,
280                         0); /* we are not alertable (IO completion events) */
281                 if(ret == WSA_WAIT_IO_COMPLETION) {
282                         log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
283                         return -1;
284                 } else if(ret == WSA_WAIT_FAILED) {
285                         log_err("WSAWaitForMultipleEvents failed: %s", 
286                                 wsa_strerror(WSAGetLastError()));
287                         return -1;
288                 } else if(ret == WSA_WAIT_TIMEOUT) {
289                         was_timeout = 1;
290                 } else
291                         startidx = ret - WSA_WAIT_EVENT_0;
292         }
293         verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", 
294                 was_timeout, startidx);
295
296         /* get new time after wait */
297         if(settime(base) < 0)
298                return -1;
299
300         /* callbacks */
301         if(base->tcp_stickies)
302                 startidx = 0; /* process all events, some are sticky */
303         for(i=startidx; i<numwait; i++)
304                 eventlist[i]->just_checked = 1;
305
306         verbose(VERB_CLIENT, "winsock_event signals");
307         for(i=startidx; i<numwait; i++) {
308                 if(!base->waitfor[i])
309                         continue; /* was deleted */
310                 if(eventlist[i]->is_signal) {
311                         eventlist[i]->just_checked = 0;
312                         handle_signal(eventlist[i]);
313                 }
314         }
315         /* early exit - do not process network, exit quickly */
316         if(base->need_to_exit)
317                 return 0;
318
319         verbose(VERB_CLIENT, "winsock_event net");
320         for(i=startidx; i<numwait; i++) {
321                 short bits = 0;
322                 /* eventlist[i] fired */
323                 /* see if eventlist[i] is still valid and just checked from
324                  * WSAWaitForEvents */
325                 if(!base->waitfor[i])
326                         continue; /* was deleted */
327                 if(!eventlist[i]->just_checked)
328                         continue; /* added by other callback */
329                 if(eventlist[i]->is_signal)
330                         continue; /* not a network event at all */
331                 eventlist[i]->just_checked = 0;
332
333                 if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, 
334                         base->waitfor[i], /* reset the event handle */
335                         /*NULL,*/ /* do not reset the event handle */
336                         &netev) != 0) {
337                         log_err("WSAEnumNetworkEvents failed: %s", 
338                                 wsa_strerror(WSAGetLastError()));
339                         return -1;
340                 }
341                 if((netev.lNetworkEvents & FD_READ)) {
342                         if(netev.iErrorCode[FD_READ_BIT] != 0)
343                                 verbose(VERB_ALGO, "FD_READ_BIT error: %s",
344                                 wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
345                         bits |= EV_READ;
346                 }
347                 if((netev.lNetworkEvents & FD_WRITE)) {
348                         if(netev.iErrorCode[FD_WRITE_BIT] != 0)
349                                 verbose(VERB_ALGO, "FD_WRITE_BIT error: %s",
350                                 wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
351                         bits |= EV_WRITE;
352                 }
353                 if((netev.lNetworkEvents & FD_CONNECT)) {
354                         if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
355                                 verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s",
356                                 wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
357                         bits |= EV_READ;
358                         bits |= EV_WRITE;
359                 }
360                 if((netev.lNetworkEvents & FD_ACCEPT)) {
361                         if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
362                                 verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s",
363                                 wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
364                         bits |= EV_READ;
365                 }
366                 if((netev.lNetworkEvents & FD_CLOSE)) {
367                         if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
368                                 verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s",
369                                 wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
370                         bits |= EV_READ;
371                         bits |= EV_WRITE;
372                 }
373                 if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
374                         verbose(VERB_ALGO, "winsock %d pass sticky %s%s",
375                                 eventlist[i]->ev_fd,
376                                 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
377                                 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
378                         bits |= eventlist[i]->old_events;
379                 }
380                 if(eventlist[i]->is_tcp && bits) {
381                         eventlist[i]->old_events = bits;
382                         eventlist[i]->stick_events = 1;
383                         if((eventlist[i]->ev_events & bits)) {
384                                 newstickies = 1;
385                         }
386                         verbose(VERB_ALGO, "winsock %d store sticky %s%s",
387                                 eventlist[i]->ev_fd,
388                                 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
389                                 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
390                 }
391                 if((bits & eventlist[i]->ev_events)) {
392                         verbose(VERB_ALGO, "winsock event callback %p fd=%d "
393                                 "%s%s%s%s%s ; %s%s%s", 
394                                 eventlist[i], eventlist[i]->ev_fd,
395                                 (netev.lNetworkEvents&FD_READ)?" FD_READ":"",
396                                 (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"",
397                                 (netev.lNetworkEvents&FD_CONNECT)?
398                                         " FD_CONNECT":"",
399                                 (netev.lNetworkEvents&FD_ACCEPT)?
400                                         " FD_ACCEPT":"",
401                                 (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"",
402                                 (bits&EV_READ)?" EV_READ":"",
403                                 (bits&EV_WRITE)?" EV_WRITE":"",
404                                 (bits&EV_TIMEOUT)?" EV_TIMEOUT":"");
405                                 
406                         fptr_ok(fptr_whitelist_event(
407                                 eventlist[i]->ev_callback));
408                         (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
409                                 bits & eventlist[i]->ev_events, 
410                                 eventlist[i]->ev_arg);
411                 }
412                 if(eventlist[i]->is_tcp && bits)
413                         verbose(VERB_ALGO, "winsock %d got sticky %s%s",
414                                 eventlist[i]->ev_fd,
415                                 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
416                                 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
417         }
418         verbose(VERB_CLIENT, "winsock_event net");
419         if(base->tcp_reinvigorated) {
420                 verbose(VERB_CLIENT, "winsock_event reinvigorated");
421                 base->tcp_reinvigorated = 0;
422                 newstickies = 1;
423         }
424         base->tcp_stickies = newstickies;
425         verbose(VERB_CLIENT, "winsock_event handle_select end");
426         return 0;
427 }
428
429 int event_base_dispatch(struct event_base *base)
430 {
431         struct timeval wait;
432         if(settime(base) < 0)
433                 return -1;
434         while(!base->need_to_exit)
435         {
436                 /* see if timeouts need handling */
437                 handle_timeouts(base, base->time_tv, &wait);
438                 if(base->need_to_exit)
439                         return 0;
440                 /* do select */
441                 if(handle_select(base, &wait) < 0) {
442                         if(base->need_to_exit)
443                                 return 0;
444                         return -1;
445                 }
446         }
447         return 0;
448 }
449
450 int event_base_loopexit(struct event_base *base, 
451         struct timeval * ATTR_UNUSED(tv))
452 {
453         verbose(VERB_CLIENT, "winsock_event loopexit");
454         base->need_to_exit = 1;
455         return 0;
456 }
457
458 void event_base_free(struct event_base *base)
459 {
460         verbose(VERB_CLIENT, "winsock_event event_base_free");
461         if(!base)
462                 return;
463         free(base->items);
464         free(base->times);
465         free(base->signals);
466         free(base);
467 }
468
469 void event_set(struct event *ev, int fd, short bits, 
470         void (*cb)(int, short, void *), void *arg)
471 {
472         ev->node.key = ev;
473         ev->ev_fd = fd;
474         ev->ev_events = bits;
475         ev->ev_callback = cb;
476         fptr_ok(fptr_whitelist_event(ev->ev_callback));
477         ev->ev_arg = arg;
478         ev->just_checked = 0;
479         ev->added = 0;
480 }
481
482 int event_base_set(struct event_base *base, struct event *ev)
483 {
484         ev->ev_base = base;
485         ev->old_events = 0;
486         ev->stick_events = 0;
487         ev->added = 0;
488         return 0;
489 }
490
491 int event_add(struct event *ev, struct timeval *tv)
492 {
493         verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 
494                 ev, ev->added, ev->ev_fd, 
495                 (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1),
496                 (ev->ev_events&EV_READ)?" EV_READ":"",
497                 (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
498                 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
499         if(ev->added)
500                 event_del(ev);
501         log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1);
502         ev->is_tcp = 0;
503         ev->is_signal = 0;
504         ev->just_checked = 0;
505
506         if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
507                 BOOL b=0;
508                 int t, l;
509                 long events = 0;
510
511                 if(ev->ev_base->max == ev->ev_base->cap)
512                         return -1;
513                 ev->idx = ev->ev_base->max++;
514                 ev->ev_base->items[ev->idx] = ev;
515
516                 if( (ev->ev_events&EV_READ) )
517                         events |= FD_READ;
518                 if( (ev->ev_events&EV_WRITE) )
519                         events |= FD_WRITE;
520                 l = sizeof(t);
521                 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
522                         (void*)&t, &l) != 0)
523                         log_err("getsockopt(SO_TYPE) failed: %s",
524                                 wsa_strerror(WSAGetLastError()));
525                 if(t == SOCK_STREAM) {
526                         /* TCP socket */
527                         ev->is_tcp = 1;
528                         events |= FD_CLOSE;
529                         if( (ev->ev_events&EV_WRITE) )
530                                 events |= FD_CONNECT;
531                         l = sizeof(b);
532                         if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
533                                 (void*)&b, &l) != 0)
534                                 log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
535                                         wsa_strerror(WSAGetLastError()));
536                         if(b) /* TCP accept socket */
537                                 events |= FD_ACCEPT;
538                 }
539                 ev->hEvent = WSACreateEvent();
540                 if(ev->hEvent == WSA_INVALID_EVENT)
541                         log_err("WSACreateEvent failed: %s",
542                                 wsa_strerror(WSAGetLastError()));
543                 /* automatically sets fd to nonblocking mode.
544                  * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
545                 if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
546                         log_err("WSAEventSelect failed: %s",
547                                 wsa_strerror(WSAGetLastError()));
548                 }
549                 if(ev->is_tcp && ev->stick_events && 
550                         (ev->ev_events & ev->old_events)) {
551                         /* go to processing the sticky event right away */
552                         ev->ev_base->tcp_reinvigorated = 1;
553                 }
554         }
555
556         if(tv && (ev->ev_events&EV_TIMEOUT)) {
557 #ifndef S_SPLINT_S
558                 struct timeval *now = ev->ev_base->time_tv;
559                 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
560                 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
561                 while(ev->ev_timeout.tv_usec >= 1000000) {
562                         ev->ev_timeout.tv_usec -= 1000000;
563                         ev->ev_timeout.tv_sec++;
564                 }
565 #endif
566                 (void)rbtree_insert(ev->ev_base->times, &ev->node);
567         }
568         ev->added = 1;
569         return 0;
570 }
571
572 int event_del(struct event *ev)
573 {
574         verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", 
575                 ev, ev->added, ev->ev_fd, 
576                 (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
577                 (long long)ev->ev_timeout.tv_usec/1000:-1,
578                 (ev->ev_events&EV_READ)?" EV_READ":"",
579                 (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
580                 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
581         if(!ev->added)
582                 return 0;
583         log_assert(ev->added);
584         if((ev->ev_events&EV_TIMEOUT))
585                 (void)rbtree_delete(ev->ev_base->times, &ev->node);
586         if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
587                 log_assert(ev->ev_base->max > 0);
588                 /* remove item and compact the list */
589                 ev->ev_base->items[ev->idx] = 
590                         ev->ev_base->items[ev->ev_base->max-1];
591                 ev->ev_base->items[ev->ev_base->max-1] = NULL;
592                 ev->ev_base->max--;
593                 if(ev->idx < ev->ev_base->max)
594                         ev->ev_base->items[ev->idx]->idx = ev->idx;
595                 zero_waitfor(ev->ev_base->waitfor, ev->hEvent);
596
597                 if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
598                         log_err("WSAEventSelect(disable) failed: %s",
599                                 wsa_strerror(WSAGetLastError()));
600                 if(!WSACloseEvent(ev->hEvent))
601                         log_err("WSACloseEvent failed: %s",
602                                 wsa_strerror(WSAGetLastError()));
603         }
604         ev->just_checked = 0;
605         ev->added = 0;
606         return 0;
607 }
608
609 /** which base gets to handle signals */
610 static struct event_base* signal_base = NULL;
611 /** signal handler */
612 static RETSIGTYPE sigh(int sig)
613 {
614         struct event* ev;
615         if(!signal_base || sig < 0 || sig >= MAX_SIG)
616                 return;
617         ev = signal_base->signals[sig];
618         if(!ev)
619                 return;
620         fptr_ok(fptr_whitelist_event(ev->ev_callback));
621         (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
622 }
623
624 int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv))
625 {
626         if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
627                 return -1;
628         signal_base = ev->ev_base;
629         ev->ev_base->signals[ev->ev_fd] = ev;
630         ev->added = 1;
631         if(signal(ev->ev_fd, sigh) == SIG_ERR) {
632                 return -1;
633         }
634         return 0;
635 }
636
637 int signal_del(struct event *ev)
638 {
639         if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
640                 return -1;
641         ev->ev_base->signals[ev->ev_fd] = NULL;
642         ev->added = 0;
643         return 0;
644 }
645
646 void winsock_tcp_wouldblock(struct event* ev, int eventbits)
647 {
648         verbose(VERB_ALGO, "winsock: tcp wouldblock %s", 
649                 eventbits==EV_READ?"EV_READ":"EV_WRITE");
650         ev->old_events &= (~eventbits);
651         if(ev->old_events == 0)
652                 ev->stick_events = 0;
653                 /* in case this is the last sticky event, we could
654                  * possibly run an empty handler loop to reset the base
655                  * tcp_stickies variable 
656                  */
657 }
658
659 int winsock_register_wsaevent(struct event_base* base, struct event* ev,
660         WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
661 {
662         if(base->max == base->cap)
663                 return 0;
664         memset(ev, 0, sizeof(*ev));
665         ev->ev_fd = -1;
666         ev->ev_events = EV_READ;
667         ev->ev_callback = cb;
668         ev->ev_arg = arg;
669         ev->is_signal = 1;
670         ev->hEvent = wsaevent;
671         ev->added = 1;
672         ev->ev_base = base;
673         ev->idx = ev->ev_base->max++;
674         ev->ev_base->items[ev->idx] = ev;
675         return 1;
676 }
677
678 void winsock_unregister_wsaevent(struct event* ev)
679 {
680         if(!ev || !ev->added) return;
681         log_assert(ev->added && ev->ev_base->max > 0)
682         /* remove item and compact the list */
683         ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
684         ev->ev_base->items[ev->ev_base->max-1] = NULL;
685         ev->ev_base->max--;
686         if(ev->idx < ev->ev_base->max)
687                 ev->ev_base->items[ev->idx]->idx = ev->idx;
688         ev->added = 0;
689 }
690
691 #else /* USE_WINSOCK */
692 /** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
693 int winsock_unused_symbol = 1;
694 #endif /* USE_WINSOCK */