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