libevent: updated to 2.0.22
[tomato.git] / release / src-rt-6.x.4708 / router / libevent / listener.c
blob2b67b525e24d962295857c318311f3e95225df32
1 /*
2 * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
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.
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.
27 #include <sys/types.h>
29 #include "event2/event-config.h"
31 #ifdef WIN32
32 #ifndef _WIN32_WINNT
33 /* Minimum required for InitializeCriticalSectionAndSpinCount */
34 #define _WIN32_WINNT 0x0403
35 #endif
36 #include <winsock2.h>
37 #include <ws2tcpip.h>
38 #include <mswsock.h>
39 #endif
40 #include <errno.h>
41 #ifdef _EVENT_HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
43 #endif
44 #ifdef _EVENT_HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47 #ifdef _EVENT_HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
51 #include "event2/listener.h"
52 #include "event2/util.h"
53 #include "event2/event.h"
54 #include "event2/event_struct.h"
55 #include "mm-internal.h"
56 #include "util-internal.h"
57 #include "log-internal.h"
58 #include "evthread-internal.h"
59 #ifdef WIN32
60 #include "iocp-internal.h"
61 #include "defer-internal.h"
62 #include "event-internal.h"
63 #endif
65 struct evconnlistener_ops {
66 int (*enable)(struct evconnlistener *);
67 int (*disable)(struct evconnlistener *);
68 void (*destroy)(struct evconnlistener *);
69 void (*shutdown)(struct evconnlistener *);
70 evutil_socket_t (*getfd)(struct evconnlistener *);
71 struct event_base *(*getbase)(struct evconnlistener *);
74 struct evconnlistener {
75 const struct evconnlistener_ops *ops;
76 void *lock;
77 evconnlistener_cb cb;
78 evconnlistener_errorcb errorcb;
79 void *user_data;
80 unsigned flags;
81 short refcnt;
82 unsigned enabled : 1;
85 struct evconnlistener_event {
86 struct evconnlistener base;
87 struct event listener;
90 #ifdef WIN32
91 struct evconnlistener_iocp {
92 struct evconnlistener base;
93 evutil_socket_t fd;
94 struct event_base *event_base;
95 struct event_iocp_port *port;
96 short n_accepting;
97 unsigned shutting_down : 1;
98 unsigned event_added : 1;
99 struct accepting_socket **accepting;
101 #endif
103 #define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
104 #define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
106 struct evconnlistener *
107 evconnlistener_new_async(struct event_base *base,
108 evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
109 evutil_socket_t fd); /* XXXX export this? */
111 static int event_listener_enable(struct evconnlistener *);
112 static int event_listener_disable(struct evconnlistener *);
113 static void event_listener_destroy(struct evconnlistener *);
114 static evutil_socket_t event_listener_getfd(struct evconnlistener *);
115 static struct event_base *event_listener_getbase(struct evconnlistener *);
117 #if 0
118 static void
119 listener_incref_and_lock(struct evconnlistener *listener)
121 LOCK(listener);
122 ++listener->refcnt;
124 #endif
126 static int
127 listener_decref_and_unlock(struct evconnlistener *listener)
129 int refcnt = --listener->refcnt;
130 if (refcnt == 0) {
131 listener->ops->destroy(listener);
132 UNLOCK(listener);
133 EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
134 mm_free(listener);
135 return 1;
136 } else {
137 UNLOCK(listener);
138 return 0;
142 static const struct evconnlistener_ops evconnlistener_event_ops = {
143 event_listener_enable,
144 event_listener_disable,
145 event_listener_destroy,
146 NULL, /* shutdown */
147 event_listener_getfd,
148 event_listener_getbase
151 static void listener_read_cb(evutil_socket_t, short, void *);
153 struct evconnlistener *
154 evconnlistener_new(struct event_base *base,
155 evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
156 evutil_socket_t fd)
158 struct evconnlistener_event *lev;
160 #ifdef WIN32
161 if (base && event_base_get_iocp(base)) {
162 const struct win32_extension_fns *ext =
163 event_get_win32_extension_fns();
164 if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
165 return evconnlistener_new_async(base, cb, ptr, flags,
166 backlog, fd);
168 #endif
170 if (backlog > 0) {
171 if (listen(fd, backlog) < 0)
172 return NULL;
173 } else if (backlog < 0) {
174 if (listen(fd, 128) < 0)
175 return NULL;
178 lev = mm_calloc(1, sizeof(struct evconnlistener_event));
179 if (!lev)
180 return NULL;
182 lev->base.ops = &evconnlistener_event_ops;
183 lev->base.cb = cb;
184 lev->base.user_data = ptr;
185 lev->base.flags = flags;
186 lev->base.refcnt = 1;
188 if (flags & LEV_OPT_THREADSAFE) {
189 EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
192 event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
193 listener_read_cb, lev);
195 evconnlistener_enable(&lev->base);
197 return &lev->base;
200 struct evconnlistener *
201 evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
202 void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
203 int socklen)
205 struct evconnlistener *listener;
206 evutil_socket_t fd;
207 int on = 1;
208 int family = sa ? sa->sa_family : AF_UNSPEC;
210 if (backlog == 0)
211 return NULL;
213 fd = socket(family, SOCK_STREAM, 0);
214 if (fd == -1)
215 return NULL;
217 if (evutil_make_socket_nonblocking(fd) < 0) {
218 evutil_closesocket(fd);
219 return NULL;
222 if (flags & LEV_OPT_CLOSE_ON_EXEC) {
223 if (evutil_make_socket_closeonexec(fd) < 0) {
224 evutil_closesocket(fd);
225 return NULL;
229 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0) {
230 evutil_closesocket(fd);
231 return NULL;
233 if (flags & LEV_OPT_REUSEABLE) {
234 if (evutil_make_listen_socket_reuseable(fd) < 0) {
235 evutil_closesocket(fd);
236 return NULL;
240 if (sa) {
241 if (bind(fd, sa, socklen)<0) {
242 evutil_closesocket(fd);
243 return NULL;
247 listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
248 if (!listener) {
249 evutil_closesocket(fd);
250 return NULL;
253 return listener;
256 void
257 evconnlistener_free(struct evconnlistener *lev)
259 LOCK(lev);
260 lev->cb = NULL;
261 lev->errorcb = NULL;
262 if (lev->ops->shutdown)
263 lev->ops->shutdown(lev);
264 listener_decref_and_unlock(lev);
267 static void
268 event_listener_destroy(struct evconnlistener *lev)
270 struct evconnlistener_event *lev_e =
271 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
273 event_del(&lev_e->listener);
274 if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
275 evutil_closesocket(event_get_fd(&lev_e->listener));
276 event_debug_unassign(&lev_e->listener);
280 evconnlistener_enable(struct evconnlistener *lev)
282 int r;
283 LOCK(lev);
284 lev->enabled = 1;
285 if (lev->cb)
286 r = lev->ops->enable(lev);
287 else
288 r = 0;
289 UNLOCK(lev);
290 return r;
294 evconnlistener_disable(struct evconnlistener *lev)
296 int r;
297 LOCK(lev);
298 lev->enabled = 0;
299 r = lev->ops->disable(lev);
300 UNLOCK(lev);
301 return r;
304 static int
305 event_listener_enable(struct evconnlistener *lev)
307 struct evconnlistener_event *lev_e =
308 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
309 return event_add(&lev_e->listener, NULL);
312 static int
313 event_listener_disable(struct evconnlistener *lev)
315 struct evconnlistener_event *lev_e =
316 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
317 return event_del(&lev_e->listener);
320 evutil_socket_t
321 evconnlistener_get_fd(struct evconnlistener *lev)
323 evutil_socket_t fd;
324 LOCK(lev);
325 fd = lev->ops->getfd(lev);
326 UNLOCK(lev);
327 return fd;
330 static evutil_socket_t
331 event_listener_getfd(struct evconnlistener *lev)
333 struct evconnlistener_event *lev_e =
334 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
335 return event_get_fd(&lev_e->listener);
338 struct event_base *
339 evconnlistener_get_base(struct evconnlistener *lev)
341 struct event_base *base;
342 LOCK(lev);
343 base = lev->ops->getbase(lev);
344 UNLOCK(lev);
345 return base;
348 static struct event_base *
349 event_listener_getbase(struct evconnlistener *lev)
351 struct evconnlistener_event *lev_e =
352 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
353 return event_get_base(&lev_e->listener);
356 void
357 evconnlistener_set_cb(struct evconnlistener *lev,
358 evconnlistener_cb cb, void *arg)
360 int enable = 0;
361 LOCK(lev);
362 if (lev->enabled && !lev->cb)
363 enable = 1;
364 lev->cb = cb;
365 lev->user_data = arg;
366 if (enable)
367 evconnlistener_enable(lev);
368 UNLOCK(lev);
371 void
372 evconnlistener_set_error_cb(struct evconnlistener *lev,
373 evconnlistener_errorcb errorcb)
375 LOCK(lev);
376 lev->errorcb = errorcb;
377 UNLOCK(lev);
380 static void
381 listener_read_cb(evutil_socket_t fd, short what, void *p)
383 struct evconnlistener *lev = p;
384 int err;
385 evconnlistener_cb cb;
386 evconnlistener_errorcb errorcb;
387 void *user_data;
388 LOCK(lev);
389 while (1) {
390 struct sockaddr_storage ss;
391 #ifdef WIN32
392 int socklen = sizeof(ss);
393 #else
394 socklen_t socklen = sizeof(ss);
395 #endif
396 evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen);
397 if (new_fd < 0)
398 break;
399 if (socklen == 0) {
400 /* This can happen with some older linux kernels in
401 * response to nmap. */
402 evutil_closesocket(new_fd);
403 continue;
406 if (!(lev->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
407 evutil_make_socket_nonblocking(new_fd);
409 if (lev->cb == NULL) {
410 evutil_closesocket(new_fd);
411 UNLOCK(lev);
412 return;
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 return;
426 --lev->refcnt;
428 err = evutil_socket_geterror(fd);
429 if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
430 UNLOCK(lev);
431 return;
433 if (lev->errorcb != NULL) {
434 ++lev->refcnt;
435 errorcb = lev->errorcb;
436 user_data = lev->user_data;
437 UNLOCK(lev);
438 errorcb(lev, user_data);
439 LOCK(lev);
440 listener_decref_and_unlock(lev);
441 } else {
442 event_sock_warn(fd, "Error from accept() call");
446 #ifdef WIN32
447 struct accepting_socket {
448 CRITICAL_SECTION lock;
449 struct event_overlapped overlapped;
450 SOCKET s;
451 int error;
452 struct deferred_cb deferred;
453 struct evconnlistener_iocp *lev;
454 ev_uint8_t buflen;
455 ev_uint8_t family;
456 unsigned free_on_cb:1;
457 char addrbuf[1];
460 static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
461 ev_ssize_t n, int ok);
462 static void accepted_socket_invoke_user_cb(struct deferred_cb *cb, void *arg);
464 static void
465 iocp_listener_event_add(struct evconnlistener_iocp *lev)
467 if (lev->event_added)
468 return;
470 lev->event_added = 1;
471 event_base_add_virtual(lev->event_base);
474 static void
475 iocp_listener_event_del(struct evconnlistener_iocp *lev)
477 if (!lev->event_added)
478 return;
480 lev->event_added = 0;
481 event_base_del_virtual(lev->event_base);
484 static struct accepting_socket *
485 new_accepting_socket(struct evconnlistener_iocp *lev, int family)
487 struct accepting_socket *res;
488 int addrlen;
489 int buflen;
491 if (family == AF_INET)
492 addrlen = sizeof(struct sockaddr_in);
493 else if (family == AF_INET6)
494 addrlen = sizeof(struct sockaddr_in6);
495 else
496 return NULL;
497 buflen = (addrlen+16)*2;
499 res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
500 if (!res)
501 return NULL;
503 event_overlapped_init(&res->overlapped, accepted_socket_cb);
504 res->s = INVALID_SOCKET;
505 res->lev = lev;
506 res->buflen = buflen;
507 res->family = family;
509 event_deferred_cb_init(&res->deferred,
510 accepted_socket_invoke_user_cb, res);
512 InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
514 return res;
517 static void
518 free_and_unlock_accepting_socket(struct accepting_socket *as)
520 /* requires lock. */
521 if (as->s != INVALID_SOCKET)
522 closesocket(as->s);
524 LeaveCriticalSection(&as->lock);
525 DeleteCriticalSection(&as->lock);
526 mm_free(as);
529 static int
530 start_accepting(struct accepting_socket *as)
532 /* requires lock */
533 const struct win32_extension_fns *ext = event_get_win32_extension_fns();
534 DWORD pending = 0;
535 SOCKET s = socket(as->family, SOCK_STREAM, 0);
536 int error = 0;
538 if (!as->lev->base.enabled)
539 return 0;
541 if (s == INVALID_SOCKET) {
542 error = WSAGetLastError();
543 goto report_err;
546 /* XXXX It turns out we need to do this again later. Does this call
547 * have any effect? */
548 setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
549 (char *)&as->lev->fd, sizeof(&as->lev->fd));
551 if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
552 evutil_make_socket_nonblocking(s);
554 if (event_iocp_port_associate(as->lev->port, s, 1) < 0) {
555 closesocket(s);
556 return -1;
559 as->s = s;
561 if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
562 as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
564 /* Immediate success! */
565 accepted_socket_cb(&as->overlapped, 1, 0, 1);
566 } else {
567 error = WSAGetLastError();
568 if (error != ERROR_IO_PENDING) {
569 goto report_err;
573 return 0;
575 report_err:
576 as->error = error;
577 event_deferred_cb_schedule(
578 event_base_get_deferred_cb_queue(as->lev->event_base),
579 &as->deferred);
580 return 0;
583 static void
584 stop_accepting(struct accepting_socket *as)
586 /* requires lock. */
587 SOCKET s = as->s;
588 as->s = INVALID_SOCKET;
589 closesocket(s);
592 static void
593 accepted_socket_invoke_user_cb(struct deferred_cb *dcb, void *arg)
595 struct accepting_socket *as = arg;
597 struct sockaddr *sa_local=NULL, *sa_remote=NULL;
598 int socklen_local=0, socklen_remote=0;
599 const struct win32_extension_fns *ext = event_get_win32_extension_fns();
600 struct evconnlistener *lev = &as->lev->base;
601 evutil_socket_t sock=-1;
602 void *data;
603 evconnlistener_cb cb=NULL;
604 evconnlistener_errorcb errorcb=NULL;
605 int error;
607 EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
609 LOCK(lev);
610 EnterCriticalSection(&as->lock);
611 if (as->free_on_cb) {
612 free_and_unlock_accepting_socket(as);
613 listener_decref_and_unlock(lev);
614 return;
617 ++lev->refcnt;
619 error = as->error;
620 if (error) {
621 as->error = 0;
622 errorcb = lev->errorcb;
623 } else {
624 ext->GetAcceptExSockaddrs(
625 as->addrbuf, 0, as->buflen/2, as->buflen/2,
626 &sa_local, &socklen_local, &sa_remote,
627 &socklen_remote);
628 sock = as->s;
629 cb = lev->cb;
630 as->s = INVALID_SOCKET;
632 /* We need to call this so getsockname, getpeername, and
633 * shutdown work correctly on the accepted socket. */
634 /* XXXX handle error? */
635 setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
636 (char *)&as->lev->fd, sizeof(&as->lev->fd));
638 data = lev->user_data;
640 LeaveCriticalSection(&as->lock);
641 UNLOCK(lev);
643 if (errorcb) {
644 WSASetLastError(error);
645 errorcb(lev, data);
646 } else if (cb) {
647 cb(lev, sock, sa_remote, socklen_remote, data);
650 LOCK(lev);
651 if (listener_decref_and_unlock(lev))
652 return;
654 EnterCriticalSection(&as->lock);
655 start_accepting(as);
656 LeaveCriticalSection(&as->lock);
659 static void
660 accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
662 struct accepting_socket *as =
663 EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
665 LOCK(&as->lev->base);
666 EnterCriticalSection(&as->lock);
667 if (ok) {
668 /* XXXX Don't do this if some EV_MT flag is set. */
669 event_deferred_cb_schedule(
670 event_base_get_deferred_cb_queue(as->lev->event_base),
671 &as->deferred);
672 LeaveCriticalSection(&as->lock);
673 } else if (as->free_on_cb) {
674 struct evconnlistener *lev = &as->lev->base;
675 free_and_unlock_accepting_socket(as);
676 listener_decref_and_unlock(lev);
677 return;
678 } else if (as->s == INVALID_SOCKET) {
679 /* This is okay; we were disabled by iocp_listener_disable. */
680 LeaveCriticalSection(&as->lock);
681 } else {
682 /* Some error on accept that we couldn't actually handle. */
683 BOOL ok;
684 DWORD transfer = 0, flags=0;
685 event_sock_warn(as->s, "Unexpected error on AcceptEx");
686 ok = WSAGetOverlappedResult(as->s, &o->overlapped,
687 &transfer, FALSE, &flags);
688 if (ok) {
689 /* well, that was confusing! */
690 as->error = 1;
691 } else {
692 as->error = WSAGetLastError();
694 event_deferred_cb_schedule(
695 event_base_get_deferred_cb_queue(as->lev->event_base),
696 &as->deferred);
697 LeaveCriticalSection(&as->lock);
699 UNLOCK(&as->lev->base);
702 static int
703 iocp_listener_enable(struct evconnlistener *lev)
705 int i;
706 struct evconnlistener_iocp *lev_iocp =
707 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
709 LOCK(lev);
710 iocp_listener_event_add(lev_iocp);
711 for (i = 0; i < lev_iocp->n_accepting; ++i) {
712 struct accepting_socket *as = lev_iocp->accepting[i];
713 if (!as)
714 continue;
715 EnterCriticalSection(&as->lock);
716 if (!as->free_on_cb && as->s == INVALID_SOCKET)
717 start_accepting(as);
718 LeaveCriticalSection(&as->lock);
720 UNLOCK(lev);
721 return 0;
724 static int
725 iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
727 int i;
728 struct evconnlistener_iocp *lev_iocp =
729 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
731 LOCK(lev);
732 iocp_listener_event_del(lev_iocp);
733 for (i = 0; i < lev_iocp->n_accepting; ++i) {
734 struct accepting_socket *as = lev_iocp->accepting[i];
735 if (!as)
736 continue;
737 EnterCriticalSection(&as->lock);
738 if (!as->free_on_cb && as->s != INVALID_SOCKET) {
739 if (shutdown)
740 as->free_on_cb = 1;
741 stop_accepting(as);
743 LeaveCriticalSection(&as->lock);
746 if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
747 evutil_closesocket(lev_iocp->fd);
749 UNLOCK(lev);
750 return 0;
753 static int
754 iocp_listener_disable(struct evconnlistener *lev)
756 return iocp_listener_disable_impl(lev,0);
759 static void
760 iocp_listener_destroy(struct evconnlistener *lev)
762 struct evconnlistener_iocp *lev_iocp =
763 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
765 if (! lev_iocp->shutting_down) {
766 lev_iocp->shutting_down = 1;
767 iocp_listener_disable_impl(lev,1);
772 static evutil_socket_t
773 iocp_listener_getfd(struct evconnlistener *lev)
775 struct evconnlistener_iocp *lev_iocp =
776 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
777 return lev_iocp->fd;
779 static struct event_base *
780 iocp_listener_getbase(struct evconnlistener *lev)
782 struct evconnlistener_iocp *lev_iocp =
783 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
784 return lev_iocp->event_base;
787 static const struct evconnlistener_ops evconnlistener_iocp_ops = {
788 iocp_listener_enable,
789 iocp_listener_disable,
790 iocp_listener_destroy,
791 iocp_listener_destroy, /* shutdown */
792 iocp_listener_getfd,
793 iocp_listener_getbase
796 /* XXX define some way to override this. */
797 #define N_SOCKETS_PER_LISTENER 4
799 struct evconnlistener *
800 evconnlistener_new_async(struct event_base *base,
801 evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
802 evutil_socket_t fd)
804 struct sockaddr_storage ss;
805 int socklen = sizeof(ss);
806 struct evconnlistener_iocp *lev;
807 int i;
809 flags |= LEV_OPT_THREADSAFE;
811 if (!base || !event_base_get_iocp(base))
812 goto err;
814 /* XXXX duplicate code */
815 if (backlog > 0) {
816 if (listen(fd, backlog) < 0)
817 goto err;
818 } else if (backlog < 0) {
819 if (listen(fd, 128) < 0)
820 goto err;
822 if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
823 event_sock_warn(fd, "getsockname");
824 goto err;
826 lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
827 if (!lev) {
828 event_warn("calloc");
829 goto err;
831 lev->base.ops = &evconnlistener_iocp_ops;
832 lev->base.cb = cb;
833 lev->base.user_data = ptr;
834 lev->base.flags = flags;
835 lev->base.refcnt = 1;
836 lev->base.enabled = 1;
838 lev->port = event_base_get_iocp(base);
839 lev->fd = fd;
840 lev->event_base = base;
843 if (event_iocp_port_associate(lev->port, fd, 1) < 0)
844 goto err_free_lev;
846 EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
848 lev->n_accepting = N_SOCKETS_PER_LISTENER;
849 lev->accepting = mm_calloc(lev->n_accepting,
850 sizeof(struct accepting_socket *));
851 if (!lev->accepting) {
852 event_warn("calloc");
853 goto err_delete_lock;
855 for (i = 0; i < lev->n_accepting; ++i) {
856 lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
857 if (!lev->accepting[i]) {
858 event_warnx("Couldn't create accepting socket");
859 goto err_free_accepting;
861 if (cb && start_accepting(lev->accepting[i]) < 0) {
862 event_warnx("Couldn't start accepting on socket");
863 EnterCriticalSection(&lev->accepting[i]->lock);
864 free_and_unlock_accepting_socket(lev->accepting[i]);
865 goto err_free_accepting;
867 ++lev->base.refcnt;
870 iocp_listener_event_add(lev);
872 return &lev->base;
874 err_free_accepting:
875 mm_free(lev->accepting);
876 /* XXXX free the other elements. */
877 err_delete_lock:
878 EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
879 err_free_lev:
880 mm_free(lev);
881 err:
882 /* Don't close the fd, it is caller's responsibility. */
883 return NULL;
886 #endif