2 * util/winsock_event.c - implementation of the unbound winsock event handler.
4 * Copyright (c) 2008, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
37 * Implementation of the unbound WinSock2 API event notification handler
38 * for the Windows port.
44 #include "util/winsock_event.h"
45 #include "util/fptr_wlist.h"
47 int mini_ev_cmp(const void* a, const void* b)
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)
53 if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
55 if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
57 if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
68 settime(struct event_base* base)
70 if(gettimeofday(base->time_tv, NULL) < 0) {
74 *base->time_secs = (uint32_t)base->time_tv->tv_sec;
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.
89 find_fd(struct event_base* base, int fd)
92 for(i=0; i<base->max; i++) {
93 if(base->items[i]->ev_fd == fd)
100 /** Find ptr in base array */
102 zero_waitfor(WSAEVENT waitfor[], WSAEVENT x)
105 for(i=0; i<WSK_MAX_ITEMS; i++) {
111 void *event_init(uint32_t* time_secs, struct timeval* time_tv)
113 struct event_base* base = (struct event_base*)malloc(
114 sizeof(struct event_base));
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);
124 base->items = (struct event**)calloc(WSK_MAX_ITEMS,
125 sizeof(struct event*));
127 event_base_free(base);
130 base->cap = WSK_MAX_ITEMS;
132 base->times = rbtree_create(mini_ev_cmp);
134 event_base_free(base);
137 base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
139 event_base_free(base);
142 base->tcp_stickies = 0;
143 base->tcp_reinvigorated = 0;
144 verbose(VERB_CLIENT, "winsock_event inited");
148 const char *event_get_version(void)
150 return "winsock-event-"PACKAGE_VERSION;
153 const char *event_get_method(void)
155 return "WSAWaitForMultipleEvents";
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)
164 wait->tv_sec = (time_t)-1;
166 verbose(VERB_CLIENT, "winsock_event handle_timeouts");
168 while((rbnode_t*)(p = (struct event*)rbtree_first(base->times))
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) {
178 wait->tv_usec = 1000000 - (now->tv_usec -
179 p->ev_timeout.tv_usec);
181 wait->tv_usec = p->ev_timeout.tv_usec
184 verbose(VERB_CLIENT, "winsock_event wait=%d.%6.6d",
185 (int)wait->tv_sec, (int)wait->tv_usec);
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);
195 verbose(VERB_CLIENT, "winsock_event wait=(-1)");
198 /** handle is_signal events and see if signalled */
199 static void handle_signal(struct event* ev)
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()));
211 if(ret == WSA_WAIT_TIMEOUT) {
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);
225 /** call select and callbacks for that */
226 static int handle_select(struct event_base* base, struct timeval* wait)
228 DWORD timeout = 0; /* in milliseconds */
230 struct event* eventlist[WSK_MAX_ITEMS];
231 WSANETWORKEVENTS netev;
232 int i, numwait = 0, startidx = 0, was_timeout = 0;
234 struct timeval nultm;
236 verbose(VERB_CLIENT, "winsock_event handle_select");
239 if(wait->tv_sec==(time_t)-1)
242 timeout = wait->tv_sec*1000 + wait->tv_usec/1000;
243 if(base->tcp_stickies) {
247 timeout = 0; /* no waiting, we have sticky events */
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 */
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);
266 /* WSAWaitFor.. doesn't like 0 event objects */
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");
279 } else if(ret == WSA_WAIT_FAILED) {
280 log_err("WSAWaitForMultipleEvents failed: %s",
281 wsa_strerror(WSAGetLastError()));
283 } else if(ret == WSA_WAIT_TIMEOUT) {
286 startidx = ret - WSA_WAIT_EVENT_0;
288 verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d",
289 was_timeout, startidx);
291 /* get new time after wait */
292 if(settime(base) < 0)
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;
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]);
310 /* early exit - do not process network, exit quickly */
311 if(base->need_to_exit)
314 verbose(VERB_CLIENT, "winsock_event net");
315 for(i=startidx; i<numwait; i++) {
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;
328 if(WSAEnumNetworkEvents(eventlist[i]->ev_fd,
329 base->waitfor[i], /* reset the event handle */
330 /*NULL,*/ /* do not reset the event handle */
332 log_err("WSAEnumNetworkEvents failed: %s",
333 wsa_strerror(WSAGetLastError()));
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]));
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]));
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]));
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]));
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]));
368 if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
369 verbose(VERB_ALGO, "winsock %d pass sticky %s%s",
371 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
372 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
373 bits |= eventlist[i]->old_events;
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)) {
381 verbose(VERB_ALGO, "winsock %d store sticky %s%s",
383 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
384 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
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)?
394 (netev.lNetworkEvents&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":"");
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);
407 if(eventlist[i]->is_tcp && bits)
408 verbose(VERB_ALGO, "winsock %d got sticky %s%s",
410 (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
411 (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
413 verbose(VERB_CLIENT, "winsock_event net");
414 if(base->tcp_reinvigorated) {
415 verbose(VERB_CLIENT, "winsock_event reinvigorated");
416 base->tcp_reinvigorated = 0;
419 base->tcp_stickies = newstickies;
420 verbose(VERB_CLIENT, "winsock_event handle_select end");
424 int event_base_dispatch(struct event_base *base)
427 if(settime(base) < 0)
429 while(!base->need_to_exit)
431 /* see if timeouts need handling */
432 handle_timeouts(base, base->time_tv, &wait);
433 if(base->need_to_exit)
436 if(handle_select(base, &wait) < 0) {
437 if(base->need_to_exit)
445 int event_base_loopexit(struct event_base *base,
446 struct timeval * ATTR_UNUSED(tv))
448 verbose(VERB_CLIENT, "winsock_event loopexit");
449 base->need_to_exit = 1;
453 void event_base_free(struct event_base *base)
455 verbose(VERB_CLIENT, "winsock_event event_base_free");
467 void event_set(struct event *ev, int fd, short bits,
468 void (*cb)(int, short, void *), void *arg)
472 ev->ev_events = bits;
473 ev->ev_callback = cb;
474 fptr_ok(fptr_whitelist_event(ev->ev_callback));
476 ev->just_checked = 0;
480 int event_base_set(struct event_base *base, struct event *ev)
484 ev->stick_events = 0;
489 int event_add(struct event *ev, struct timeval *tv)
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":"");
499 log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1);
502 ev->just_checked = 0;
504 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
509 if(ev->ev_base->max == ev->ev_base->cap)
511 ev->idx = ev->ev_base->max++;
512 ev->ev_base->items[ev->idx] = ev;
514 if( (ev->ev_events&EV_READ) )
516 if( (ev->ev_events&EV_WRITE) )
519 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
521 log_err("getsockopt(SO_TYPE) failed: %s",
522 wsa_strerror(WSAGetLastError()));
523 if(t == SOCK_STREAM) {
527 if( (ev->ev_events&EV_WRITE) )
528 events |= FD_CONNECT;
530 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
532 log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
533 wsa_strerror(WSAGetLastError()));
534 if(b) /* TCP accept socket */
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()));
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;
554 if(tv && (ev->ev_events&EV_TIMEOUT)) {
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++;
564 (void)rbtree_insert(ev->ev_base->times, &ev->node);
570 int event_del(struct event *ev)
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":"");
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;
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);
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()));
602 ev->just_checked = 0;
607 /** which base gets to handle signals */
608 static struct event_base* signal_base = NULL;
609 /** signal handler */
610 static RETSIGTYPE sigh(int sig)
613 if(!signal_base || sig < 0 || sig >= MAX_SIG)
615 ev = signal_base->signals[sig];
618 fptr_ok(fptr_whitelist_event(ev->ev_callback));
619 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
622 int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv))
624 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
626 signal_base = ev->ev_base;
627 ev->ev_base->signals[ev->ev_fd] = ev;
629 if(signal(ev->ev_fd, sigh) == SIG_ERR) {
635 int signal_del(struct event *ev)
637 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
639 ev->ev_base->signals[ev->ev_fd] = NULL;
644 void winsock_tcp_wouldblock(struct event* ev, int eventbits)
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
657 int winsock_register_wsaevent(struct event_base* base, struct event* ev,
658 WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
660 if(base->max == base->cap)
662 memset(ev, 0, sizeof(*ev));
664 ev->ev_events = EV_READ;
665 ev->ev_callback = cb;
668 ev->hEvent = wsaevent;
671 ev->idx = ev->ev_base->max++;
672 ev->ev_base->items[ev->idx] = ev;
676 void winsock_unregister_wsaevent(struct event* ev)
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;
684 if(ev->idx < ev->ev_base->max)
685 ev->ev_base->items[ev->idx]->idx = ev->idx;
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 */