Remove building with NOCRYPTO option
[minix.git] / external / bsd / libevent / dist / listener.c
blob25631ea3a67db45fc94c17ef486b8d7af93d1110
1 /* $NetBSD: listener.c,v 1.1.1.2 2015/01/29 06:38:08 spz Exp $ */
2 /*
3 * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
30 #include "event2/event-config.h"
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: listener.c,v 1.1.1.2 2015/01/29 06:38:08 spz Exp $");
34 #ifdef WIN32
35 #ifndef _WIN32_WINNT
36 /* Minimum required for InitializeCriticalSectionAndSpinCount */
37 #define _WIN32_WINNT 0x0403
38 #endif
39 #include <winsock2.h>
40 #include <ws2tcpip.h>
41 #include <mswsock.h>
42 #endif
43 #include <errno.h>
44 #ifdef _EVENT_HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #ifdef _EVENT_HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50 #ifdef _EVENT_HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
54 #include "event2/listener.h"
55 #include "event2/util.h"
56 #include "event2/event.h"
57 #include "event2/event_struct.h"
58 #include "mm-internal.h"
59 #include "util-internal.h"
60 #include "log-internal.h"
61 #include "evthread-internal.h"
62 #ifdef WIN32
63 #include "iocp-internal.h"
64 #include "defer-internal.h"
65 #include "event-internal.h"
66 #endif
68 struct evconnlistener_ops {
69 int (*enable)(struct evconnlistener *);
70 int (*disable)(struct evconnlistener *);
71 void (*destroy)(struct evconnlistener *);
72 void (*shutdown)(struct evconnlistener *);
73 evutil_socket_t (*getfd)(struct evconnlistener *);
74 struct event_base *(*getbase)(struct evconnlistener *);
77 struct evconnlistener {
78 const struct evconnlistener_ops *ops;
79 void *lock;
80 evconnlistener_cb cb;
81 evconnlistener_errorcb errorcb;
82 void *user_data;
83 unsigned flags;
84 short refcnt;
85 unsigned enabled : 1;
88 struct evconnlistener_event {
89 struct evconnlistener base;
90 struct event listener;
93 #ifdef WIN32
94 struct evconnlistener_iocp {
95 struct evconnlistener base;
96 evutil_socket_t fd;
97 struct event_base *event_base;
98 struct event_iocp_port *port;
99 short n_accepting;
100 unsigned shutting_down : 1;
101 unsigned event_added : 1;
102 struct accepting_socket **accepting;
104 #endif
106 #define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
107 #define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
109 struct evconnlistener *
110 evconnlistener_new_async(struct event_base *base,
111 evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
112 evutil_socket_t fd); /* XXXX export this? */
114 static int event_listener_enable(struct evconnlistener *);
115 static int event_listener_disable(struct evconnlistener *);
116 static void event_listener_destroy(struct evconnlistener *);
117 static evutil_socket_t event_listener_getfd(struct evconnlistener *);
118 static struct event_base *event_listener_getbase(struct evconnlistener *);
120 #if 0
121 static void
122 listener_incref_and_lock(struct evconnlistener *listener)
124 LOCK(listener);
125 ++listener->refcnt;
127 #endif
129 static int
130 listener_decref_and_unlock(struct evconnlistener *listener)
132 int refcnt = --listener->refcnt;
133 if (refcnt == 0) {
134 listener->ops->destroy(listener);
135 UNLOCK(listener);
136 EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
137 mm_free(listener);
138 return 1;
139 } else {
140 UNLOCK(listener);
141 return 0;
145 static const struct evconnlistener_ops evconnlistener_event_ops = {
146 event_listener_enable,
147 event_listener_disable,
148 event_listener_destroy,
149 NULL, /* shutdown */
150 event_listener_getfd,
151 event_listener_getbase
154 static void listener_read_cb(evutil_socket_t, short, void *);
156 struct evconnlistener *
157 evconnlistener_new(struct event_base *base,
158 evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
159 evutil_socket_t fd)
161 struct evconnlistener_event *lev;
163 #ifdef WIN32
164 if (base && event_base_get_iocp(base)) {
165 const struct win32_extension_fns *ext =
166 event_get_win32_extension_fns();
167 if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
168 return evconnlistener_new_async(base, cb, ptr, flags,
169 backlog, fd);
171 #endif
173 if (backlog > 0) {
174 if (listen(fd, backlog) < 0)
175 return NULL;
176 } else if (backlog < 0) {
177 if (listen(fd, 128) < 0)
178 return NULL;
181 lev = mm_calloc(1, sizeof(struct evconnlistener_event));
182 if (!lev)
183 return NULL;
185 lev->base.ops = &evconnlistener_event_ops;
186 lev->base.cb = cb;
187 lev->base.user_data = ptr;
188 lev->base.flags = flags;
189 lev->base.refcnt = 1;
191 if (flags & LEV_OPT_THREADSAFE) {
192 EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
195 event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
196 listener_read_cb, lev);
198 evconnlistener_enable(&lev->base);
200 return &lev->base;
203 struct evconnlistener *
204 evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
205 void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
206 int socklen)
208 struct evconnlistener *listener;
209 evutil_socket_t fd;
210 int on = 1;
211 int family = sa ? sa->sa_family : AF_UNSPEC;
213 if (backlog == 0)
214 return NULL;
216 fd = socket(family, SOCK_STREAM, 0);
217 if (fd == -1)
218 return NULL;
220 if (evutil_make_socket_nonblocking(fd) < 0) {
221 evutil_closesocket(fd);
222 return NULL;
225 if (flags & LEV_OPT_CLOSE_ON_EXEC) {
226 if (evutil_make_socket_closeonexec(fd) < 0) {
227 evutil_closesocket(fd);
228 return NULL;
232 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0) {
233 evutil_closesocket(fd);
234 return NULL;
236 if (flags & LEV_OPT_REUSEABLE) {
237 if (evutil_make_listen_socket_reuseable(fd) < 0) {
238 evutil_closesocket(fd);
239 return NULL;
243 if (sa) {
244 if (bind(fd, sa, socklen)<0) {
245 evutil_closesocket(fd);
246 return NULL;
250 listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
251 if (!listener) {
252 evutil_closesocket(fd);
253 return NULL;
256 return listener;
259 void
260 evconnlistener_free(struct evconnlistener *lev)
262 LOCK(lev);
263 lev->cb = NULL;
264 lev->errorcb = NULL;
265 if (lev->ops->shutdown)
266 lev->ops->shutdown(lev);
267 listener_decref_and_unlock(lev);
270 static void
271 event_listener_destroy(struct evconnlistener *lev)
273 struct evconnlistener_event *lev_e =
274 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
276 event_del(&lev_e->listener);
277 if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
278 evutil_closesocket(event_get_fd(&lev_e->listener));
279 event_debug_unassign(&lev_e->listener);
283 evconnlistener_enable(struct evconnlistener *lev)
285 int r;
286 LOCK(lev);
287 lev->enabled = 1;
288 if (lev->cb)
289 r = lev->ops->enable(lev);
290 else
291 r = 0;
292 UNLOCK(lev);
293 return r;
297 evconnlistener_disable(struct evconnlistener *lev)
299 int r;
300 LOCK(lev);
301 lev->enabled = 0;
302 r = lev->ops->disable(lev);
303 UNLOCK(lev);
304 return r;
307 static int
308 event_listener_enable(struct evconnlistener *lev)
310 struct evconnlistener_event *lev_e =
311 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
312 return event_add(&lev_e->listener, NULL);
315 static int
316 event_listener_disable(struct evconnlistener *lev)
318 struct evconnlistener_event *lev_e =
319 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
320 return event_del(&lev_e->listener);
323 evutil_socket_t
324 evconnlistener_get_fd(struct evconnlistener *lev)
326 evutil_socket_t fd;
327 LOCK(lev);
328 fd = lev->ops->getfd(lev);
329 UNLOCK(lev);
330 return fd;
333 static evutil_socket_t
334 event_listener_getfd(struct evconnlistener *lev)
336 struct evconnlistener_event *lev_e =
337 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
338 return event_get_fd(&lev_e->listener);
341 struct event_base *
342 evconnlistener_get_base(struct evconnlistener *lev)
344 struct event_base *base;
345 LOCK(lev);
346 base = lev->ops->getbase(lev);
347 UNLOCK(lev);
348 return base;
351 static struct event_base *
352 event_listener_getbase(struct evconnlistener *lev)
354 struct evconnlistener_event *lev_e =
355 EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
356 return event_get_base(&lev_e->listener);
359 void
360 evconnlistener_set_cb(struct evconnlistener *lev,
361 evconnlistener_cb cb, void *arg)
363 int enable = 0;
364 LOCK(lev);
365 if (lev->enabled && !lev->cb)
366 enable = 1;
367 lev->cb = cb;
368 lev->user_data = arg;
369 if (enable)
370 evconnlistener_enable(lev);
371 UNLOCK(lev);
374 void
375 evconnlistener_set_error_cb(struct evconnlistener *lev,
376 evconnlistener_errorcb errorcb)
378 LOCK(lev);
379 lev->errorcb = errorcb;
380 UNLOCK(lev);
383 static void
384 listener_read_cb(evutil_socket_t fd, short what, void *p)
386 struct evconnlistener *lev = p;
387 int err;
388 evconnlistener_cb cb;
389 evconnlistener_errorcb errorcb;
390 void *user_data;
391 LOCK(lev);
392 while (1) {
393 struct sockaddr_storage ss;
394 #ifdef WIN32
395 int socklen = sizeof(ss);
396 #else
397 socklen_t socklen = sizeof(ss);
398 #endif
399 evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen);
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;
409 if (!(lev->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
410 evutil_make_socket_nonblocking(new_fd);
412 if (lev->cb == NULL) {
413 evutil_closesocket(new_fd);
414 UNLOCK(lev);
415 return;
417 ++lev->refcnt;
418 cb = lev->cb;
419 user_data = lev->user_data;
420 UNLOCK(lev);
421 cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
422 user_data);
423 LOCK(lev);
424 if (lev->refcnt == 1) {
425 int freed = listener_decref_and_unlock(lev);
426 EVUTIL_ASSERT(freed);
427 return;
429 --lev->refcnt;
431 err = evutil_socket_geterror(fd);
432 if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
433 UNLOCK(lev);
434 return;
436 if (lev->errorcb != NULL) {
437 ++lev->refcnt;
438 errorcb = lev->errorcb;
439 user_data = lev->user_data;
440 UNLOCK(lev);
441 errorcb(lev, user_data);
442 LOCK(lev);
443 listener_decref_and_unlock(lev);
444 } else {
445 event_sock_warn(fd, "Error from accept() call");
449 #ifdef WIN32
450 struct accepting_socket {
451 CRITICAL_SECTION lock;
452 struct event_overlapped overlapped;
453 SOCKET s;
454 int error;
455 struct deferred_cb deferred;
456 struct evconnlistener_iocp *lev;
457 ev_uint8_t buflen;
458 ev_uint8_t family;
459 unsigned free_on_cb:1;
460 char addrbuf[1];
463 static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
464 ev_ssize_t n, int ok);
465 static void accepted_socket_invoke_user_cb(struct deferred_cb *cb, void *arg);
467 static void
468 iocp_listener_event_add(struct evconnlistener_iocp *lev)
470 if (lev->event_added)
471 return;
473 lev->event_added = 1;
474 event_base_add_virtual(lev->event_base);
477 static void
478 iocp_listener_event_del(struct evconnlistener_iocp *lev)
480 if (!lev->event_added)
481 return;
483 lev->event_added = 0;
484 event_base_del_virtual(lev->event_base);
487 static struct accepting_socket *
488 new_accepting_socket(struct evconnlistener_iocp *lev, int family)
490 struct accepting_socket *res;
491 int addrlen;
492 int buflen;
494 if (family == AF_INET)
495 addrlen = sizeof(struct sockaddr_in);
496 else if (family == AF_INET6)
497 addrlen = sizeof(struct sockaddr_in6);
498 else
499 return NULL;
500 buflen = (addrlen+16)*2;
502 res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
503 if (!res)
504 return NULL;
506 event_overlapped_init(&res->overlapped, accepted_socket_cb);
507 res->s = INVALID_SOCKET;
508 res->lev = lev;
509 res->buflen = buflen;
510 res->family = family;
512 event_deferred_cb_init(&res->deferred,
513 accepted_socket_invoke_user_cb, res);
515 InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
517 return res;
520 static void
521 free_and_unlock_accepting_socket(struct accepting_socket *as)
523 /* requires lock. */
524 if (as->s != INVALID_SOCKET)
525 closesocket(as->s);
527 LeaveCriticalSection(&as->lock);
528 DeleteCriticalSection(&as->lock);
529 mm_free(as);
532 static int
533 start_accepting(struct accepting_socket *as)
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;
541 if (!as->lev->base.enabled)
542 return 0;
544 if (s == INVALID_SOCKET) {
545 error = WSAGetLastError();
546 goto report_err;
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));
554 if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
555 evutil_make_socket_nonblocking(s);
557 if (event_iocp_port_associate(as->lev->port, s, 1) < 0) {
558 closesocket(s);
559 return -1;
562 as->s = s;
564 if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
565 as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
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;
576 return 0;
578 report_err:
579 as->error = error;
580 event_deferred_cb_schedule(
581 event_base_get_deferred_cb_queue(as->lev->event_base),
582 &as->deferred);
583 return 0;
586 static void
587 stop_accepting(struct accepting_socket *as)
589 /* requires lock. */
590 SOCKET s = as->s;
591 as->s = INVALID_SOCKET;
592 closesocket(s);
595 static void
596 accepted_socket_invoke_user_cb(struct deferred_cb *dcb, void *arg)
598 struct accepting_socket *as = arg;
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;
610 EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
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;
620 ++lev->refcnt;
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;
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));
641 data = lev->user_data;
643 LeaveCriticalSection(&as->lock);
644 UNLOCK(lev);
646 if (errorcb) {
647 WSASetLastError(error);
648 errorcb(lev, data);
649 } else if (cb) {
650 cb(lev, sock, sa_remote, socklen_remote, data);
653 LOCK(lev);
654 if (listener_decref_and_unlock(lev))
655 return;
657 EnterCriticalSection(&as->lock);
658 start_accepting(as);
659 LeaveCriticalSection(&as->lock);
662 static void
663 accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
665 struct accepting_socket *as =
666 EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
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 event_base_get_deferred_cb_queue(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();
697 event_deferred_cb_schedule(
698 event_base_get_deferred_cb_queue(as->lev->event_base),
699 &as->deferred);
700 LeaveCriticalSection(&as->lock);
702 UNLOCK(&as->lev->base);
705 static int
706 iocp_listener_enable(struct evconnlistener *lev)
708 int i;
709 struct evconnlistener_iocp *lev_iocp =
710 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
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);
723 UNLOCK(lev);
724 return 0;
727 static int
728 iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
730 int i;
731 struct evconnlistener_iocp *lev_iocp =
732 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
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);
746 LeaveCriticalSection(&as->lock);
749 if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
750 evutil_closesocket(lev_iocp->fd);
752 UNLOCK(lev);
753 return 0;
756 static int
757 iocp_listener_disable(struct evconnlistener *lev)
759 return iocp_listener_disable_impl(lev,0);
762 static void
763 iocp_listener_destroy(struct evconnlistener *lev)
765 struct evconnlistener_iocp *lev_iocp =
766 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
768 if (! lev_iocp->shutting_down) {
769 lev_iocp->shutting_down = 1;
770 iocp_listener_disable_impl(lev,1);
775 static evutil_socket_t
776 iocp_listener_getfd(struct evconnlistener *lev)
778 struct evconnlistener_iocp *lev_iocp =
779 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
780 return lev_iocp->fd;
782 static struct event_base *
783 iocp_listener_getbase(struct evconnlistener *lev)
785 struct evconnlistener_iocp *lev_iocp =
786 EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
787 return lev_iocp->event_base;
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
799 /* XXX define some way to override this. */
800 #define N_SOCKETS_PER_LISTENER 4
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)
807 struct sockaddr_storage ss;
808 int socklen = sizeof(ss);
809 struct evconnlistener_iocp *lev;
810 int i;
812 flags |= LEV_OPT_THREADSAFE;
814 if (!base || !event_base_get_iocp(base))
815 goto err;
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;
825 if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
826 event_sock_warn(fd, "getsockname");
827 goto err;
829 lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
830 if (!lev) {
831 event_warn("calloc");
832 goto err;
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;
841 lev->port = event_base_get_iocp(base);
842 lev->fd = fd;
843 lev->event_base = base;
846 if (event_iocp_port_associate(lev->port, fd, 1) < 0)
847 goto err_free_lev;
849 EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
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;
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;
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;
870 ++lev->base.refcnt;
873 iocp_listener_event_add(lev);
875 return &lev->base;
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;
889 #endif