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