listener.c revision 290001
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
66struct 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
75struct 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
87struct evconnlistener_event {
88	struct evconnlistener base;
89	struct event listener;
90};
91
92#ifdef _WIN32
93struct 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
108struct evconnlistener *
109evconnlistener_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
113static int event_listener_enable(struct evconnlistener *);
114static int event_listener_disable(struct evconnlistener *);
115static void event_listener_destroy(struct evconnlistener *);
116static evutil_socket_t event_listener_getfd(struct evconnlistener *);
117static struct event_base *event_listener_getbase(struct evconnlistener *);
118
119#if 0
120static void
121listener_incref_and_lock(struct evconnlistener *listener)
122{
123	LOCK(listener);
124	++listener->refcnt;
125}
126#endif
127
128static int
129listener_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
144static 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
153static void listener_read_cb(evutil_socket_t, short, void *);
154
155struct evconnlistener *
156evconnlistener_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
209struct evconnlistener *
210evconnlistener_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;
258err:
259	evutil_closesocket(fd);
260	return NULL;
261}
262
263void
264evconnlistener_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
274static void
275event_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
286int
287evconnlistener_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
300int
301evconnlistener_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
311static int
312event_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
319static int
320event_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
327evutil_socket_t
328evconnlistener_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
337static evutil_socket_t
338event_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
345struct event_base *
346evconnlistener_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
355static struct event_base *
356event_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
363void
364evconnlistener_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
378void
379evconnlistener_set_error_cb(struct evconnlistener *lev,
380    evconnlistener_errorcb errorcb)
381{
382	LOCK(lev);
383	lev->errorcb = errorcb;
384	UNLOCK(lev);
385}
386
387static void
388listener_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
449struct 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
462static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
463    ev_ssize_t n, int ok);
464static void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
465
466static void
467iocp_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
476static void
477iocp_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
486static struct accepting_socket *
487new_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
520static void
521free_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
532static int
533start_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
578report_err:
579	as->error = error;
580	event_deferred_cb_schedule_(
581		as->lev->event_base,
582		&as->deferred);
583	return 0;
584}
585
586static void
587stop_accepting(struct accepting_socket *as)
588{
589	/* requires lock. */
590	SOCKET s = as->s;
591	as->s = INVALID_SOCKET;
592	closesocket(s);
593}
594
595static void
596accepted_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
662static void
663accepted_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
705static int
706iocp_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
727static int
728iocp_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
756static int
757iocp_listener_disable(struct evconnlistener *lev)
758{
759	return iocp_listener_disable_impl(lev,0);
760}
761
762static void
763iocp_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
775static evutil_socket_t
776iocp_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}
782static struct event_base *
783iocp_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
790static 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
802struct evconnlistener *
803evconnlistener_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
877err_free_accepting:
878	mm_free(lev->accepting);
879	/* XXXX free the other elements. */
880err_delete_lock:
881	EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
882err_free_lev:
883	mm_free(lev);
884err:
885	/* Don't close the fd, it is caller's responsibility. */
886	return NULL;
887}
888
889#endif
890