]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/sntp/libevent/listener.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / sntp / libevent / listener.c
1 /*
2  * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "event2/event-config.h"
28 #include "evconfig-private.h"
29
30 #include <sys/types.h>
31
32 #ifdef _WIN32
33 #ifndef _WIN32_WINNT
34 /* Minimum required for InitializeCriticalSectionAndSpinCount */
35 #define _WIN32_WINNT 0x0403
36 #endif
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 #include <mswsock.h>
40 #endif
41 #include <errno.h>
42 #ifdef EVENT__HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
45 #ifdef EVENT__HAVE_FCNTL_H
46 #include <fcntl.h>
47 #endif
48 #ifdef EVENT__HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include "event2/listener.h"
53 #include "event2/util.h"
54 #include "event2/event.h"
55 #include "event2/event_struct.h"
56 #include "mm-internal.h"
57 #include "util-internal.h"
58 #include "log-internal.h"
59 #include "evthread-internal.h"
60 #ifdef _WIN32
61 #include "iocp-internal.h"
62 #include "defer-internal.h"
63 #include "event-internal.h"
64 #endif
65
66 struct evconnlistener_ops {
67         int (*enable)(struct evconnlistener *);
68         int (*disable)(struct evconnlistener *);
69         void (*destroy)(struct evconnlistener *);
70         void (*shutdown)(struct evconnlistener *);
71         evutil_socket_t (*getfd)(struct evconnlistener *);
72         struct event_base *(*getbase)(struct evconnlistener *);
73 };
74
75 struct evconnlistener {
76         const struct evconnlistener_ops *ops;
77         void *lock;
78         evconnlistener_cb cb;
79         evconnlistener_errorcb errorcb;
80         void *user_data;
81         unsigned flags;
82         short refcnt;
83         int accept4_flags;
84         unsigned enabled : 1;
85 };
86
87 struct evconnlistener_event {
88         struct evconnlistener base;
89         struct event listener;
90 };
91
92 #ifdef _WIN32
93 struct evconnlistener_iocp {
94         struct evconnlistener base;
95         evutil_socket_t fd;
96         struct event_base *event_base;
97         struct event_iocp_port *port;
98         short n_accepting;
99         unsigned shutting_down : 1;
100         unsigned event_added : 1;
101         struct accepting_socket **accepting;
102 };
103 #endif
104
105 #define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
106 #define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
107
108 struct evconnlistener *
109 evconnlistener_new_async(struct event_base *base,
110     evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
111     evutil_socket_t fd); /* XXXX export this? */
112
113 static int event_listener_enable(struct evconnlistener *);
114 static int event_listener_disable(struct evconnlistener *);
115 static void event_listener_destroy(struct evconnlistener *);
116 static evutil_socket_t event_listener_getfd(struct evconnlistener *);
117 static struct event_base *event_listener_getbase(struct evconnlistener *);
118
119 #if 0
120 static void
121 listener_incref_and_lock(struct evconnlistener *listener)
122 {
123         LOCK(listener);
124         ++listener->refcnt;
125 }
126 #endif
127
128 static int
129 listener_decref_and_unlock(struct evconnlistener *listener)
130 {
131         int refcnt = --listener->refcnt;
132         if (refcnt == 0) {
133                 listener->ops->destroy(listener);
134                 UNLOCK(listener);
135                 EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
136                 mm_free(listener);
137                 return 1;
138         } else {
139                 UNLOCK(listener);
140                 return 0;
141         }
142 }
143
144 static const struct evconnlistener_ops evconnlistener_event_ops = {
145         event_listener_enable,
146         event_listener_disable,
147         event_listener_destroy,
148         NULL, /* shutdown */
149         event_listener_getfd,
150         event_listener_getbase
151 };
152
153 static void listener_read_cb(evutil_socket_t, short, void *);
154
155 struct evconnlistener *
156 evconnlistener_new(struct event_base *base,
157     evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
158     evutil_socket_t fd)
159 {
160         struct evconnlistener_event *lev;
161
162 #ifdef _WIN32
163         if (base && event_base_get_iocp_(base)) {
164                 const struct win32_extension_fns *ext =
165                         event_get_win32_extension_fns_();
166                 if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
167                         return evconnlistener_new_async(base, cb, ptr, flags,
168                                 backlog, fd);
169         }
170 #endif
171
172         if (backlog > 0) {
173                 if (listen(fd, backlog) < 0)
174                         return NULL;
175         } else if (backlog < 0) {
176                 if (listen(fd, 128) < 0)
177                         return NULL;
178         }
179
180         lev = mm_calloc(1, sizeof(struct evconnlistener_event));
181         if (!lev)
182                 return NULL;
183
184         lev->base.ops = &evconnlistener_event_ops;
185         lev->base.cb = cb;
186         lev->base.user_data = ptr;
187         lev->base.flags = flags;
188         lev->base.refcnt = 1;
189
190         lev->base.accept4_flags = 0;
191         if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
192                 lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
193         if (flags & LEV_OPT_CLOSE_ON_EXEC)
194                 lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
195
196         if (flags & LEV_OPT_THREADSAFE) {
197                 EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
198         }
199
200         event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
201             listener_read_cb, lev);
202
203         if (!(flags & LEV_OPT_DISABLED))
204             evconnlistener_enable(&lev->base);
205
206         return &lev->base;
207 }
208
209 struct evconnlistener *
210 evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
211     void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
212     int socklen)
213 {
214         struct evconnlistener *listener;
215         evutil_socket_t fd;
216         int on = 1;
217         int family = sa ? sa->sa_family : AF_UNSPEC;
218         int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
219
220         if (backlog == 0)
221                 return NULL;
222
223         if (flags & LEV_OPT_CLOSE_ON_EXEC)
224                 socktype |= EVUTIL_SOCK_CLOEXEC;
225
226         fd = evutil_socket_(family, socktype, 0);
227         if (fd == -1)
228                 return NULL;
229
230         if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
231                 goto err;
232
233         if (flags & LEV_OPT_REUSEABLE) {
234                 if (evutil_make_listen_socket_reuseable(fd) < 0)
235                         goto err;
236         }
237
238         if (flags & LEV_OPT_REUSEABLE_PORT) {
239                 if (evutil_make_listen_socket_reuseable_port(fd) < 0)
240                         goto err;
241         }
242
243         if (flags & LEV_OPT_DEFERRED_ACCEPT) {
244                 if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
245                         goto err;
246         }
247
248         if (sa) {
249                 if (bind(fd, sa, socklen)<0)
250                         goto err;
251         }
252
253         listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
254         if (!listener)
255                 goto err;
256
257         return listener;
258 err:
259         evutil_closesocket(fd);
260         return NULL;
261 }
262
263 void
264 evconnlistener_free(struct evconnlistener *lev)
265 {
266         LOCK(lev);
267         lev->cb = NULL;
268         lev->errorcb = NULL;
269         if (lev->ops->shutdown)
270                 lev->ops->shutdown(lev);
271         listener_decref_and_unlock(lev);
272 }
273
274 static void
275 event_listener_destroy(struct evconnlistener *lev)
276 {
277         struct evconnlistener_event *lev_e =
278             EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
279
280         event_del(&lev_e->listener);
281         if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
282                 evutil_closesocket(event_get_fd(&lev_e->listener));
283         event_debug_unassign(&lev_e->listener);
284 }
285
286 int
287 evconnlistener_enable(struct evconnlistener *lev)
288 {
289         int r;
290         LOCK(lev);
291         lev->enabled = 1;
292         if (lev->cb)
293                 r = lev->ops->enable(lev);
294         else
295                 r = 0;
296         UNLOCK(lev);
297         return r;
298 }
299
300 int
301 evconnlistener_disable(struct evconnlistener *lev)
302 {
303         int r;
304         LOCK(lev);
305         lev->enabled = 0;
306         r = lev->ops->disable(lev);
307         UNLOCK(lev);
308         return r;
309 }
310
311 static int
312 event_listener_enable(struct evconnlistener *lev)
313 {
314         struct evconnlistener_event *lev_e =
315             EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
316         return event_add(&lev_e->listener, NULL);
317 }
318
319 static int
320 event_listener_disable(struct evconnlistener *lev)
321 {
322         struct evconnlistener_event *lev_e =
323             EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
324         return event_del(&lev_e->listener);
325 }
326
327 evutil_socket_t
328 evconnlistener_get_fd(struct evconnlistener *lev)
329 {
330         evutil_socket_t fd;
331         LOCK(lev);
332         fd = lev->ops->getfd(lev);
333         UNLOCK(lev);
334         return fd;
335 }
336
337 static evutil_socket_t
338 event_listener_getfd(struct evconnlistener *lev)
339 {
340         struct evconnlistener_event *lev_e =
341             EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
342         return event_get_fd(&lev_e->listener);
343 }
344
345 struct event_base *
346 evconnlistener_get_base(struct evconnlistener *lev)
347 {
348         struct event_base *base;
349         LOCK(lev);
350         base = lev->ops->getbase(lev);
351         UNLOCK(lev);
352         return base;
353 }
354
355 static struct event_base *
356 event_listener_getbase(struct evconnlistener *lev)
357 {
358         struct evconnlistener_event *lev_e =
359             EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
360         return event_get_base(&lev_e->listener);
361 }
362
363 void
364 evconnlistener_set_cb(struct evconnlistener *lev,
365     evconnlistener_cb cb, void *arg)
366 {
367         int enable = 0;
368         LOCK(lev);
369         if (lev->enabled && !lev->cb)
370                 enable = 1;
371         lev->cb = cb;
372         lev->user_data = arg;
373         if (enable)
374                 evconnlistener_enable(lev);
375         UNLOCK(lev);
376 }
377
378 void
379 evconnlistener_set_error_cb(struct evconnlistener *lev,
380     evconnlistener_errorcb errorcb)
381 {
382         LOCK(lev);
383         lev->errorcb = errorcb;
384         UNLOCK(lev);
385 }
386
387 static void
388 listener_read_cb(evutil_socket_t fd, short what, void *p)
389 {
390         struct evconnlistener *lev = p;
391         int err;
392         evconnlistener_cb cb;
393         evconnlistener_errorcb errorcb;
394         void *user_data;
395         LOCK(lev);
396         while (1) {
397                 struct sockaddr_storage ss;
398                 ev_socklen_t socklen = sizeof(ss);
399                 evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
400                 if (new_fd < 0)
401                         break;
402                 if (socklen == 0) {
403                         /* This can happen with some older linux kernels in
404                          * response to nmap. */
405                         evutil_closesocket(new_fd);
406                         continue;
407                 }
408
409                 if (lev->cb == NULL) {
410                         evutil_closesocket(new_fd);
411                         UNLOCK(lev);
412                         return;
413                 }
414                 ++lev->refcnt;
415                 cb = lev->cb;
416                 user_data = lev->user_data;
417                 UNLOCK(lev);
418                 cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
419                     user_data);
420                 LOCK(lev);
421                 if (lev->refcnt == 1) {
422                         int freed = listener_decref_and_unlock(lev);
423                         EVUTIL_ASSERT(freed);
424
425                         evutil_closesocket(new_fd);
426                         return;
427                 }
428                 --lev->refcnt;
429         }
430         err = evutil_socket_geterror(fd);
431         if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
432                 UNLOCK(lev);
433                 return;
434         }
435         if (lev->errorcb != NULL) {
436                 ++lev->refcnt;
437                 errorcb = lev->errorcb;
438                 user_data = lev->user_data;
439                 UNLOCK(lev);
440                 errorcb(lev, user_data);
441                 LOCK(lev);
442                 listener_decref_and_unlock(lev);
443         } else {
444                 event_sock_warn(fd, "Error from accept() call");
445         }
446 }
447
448 #ifdef _WIN32
449 struct accepting_socket {
450         CRITICAL_SECTION lock;
451         struct event_overlapped overlapped;
452         SOCKET s;
453         int error;
454         struct event_callback deferred;
455         struct evconnlistener_iocp *lev;
456         ev_uint8_t buflen;
457         ev_uint8_t family;
458         unsigned free_on_cb:1;
459         char addrbuf[1];
460 };
461
462 static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
463     ev_ssize_t n, int ok);
464 static void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
465
466 static void
467 iocp_listener_event_add(struct evconnlistener_iocp *lev)
468 {
469         if (lev->event_added)
470                 return;
471
472         lev->event_added = 1;
473         event_base_add_virtual_(lev->event_base);
474 }
475
476 static void
477 iocp_listener_event_del(struct evconnlistener_iocp *lev)
478 {
479         if (!lev->event_added)
480                 return;
481
482         lev->event_added = 0;
483         event_base_del_virtual_(lev->event_base);
484 }
485
486 static struct accepting_socket *
487 new_accepting_socket(struct evconnlistener_iocp *lev, int family)
488 {
489         struct accepting_socket *res;
490         int addrlen;
491         int buflen;
492
493         if (family == AF_INET)
494                 addrlen = sizeof(struct sockaddr_in);
495         else if (family == AF_INET6)
496                 addrlen = sizeof(struct sockaddr_in6);
497         else
498                 return NULL;
499         buflen = (addrlen+16)*2;
500
501         res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
502         if (!res)
503                 return NULL;
504
505         event_overlapped_init_(&res->overlapped, accepted_socket_cb);
506         res->s = INVALID_SOCKET;
507         res->lev = lev;
508         res->buflen = buflen;
509         res->family = family;
510
511         event_deferred_cb_init_(&res->deferred,
512             event_base_get_npriorities(lev->event_base) / 2,
513             accepted_socket_invoke_user_cb, res);
514
515         InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
516
517         return res;
518 }
519
520 static void
521 free_and_unlock_accepting_socket(struct accepting_socket *as)
522 {
523         /* requires lock. */
524         if (as->s != INVALID_SOCKET)
525                 closesocket(as->s);
526
527         LeaveCriticalSection(&as->lock);
528         DeleteCriticalSection(&as->lock);
529         mm_free(as);
530 }
531
532 static int
533 start_accepting(struct accepting_socket *as)
534 {
535         /* requires lock */
536         const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
537         DWORD pending = 0;
538         SOCKET s = socket(as->family, SOCK_STREAM, 0);
539         int error = 0;
540
541         if (!as->lev->base.enabled)
542                 return 0;
543
544         if (s == INVALID_SOCKET) {
545                 error = WSAGetLastError();
546                 goto report_err;
547         }
548
549         /* XXXX It turns out we need to do this again later.  Does this call
550          * have any effect? */
551         setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
552             (char *)&as->lev->fd, sizeof(&as->lev->fd));
553
554         if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
555                 evutil_make_socket_nonblocking(s);
556
557         if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
558                 closesocket(s);
559                 return -1;
560         }
561
562         as->s = s;
563
564         if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
565                 as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
566         {
567                 /* Immediate success! */
568                 accepted_socket_cb(&as->overlapped, 1, 0, 1);
569         } else {
570                 error = WSAGetLastError();
571                 if (error != ERROR_IO_PENDING) {
572                         goto report_err;
573                 }
574         }
575
576         return 0;
577
578 report_err:
579         as->error = error;
580         event_deferred_cb_schedule_(
581                 as->lev->event_base,
582                 &as->deferred);
583         return 0;
584 }
585
586 static void
587 stop_accepting(struct accepting_socket *as)
588 {
589         /* requires lock. */
590         SOCKET s = as->s;
591         as->s = INVALID_SOCKET;
592         closesocket(s);
593 }
594
595 static void
596 accepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
597 {
598         struct accepting_socket *as = arg;
599
600         struct sockaddr *sa_local=NULL, *sa_remote=NULL;
601         int socklen_local=0, socklen_remote=0;
602         const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
603         struct evconnlistener *lev = &as->lev->base;
604         evutil_socket_t sock=-1;
605         void *data;
606         evconnlistener_cb cb=NULL;
607         evconnlistener_errorcb errorcb=NULL;
608         int error;
609
610         EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
611
612         LOCK(lev);
613         EnterCriticalSection(&as->lock);
614         if (as->free_on_cb) {
615                 free_and_unlock_accepting_socket(as);
616                 listener_decref_and_unlock(lev);
617                 return;
618         }
619
620         ++lev->refcnt;
621
622         error = as->error;
623         if (error) {
624                 as->error = 0;
625                 errorcb = lev->errorcb;
626         } else {
627                 ext->GetAcceptExSockaddrs(
628                         as->addrbuf, 0, as->buflen/2, as->buflen/2,
629                         &sa_local, &socklen_local, &sa_remote,
630                         &socklen_remote);
631                 sock = as->s;
632                 cb = lev->cb;
633                 as->s = INVALID_SOCKET;
634
635                 /* We need to call this so getsockname, getpeername, and
636                  * shutdown work correctly on the accepted socket. */
637                 /* XXXX handle error? */
638                 setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
639                     (char *)&as->lev->fd, sizeof(&as->lev->fd));
640         }
641         data = lev->user_data;
642
643         LeaveCriticalSection(&as->lock);
644         UNLOCK(lev);
645
646         if (errorcb) {
647                 WSASetLastError(error);
648                 errorcb(lev, data);
649         } else if (cb) {
650                 cb(lev, sock, sa_remote, socklen_remote, data);
651         }
652
653         LOCK(lev);
654         if (listener_decref_and_unlock(lev))
655                 return;
656
657         EnterCriticalSection(&as->lock);
658         start_accepting(as);
659         LeaveCriticalSection(&as->lock);
660 }
661
662 static void
663 accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
664 {
665         struct accepting_socket *as =
666             EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
667
668         LOCK(&as->lev->base);
669         EnterCriticalSection(&as->lock);
670         if (ok) {
671                 /* XXXX Don't do this if some EV_MT flag is set. */
672                 event_deferred_cb_schedule_(
673                         as->lev->event_base,
674                         &as->deferred);
675                 LeaveCriticalSection(&as->lock);
676         } else if (as->free_on_cb) {
677                 struct evconnlistener *lev = &as->lev->base;
678                 free_and_unlock_accepting_socket(as);
679                 listener_decref_and_unlock(lev);
680                 return;
681         } else if (as->s == INVALID_SOCKET) {
682                 /* This is okay; we were disabled by iocp_listener_disable. */
683                 LeaveCriticalSection(&as->lock);
684         } else {
685                 /* Some error on accept that we couldn't actually handle. */
686                 BOOL ok;
687                 DWORD transfer = 0, flags=0;
688                 event_sock_warn(as->s, "Unexpected error on AcceptEx");
689                 ok = WSAGetOverlappedResult(as->s, &o->overlapped,
690                     &transfer, FALSE, &flags);
691                 if (ok) {
692                         /* well, that was confusing! */
693                         as->error = 1;
694                 } else {
695                         as->error = WSAGetLastError();
696                 }
697                 event_deferred_cb_schedule_(
698                         as->lev->event_base,
699                         &as->deferred);
700                 LeaveCriticalSection(&as->lock);
701         }
702         UNLOCK(&as->lev->base);
703 }
704
705 static int
706 iocp_listener_enable(struct evconnlistener *lev)
707 {
708         int i;
709         struct evconnlistener_iocp *lev_iocp =
710             EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
711
712         LOCK(lev);
713         iocp_listener_event_add(lev_iocp);
714         for (i = 0; i < lev_iocp->n_accepting; ++i) {
715                 struct accepting_socket *as = lev_iocp->accepting[i];
716                 if (!as)
717                         continue;
718                 EnterCriticalSection(&as->lock);
719                 if (!as->free_on_cb && as->s == INVALID_SOCKET)
720                         start_accepting(as);
721                 LeaveCriticalSection(&as->lock);
722         }
723         UNLOCK(lev);
724         return 0;
725 }
726
727 static int
728 iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
729 {
730         int i;
731         struct evconnlistener_iocp *lev_iocp =
732             EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
733
734         LOCK(lev);
735         iocp_listener_event_del(lev_iocp);
736         for (i = 0; i < lev_iocp->n_accepting; ++i) {
737                 struct accepting_socket *as = lev_iocp->accepting[i];
738                 if (!as)
739                         continue;
740                 EnterCriticalSection(&as->lock);
741                 if (!as->free_on_cb && as->s != INVALID_SOCKET) {
742                         if (shutdown)
743                                 as->free_on_cb = 1;
744                         stop_accepting(as);
745                 }
746                 LeaveCriticalSection(&as->lock);
747         }
748
749         if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
750                 evutil_closesocket(lev_iocp->fd);
751
752         UNLOCK(lev);
753         return 0;
754 }
755
756 static int
757 iocp_listener_disable(struct evconnlistener *lev)
758 {
759         return iocp_listener_disable_impl(lev,0);
760 }
761
762 static void
763 iocp_listener_destroy(struct evconnlistener *lev)
764 {
765         struct evconnlistener_iocp *lev_iocp =
766             EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
767
768         if (! lev_iocp->shutting_down) {
769                 lev_iocp->shutting_down = 1;
770                 iocp_listener_disable_impl(lev,1);
771         }
772
773 }
774
775 static evutil_socket_t
776 iocp_listener_getfd(struct evconnlistener *lev)
777 {
778         struct evconnlistener_iocp *lev_iocp =
779             EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
780         return lev_iocp->fd;
781 }
782 static struct event_base *
783 iocp_listener_getbase(struct evconnlistener *lev)
784 {
785         struct evconnlistener_iocp *lev_iocp =
786             EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
787         return lev_iocp->event_base;
788 }
789
790 static const struct evconnlistener_ops evconnlistener_iocp_ops = {
791         iocp_listener_enable,
792         iocp_listener_disable,
793         iocp_listener_destroy,
794         iocp_listener_destroy, /* shutdown */
795         iocp_listener_getfd,
796         iocp_listener_getbase
797 };
798
799 /* XXX define some way to override this. */
800 #define N_SOCKETS_PER_LISTENER 4
801
802 struct evconnlistener *
803 evconnlistener_new_async(struct event_base *base,
804     evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
805     evutil_socket_t fd)
806 {
807         struct sockaddr_storage ss;
808         int socklen = sizeof(ss);
809         struct evconnlistener_iocp *lev;
810         int i;
811
812         flags |= LEV_OPT_THREADSAFE;
813
814         if (!base || !event_base_get_iocp_(base))
815                 goto err;
816
817         /* XXXX duplicate code */
818         if (backlog > 0) {
819                 if (listen(fd, backlog) < 0)
820                         goto err;
821         } else if (backlog < 0) {
822                 if (listen(fd, 128) < 0)
823                         goto err;
824         }
825         if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
826                 event_sock_warn(fd, "getsockname");
827                 goto err;
828         }
829         lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
830         if (!lev) {
831                 event_warn("calloc");
832                 goto err;
833         }
834         lev->base.ops = &evconnlistener_iocp_ops;
835         lev->base.cb = cb;
836         lev->base.user_data = ptr;
837         lev->base.flags = flags;
838         lev->base.refcnt = 1;
839         lev->base.enabled = 1;
840
841         lev->port = event_base_get_iocp_(base);
842         lev->fd = fd;
843         lev->event_base = base;
844
845
846         if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
847                 goto err_free_lev;
848
849         EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
850
851         lev->n_accepting = N_SOCKETS_PER_LISTENER;
852         lev->accepting = mm_calloc(lev->n_accepting,
853             sizeof(struct accepting_socket *));
854         if (!lev->accepting) {
855                 event_warn("calloc");
856                 goto err_delete_lock;
857         }
858         for (i = 0; i < lev->n_accepting; ++i) {
859                 lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
860                 if (!lev->accepting[i]) {
861                         event_warnx("Couldn't create accepting socket");
862                         goto err_free_accepting;
863                 }
864                 if (cb && start_accepting(lev->accepting[i]) < 0) {
865                         event_warnx("Couldn't start accepting on socket");
866                         EnterCriticalSection(&lev->accepting[i]->lock);
867                         free_and_unlock_accepting_socket(lev->accepting[i]);
868                         goto err_free_accepting;
869                 }
870                 ++lev->base.refcnt;
871         }
872
873         iocp_listener_event_add(lev);
874
875         return &lev->base;
876
877 err_free_accepting:
878         mm_free(lev->accepting);
879         /* XXXX free the other elements. */
880 err_delete_lock:
881         EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
882 err_free_lev:
883         mm_free(lev);
884 err:
885         /* Don't close the fd, it is caller's responsibility. */
886         return NULL;
887 }
888
889 #endif