]> git.saurik.com Git - apple/network_cmds.git/blame - unbound/util/winsock_event.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / unbound / util / winsock_event.c
CommitLineData
89c4ed63
A
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
51int 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 */
71static int
72settime(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 */
92static int
93find_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 */
105static void
106zero_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
115void *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
152const char *event_get_version(void)
153{
154 return "winsock-event-"PACKAGE_VERSION;
155}
156
157const 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 */
163static 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 */
203static 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 */
230static 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
428int 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
449int 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
457void event_base_free(struct event_base *base)
458{
459 verbose(VERB_CLIENT, "winsock_event event_base_free");
460 if(!base)
461 return;
462 if(base->items)
463 free(base->items);
464 if(base->times)
465 free(base->times);
466 if(base->signals)
467 free(base->signals);
468 free(base);
469}
470
471void event_set(struct event *ev, int fd, short bits,
472 void (*cb)(int, short, void *), void *arg)
473{
474 ev->node.key = ev;
475 ev->ev_fd = fd;
476 ev->ev_events = bits;
477 ev->ev_callback = cb;
478 fptr_ok(fptr_whitelist_event(ev->ev_callback));
479 ev->ev_arg = arg;
480 ev->just_checked = 0;
481 ev->added = 0;
482}
483
484int event_base_set(struct event_base *base, struct event *ev)
485{
486 ev->ev_base = base;
487 ev->old_events = 0;
488 ev->stick_events = 0;
489 ev->added = 0;
490 return 0;
491}
492
493int event_add(struct event *ev, struct timeval *tv)
494{
495 verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
496 ev, ev->added, ev->ev_fd,
497 (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1),
498 (ev->ev_events&EV_READ)?" EV_READ":"",
499 (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
500 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
501 if(ev->added)
502 event_del(ev);
503 log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1);
504 ev->is_tcp = 0;
505 ev->is_signal = 0;
506 ev->just_checked = 0;
507
508 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
509 BOOL b=0;
510 int t, l;
511 long events = 0;
512
513 if(ev->ev_base->max == ev->ev_base->cap)
514 return -1;
515 ev->idx = ev->ev_base->max++;
516 ev->ev_base->items[ev->idx] = ev;
517
518 if( (ev->ev_events&EV_READ) )
519 events |= FD_READ;
520 if( (ev->ev_events&EV_WRITE) )
521 events |= FD_WRITE;
522 l = sizeof(t);
523 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
524 (void*)&t, &l) != 0)
525 log_err("getsockopt(SO_TYPE) failed: %s",
526 wsa_strerror(WSAGetLastError()));
527 if(t == SOCK_STREAM) {
528 /* TCP socket */
529 ev->is_tcp = 1;
530 events |= FD_CLOSE;
531 if( (ev->ev_events&EV_WRITE) )
532 events |= FD_CONNECT;
533 l = sizeof(b);
534 if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
535 (void*)&b, &l) != 0)
536 log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
537 wsa_strerror(WSAGetLastError()));
538 if(b) /* TCP accept socket */
539 events |= FD_ACCEPT;
540 }
541 ev->hEvent = WSACreateEvent();
542 if(ev->hEvent == WSA_INVALID_EVENT)
543 log_err("WSACreateEvent failed: %s",
544 wsa_strerror(WSAGetLastError()));
545 /* automatically sets fd to nonblocking mode.
546 * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
547 if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
548 log_err("WSAEventSelect failed: %s",
549 wsa_strerror(WSAGetLastError()));
550 }
551 if(ev->is_tcp && ev->stick_events &&
552 (ev->ev_events & ev->old_events)) {
553 /* go to processing the sticky event right away */
554 ev->ev_base->tcp_reinvigorated = 1;
555 }
556 }
557
558 if(tv && (ev->ev_events&EV_TIMEOUT)) {
559#ifndef S_SPLINT_S
560 struct timeval *now = ev->ev_base->time_tv;
561 ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
562 ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
563 while(ev->ev_timeout.tv_usec > 1000000) {
564 ev->ev_timeout.tv_usec -= 1000000;
565 ev->ev_timeout.tv_sec++;
566 }
567#endif
568 (void)rbtree_insert(ev->ev_base->times, &ev->node);
569 }
570 ev->added = 1;
571 return 0;
572}
573
574int event_del(struct event *ev)
575{
576 verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
577 ev, ev->added, ev->ev_fd,
578 (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
579 (long long)ev->ev_timeout.tv_usec/1000:-1,
580 (ev->ev_events&EV_READ)?" EV_READ":"",
581 (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
582 (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
583 if(!ev->added)
584 return 0;
585 log_assert(ev->added);
586 if((ev->ev_events&EV_TIMEOUT))
587 (void)rbtree_delete(ev->ev_base->times, &ev->node);
588 if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
589 log_assert(ev->ev_base->max > 0);
590 /* remove item and compact the list */
591 ev->ev_base->items[ev->idx] =
592 ev->ev_base->items[ev->ev_base->max-1];
593 ev->ev_base->items[ev->ev_base->max-1] = NULL;
594 ev->ev_base->max--;
595 if(ev->idx < ev->ev_base->max)
596 ev->ev_base->items[ev->idx]->idx = ev->idx;
597 zero_waitfor(ev->ev_base->waitfor, ev->hEvent);
598
599 if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
600 log_err("WSAEventSelect(disable) failed: %s",
601 wsa_strerror(WSAGetLastError()));
602 if(!WSACloseEvent(ev->hEvent))
603 log_err("WSACloseEvent failed: %s",
604 wsa_strerror(WSAGetLastError()));
605 }
606 ev->just_checked = 0;
607 ev->added = 0;
608 return 0;
609}
610
611/** which base gets to handle signals */
612static struct event_base* signal_base = NULL;
613/** signal handler */
614static RETSIGTYPE sigh(int sig)
615{
616 struct event* ev;
617 if(!signal_base || sig < 0 || sig >= MAX_SIG)
618 return;
619 ev = signal_base->signals[sig];
620 if(!ev)
621 return;
622 fptr_ok(fptr_whitelist_event(ev->ev_callback));
623 (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
624}
625
626int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv))
627{
628 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
629 return -1;
630 signal_base = ev->ev_base;
631 ev->ev_base->signals[ev->ev_fd] = ev;
632 ev->added = 1;
633 if(signal(ev->ev_fd, sigh) == SIG_ERR) {
634 return -1;
635 }
636 return 0;
637}
638
639int signal_del(struct event *ev)
640{
641 if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
642 return -1;
643 ev->ev_base->signals[ev->ev_fd] = NULL;
644 ev->added = 0;
645 return 0;
646}
647
648void winsock_tcp_wouldblock(struct event* ev, int eventbits)
649{
650 verbose(VERB_ALGO, "winsock: tcp wouldblock %s",
651 eventbits==EV_READ?"EV_READ":"EV_WRITE");
652 ev->old_events &= (~eventbits);
653 if(ev->old_events == 0)
654 ev->stick_events = 0;
655 /* in case this is the last sticky event, we could
656 * possibly run an empty handler loop to reset the base
657 * tcp_stickies variable
658 */
659}
660
661int winsock_register_wsaevent(struct event_base* base, struct event* ev,
662 WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
663{
664 if(base->max == base->cap)
665 return 0;
666 memset(ev, 0, sizeof(*ev));
667 ev->ev_fd = -1;
668 ev->ev_events = EV_READ;
669 ev->ev_callback = cb;
670 ev->ev_arg = arg;
671 ev->is_signal = 1;
672 ev->hEvent = wsaevent;
673 ev->added = 1;
674 ev->ev_base = base;
675 ev->idx = ev->ev_base->max++;
676 ev->ev_base->items[ev->idx] = ev;
677 return 1;
678}
679
680void winsock_unregister_wsaevent(struct event* ev)
681{
682 if(!ev || !ev->added) return;
683 log_assert(ev->added && ev->ev_base->max > 0)
684 /* remove item and compact the list */
685 ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
686 ev->ev_base->items[ev->ev_base->max-1] = NULL;
687 ev->ev_base->max--;
688 if(ev->idx < ev->ev_base->max)
689 ev->ev_base->items[ev->idx]->idx = ev->idx;
690 ev->added = 0;
691}
692
693#else /* USE_WINSOCK */
694/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
695int winsock_unused_symbol = 1;
696#endif /* USE_WINSOCK */