1290001Sglebius/*
2290001Sglebius * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
3290001Sglebius *
4290001Sglebius * Redistribution and use in source and binary forms, with or without
5290001Sglebius * modification, are permitted provided that the following conditions
6290001Sglebius * are met:
7290001Sglebius * 1. Redistributions of source code must retain the above copyright
8290001Sglebius *    notice, this list of conditions and the following disclaimer.
9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
10290001Sglebius *    notice, this list of conditions and the following disclaimer in the
11290001Sglebius *    documentation and/or other materials provided with the distribution.
12290001Sglebius * 3. The name of the author may not be used to endorse or promote products
13290001Sglebius *    derived from this software without specific prior written permission.
14290001Sglebius *
15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25290001Sglebius */
26290001Sglebius
27290001Sglebius#include "event2/event-config.h"
28290001Sglebius#include "evconfig-private.h"
29290001Sglebius
30290001Sglebius#include <sys/types.h>
31290001Sglebius
32290001Sglebius#ifdef _WIN32
33290001Sglebius#ifndef _WIN32_WINNT
34290001Sglebius/* Minimum required for InitializeCriticalSectionAndSpinCount */
35290001Sglebius#define _WIN32_WINNT 0x0403
36290001Sglebius#endif
37290001Sglebius#include <winsock2.h>
38290001Sglebius#include <ws2tcpip.h>
39290001Sglebius#include <mswsock.h>
40290001Sglebius#endif
41290001Sglebius#include <errno.h>
42290001Sglebius#ifdef EVENT__HAVE_SYS_SOCKET_H
43290001Sglebius#include <sys/socket.h>
44290001Sglebius#endif
45290001Sglebius#ifdef EVENT__HAVE_FCNTL_H
46290001Sglebius#include <fcntl.h>
47290001Sglebius#endif
48290001Sglebius#ifdef EVENT__HAVE_UNISTD_H
49290001Sglebius#include <unistd.h>
50290001Sglebius#endif
51290001Sglebius
52290001Sglebius#include "event2/listener.h"
53290001Sglebius#include "event2/util.h"
54290001Sglebius#include "event2/event.h"
55290001Sglebius#include "event2/event_struct.h"
56290001Sglebius#include "mm-internal.h"
57290001Sglebius#include "util-internal.h"
58290001Sglebius#include "log-internal.h"
59290001Sglebius#include "evthread-internal.h"
60290001Sglebius#ifdef _WIN32
61290001Sglebius#include "iocp-internal.h"
62290001Sglebius#include "defer-internal.h"
63290001Sglebius#include "event-internal.h"
64290001Sglebius#endif
65290001Sglebius
66290001Sglebiusstruct evconnlistener_ops {
67290001Sglebius	int (*enable)(struct evconnlistener *);
68290001Sglebius	int (*disable)(struct evconnlistener *);
69290001Sglebius	void (*destroy)(struct evconnlistener *);
70290001Sglebius	void (*shutdown)(struct evconnlistener *);
71290001Sglebius	evutil_socket_t (*getfd)(struct evconnlistener *);
72290001Sglebius	struct event_base *(*getbase)(struct evconnlistener *);
73290001Sglebius};
74290001Sglebius
75290001Sglebiusstruct evconnlistener {
76290001Sglebius	const struct evconnlistener_ops *ops;
77290001Sglebius	void *lock;
78290001Sglebius	evconnlistener_cb cb;
79290001Sglebius	evconnlistener_errorcb errorcb;
80290001Sglebius	void *user_data;
81290001Sglebius	unsigned flags;
82290001Sglebius	short refcnt;
83290001Sglebius	int accept4_flags;
84290001Sglebius	unsigned enabled : 1;
85290001Sglebius};
86290001Sglebius
87290001Sglebiusstruct evconnlistener_event {
88290001Sglebius	struct evconnlistener base;
89290001Sglebius	struct event listener;
90290001Sglebius};
91290001Sglebius
92290001Sglebius#ifdef _WIN32
93290001Sglebiusstruct evconnlistener_iocp {
94290001Sglebius	struct evconnlistener base;
95290001Sglebius	evutil_socket_t fd;
96290001Sglebius	struct event_base *event_base;
97290001Sglebius	struct event_iocp_port *port;
98290001Sglebius	short n_accepting;
99290001Sglebius	unsigned shutting_down : 1;
100290001Sglebius	unsigned event_added : 1;
101290001Sglebius	struct accepting_socket **accepting;
102290001Sglebius};
103290001Sglebius#endif
104290001Sglebius
105290001Sglebius#define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
106290001Sglebius#define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
107290001Sglebius
108290001Sglebiusstruct evconnlistener *
109290001Sglebiusevconnlistener_new_async(struct event_base *base,
110290001Sglebius    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
111290001Sglebius    evutil_socket_t fd); /* XXXX export this? */
112290001Sglebius
113290001Sglebiusstatic int event_listener_enable(struct evconnlistener *);
114290001Sglebiusstatic int event_listener_disable(struct evconnlistener *);
115290001Sglebiusstatic void event_listener_destroy(struct evconnlistener *);
116290001Sglebiusstatic evutil_socket_t event_listener_getfd(struct evconnlistener *);
117290001Sglebiusstatic struct event_base *event_listener_getbase(struct evconnlistener *);
118290001Sglebius
119290001Sglebius#if 0
120290001Sglebiusstatic void
121290001Sglebiuslistener_incref_and_lock(struct evconnlistener *listener)
122290001Sglebius{
123290001Sglebius	LOCK(listener);
124290001Sglebius	++listener->refcnt;
125290001Sglebius}
126290001Sglebius#endif
127290001Sglebius
128290001Sglebiusstatic int
129290001Sglebiuslistener_decref_and_unlock(struct evconnlistener *listener)
130290001Sglebius{
131290001Sglebius	int refcnt = --listener->refcnt;
132290001Sglebius	if (refcnt == 0) {
133290001Sglebius		listener->ops->destroy(listener);
134290001Sglebius		UNLOCK(listener);
135290001Sglebius		EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
136290001Sglebius		mm_free(listener);
137290001Sglebius		return 1;
138290001Sglebius	} else {
139290001Sglebius		UNLOCK(listener);
140290001Sglebius		return 0;
141290001Sglebius	}
142290001Sglebius}
143290001Sglebius
144290001Sglebiusstatic const struct evconnlistener_ops evconnlistener_event_ops = {
145290001Sglebius	event_listener_enable,
146290001Sglebius	event_listener_disable,
147290001Sglebius	event_listener_destroy,
148290001Sglebius	NULL, /* shutdown */
149290001Sglebius	event_listener_getfd,
150290001Sglebius	event_listener_getbase
151290001Sglebius};
152290001Sglebius
153290001Sglebiusstatic void listener_read_cb(evutil_socket_t, short, void *);
154290001Sglebius
155290001Sglebiusstruct evconnlistener *
156290001Sglebiusevconnlistener_new(struct event_base *base,
157290001Sglebius    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
158290001Sglebius    evutil_socket_t fd)
159290001Sglebius{
160290001Sglebius	struct evconnlistener_event *lev;
161290001Sglebius
162290001Sglebius#ifdef _WIN32
163290001Sglebius	if (base && event_base_get_iocp_(base)) {
164290001Sglebius		const struct win32_extension_fns *ext =
165290001Sglebius			event_get_win32_extension_fns_();
166290001Sglebius		if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
167290001Sglebius			return evconnlistener_new_async(base, cb, ptr, flags,
168290001Sglebius				backlog, fd);
169290001Sglebius	}
170290001Sglebius#endif
171290001Sglebius
172290001Sglebius	if (backlog > 0) {
173290001Sglebius		if (listen(fd, backlog) < 0)
174290001Sglebius			return NULL;
175290001Sglebius	} else if (backlog < 0) {
176290001Sglebius		if (listen(fd, 128) < 0)
177290001Sglebius			return NULL;
178290001Sglebius	}
179290001Sglebius
180290001Sglebius	lev = mm_calloc(1, sizeof(struct evconnlistener_event));
181290001Sglebius	if (!lev)
182290001Sglebius		return NULL;
183290001Sglebius
184290001Sglebius	lev->base.ops = &evconnlistener_event_ops;
185290001Sglebius	lev->base.cb = cb;
186290001Sglebius	lev->base.user_data = ptr;
187290001Sglebius	lev->base.flags = flags;
188290001Sglebius	lev->base.refcnt = 1;
189290001Sglebius
190290001Sglebius	lev->base.accept4_flags = 0;
191290001Sglebius	if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
192290001Sglebius		lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
193290001Sglebius	if (flags & LEV_OPT_CLOSE_ON_EXEC)
194290001Sglebius		lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
195290001Sglebius
196290001Sglebius	if (flags & LEV_OPT_THREADSAFE) {
197290001Sglebius		EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
198290001Sglebius	}
199290001Sglebius
200290001Sglebius	event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
201290001Sglebius	    listener_read_cb, lev);
202290001Sglebius
203290001Sglebius	if (!(flags & LEV_OPT_DISABLED))
204290001Sglebius	    evconnlistener_enable(&lev->base);
205290001Sglebius
206290001Sglebius	return &lev->base;
207290001Sglebius}
208290001Sglebius
209290001Sglebiusstruct evconnlistener *
210290001Sglebiusevconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
211290001Sglebius    void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
212290001Sglebius    int socklen)
213290001Sglebius{
214290001Sglebius	struct evconnlistener *listener;
215290001Sglebius	evutil_socket_t fd;
216290001Sglebius	int on = 1;
217290001Sglebius	int family = sa ? sa->sa_family : AF_UNSPEC;
218290001Sglebius	int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
219290001Sglebius
220290001Sglebius	if (backlog == 0)
221290001Sglebius		return NULL;
222290001Sglebius
223290001Sglebius	if (flags & LEV_OPT_CLOSE_ON_EXEC)
224290001Sglebius		socktype |= EVUTIL_SOCK_CLOEXEC;
225290001Sglebius
226290001Sglebius	fd = evutil_socket_(family, socktype, 0);
227290001Sglebius	if (fd == -1)
228290001Sglebius		return NULL;
229290001Sglebius
230290001Sglebius	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
231290001Sglebius		goto err;
232290001Sglebius
233290001Sglebius	if (flags & LEV_OPT_REUSEABLE) {
234290001Sglebius		if (evutil_make_listen_socket_reuseable(fd) < 0)
235290001Sglebius			goto err;
236290001Sglebius	}
237290001Sglebius
238290001Sglebius	if (flags & LEV_OPT_REUSEABLE_PORT) {
239290001Sglebius		if (evutil_make_listen_socket_reuseable_port(fd) < 0)
240290001Sglebius			goto err;
241290001Sglebius	}
242290001Sglebius
243290001Sglebius	if (flags & LEV_OPT_DEFERRED_ACCEPT) {
244290001Sglebius		if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
245290001Sglebius			goto err;
246290001Sglebius	}
247290001Sglebius
248290001Sglebius	if (sa) {
249290001Sglebius		if (bind(fd, sa, socklen)<0)
250290001Sglebius			goto err;
251290001Sglebius	}
252290001Sglebius
253290001Sglebius	listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
254290001Sglebius	if (!listener)
255290001Sglebius		goto err;
256290001Sglebius
257290001Sglebius	return listener;
258290001Sglebiuserr:
259290001Sglebius	evutil_closesocket(fd);
260290001Sglebius	return NULL;
261290001Sglebius}
262290001Sglebius
263290001Sglebiusvoid
264290001Sglebiusevconnlistener_free(struct evconnlistener *lev)
265290001Sglebius{
266290001Sglebius	LOCK(lev);
267290001Sglebius	lev->cb = NULL;
268290001Sglebius	lev->errorcb = NULL;
269290001Sglebius	if (lev->ops->shutdown)
270290001Sglebius		lev->ops->shutdown(lev);
271290001Sglebius	listener_decref_and_unlock(lev);
272290001Sglebius}
273290001Sglebius
274290001Sglebiusstatic void
275290001Sglebiusevent_listener_destroy(struct evconnlistener *lev)
276290001Sglebius{
277290001Sglebius	struct evconnlistener_event *lev_e =
278290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
279290001Sglebius
280290001Sglebius	event_del(&lev_e->listener);
281290001Sglebius	if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
282290001Sglebius		evutil_closesocket(event_get_fd(&lev_e->listener));
283290001Sglebius	event_debug_unassign(&lev_e->listener);
284290001Sglebius}
285290001Sglebius
286290001Sglebiusint
287290001Sglebiusevconnlistener_enable(struct evconnlistener *lev)
288290001Sglebius{
289290001Sglebius	int r;
290290001Sglebius	LOCK(lev);
291290001Sglebius	lev->enabled = 1;
292290001Sglebius	if (lev->cb)
293290001Sglebius		r = lev->ops->enable(lev);
294290001Sglebius	else
295290001Sglebius		r = 0;
296290001Sglebius	UNLOCK(lev);
297290001Sglebius	return r;
298290001Sglebius}
299290001Sglebius
300290001Sglebiusint
301290001Sglebiusevconnlistener_disable(struct evconnlistener *lev)
302290001Sglebius{
303290001Sglebius	int r;
304290001Sglebius	LOCK(lev);
305290001Sglebius	lev->enabled = 0;
306290001Sglebius	r = lev->ops->disable(lev);
307290001Sglebius	UNLOCK(lev);
308290001Sglebius	return r;
309290001Sglebius}
310290001Sglebius
311290001Sglebiusstatic int
312290001Sglebiusevent_listener_enable(struct evconnlistener *lev)
313290001Sglebius{
314290001Sglebius	struct evconnlistener_event *lev_e =
315290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
316290001Sglebius	return event_add(&lev_e->listener, NULL);
317290001Sglebius}
318290001Sglebius
319290001Sglebiusstatic int
320290001Sglebiusevent_listener_disable(struct evconnlistener *lev)
321290001Sglebius{
322290001Sglebius	struct evconnlistener_event *lev_e =
323290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
324290001Sglebius	return event_del(&lev_e->listener);
325290001Sglebius}
326290001Sglebius
327290001Sglebiusevutil_socket_t
328290001Sglebiusevconnlistener_get_fd(struct evconnlistener *lev)
329290001Sglebius{
330290001Sglebius	evutil_socket_t fd;
331290001Sglebius	LOCK(lev);
332290001Sglebius	fd = lev->ops->getfd(lev);
333290001Sglebius	UNLOCK(lev);
334290001Sglebius	return fd;
335290001Sglebius}
336290001Sglebius
337290001Sglebiusstatic evutil_socket_t
338290001Sglebiusevent_listener_getfd(struct evconnlistener *lev)
339290001Sglebius{
340290001Sglebius	struct evconnlistener_event *lev_e =
341290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
342290001Sglebius	return event_get_fd(&lev_e->listener);
343290001Sglebius}
344290001Sglebius
345290001Sglebiusstruct event_base *
346290001Sglebiusevconnlistener_get_base(struct evconnlistener *lev)
347290001Sglebius{
348290001Sglebius	struct event_base *base;
349290001Sglebius	LOCK(lev);
350290001Sglebius	base = lev->ops->getbase(lev);
351290001Sglebius	UNLOCK(lev);
352290001Sglebius	return base;
353290001Sglebius}
354290001Sglebius
355290001Sglebiusstatic struct event_base *
356290001Sglebiusevent_listener_getbase(struct evconnlistener *lev)
357290001Sglebius{
358290001Sglebius	struct evconnlistener_event *lev_e =
359290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
360290001Sglebius	return event_get_base(&lev_e->listener);
361290001Sglebius}
362290001Sglebius
363290001Sglebiusvoid
364290001Sglebiusevconnlistener_set_cb(struct evconnlistener *lev,
365290001Sglebius    evconnlistener_cb cb, void *arg)
366290001Sglebius{
367290001Sglebius	int enable = 0;
368290001Sglebius	LOCK(lev);
369290001Sglebius	if (lev->enabled && !lev->cb)
370290001Sglebius		enable = 1;
371290001Sglebius	lev->cb = cb;
372290001Sglebius	lev->user_data = arg;
373290001Sglebius	if (enable)
374290001Sglebius		evconnlistener_enable(lev);
375290001Sglebius	UNLOCK(lev);
376290001Sglebius}
377290001Sglebius
378290001Sglebiusvoid
379290001Sglebiusevconnlistener_set_error_cb(struct evconnlistener *lev,
380290001Sglebius    evconnlistener_errorcb errorcb)
381290001Sglebius{
382290001Sglebius	LOCK(lev);
383290001Sglebius	lev->errorcb = errorcb;
384290001Sglebius	UNLOCK(lev);
385290001Sglebius}
386290001Sglebius
387290001Sglebiusstatic void
388290001Sglebiuslistener_read_cb(evutil_socket_t fd, short what, void *p)
389290001Sglebius{
390290001Sglebius	struct evconnlistener *lev = p;
391290001Sglebius	int err;
392290001Sglebius	evconnlistener_cb cb;
393290001Sglebius	evconnlistener_errorcb errorcb;
394290001Sglebius	void *user_data;
395290001Sglebius	LOCK(lev);
396290001Sglebius	while (1) {
397290001Sglebius		struct sockaddr_storage ss;
398290001Sglebius		ev_socklen_t socklen = sizeof(ss);
399290001Sglebius		evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
400290001Sglebius		if (new_fd < 0)
401290001Sglebius			break;
402290001Sglebius		if (socklen == 0) {
403290001Sglebius			/* This can happen with some older linux kernels in
404290001Sglebius			 * response to nmap. */
405290001Sglebius			evutil_closesocket(new_fd);
406290001Sglebius			continue;
407290001Sglebius		}
408290001Sglebius
409290001Sglebius		if (lev->cb == NULL) {
410290001Sglebius			evutil_closesocket(new_fd);
411290001Sglebius			UNLOCK(lev);
412290001Sglebius			return;
413290001Sglebius		}
414290001Sglebius		++lev->refcnt;
415290001Sglebius		cb = lev->cb;
416290001Sglebius		user_data = lev->user_data;
417290001Sglebius		UNLOCK(lev);
418290001Sglebius		cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
419290001Sglebius		    user_data);
420290001Sglebius		LOCK(lev);
421290001Sglebius		if (lev->refcnt == 1) {
422290001Sglebius			int freed = listener_decref_and_unlock(lev);
423290001Sglebius			EVUTIL_ASSERT(freed);
424290001Sglebius
425290001Sglebius			evutil_closesocket(new_fd);
426290001Sglebius			return;
427290001Sglebius		}
428290001Sglebius		--lev->refcnt;
429290001Sglebius	}
430290001Sglebius	err = evutil_socket_geterror(fd);
431290001Sglebius	if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
432290001Sglebius		UNLOCK(lev);
433290001Sglebius		return;
434290001Sglebius	}
435290001Sglebius	if (lev->errorcb != NULL) {
436290001Sglebius		++lev->refcnt;
437290001Sglebius		errorcb = lev->errorcb;
438290001Sglebius		user_data = lev->user_data;
439290001Sglebius		UNLOCK(lev);
440290001Sglebius		errorcb(lev, user_data);
441290001Sglebius		LOCK(lev);
442290001Sglebius		listener_decref_and_unlock(lev);
443290001Sglebius	} else {
444290001Sglebius		event_sock_warn(fd, "Error from accept() call");
445290001Sglebius	}
446290001Sglebius}
447290001Sglebius
448290001Sglebius#ifdef _WIN32
449290001Sglebiusstruct accepting_socket {
450290001Sglebius	CRITICAL_SECTION lock;
451290001Sglebius	struct event_overlapped overlapped;
452290001Sglebius	SOCKET s;
453290001Sglebius	int error;
454290001Sglebius	struct event_callback deferred;
455290001Sglebius	struct evconnlistener_iocp *lev;
456290001Sglebius	ev_uint8_t buflen;
457290001Sglebius	ev_uint8_t family;
458290001Sglebius	unsigned free_on_cb:1;
459290001Sglebius	char addrbuf[1];
460290001Sglebius};
461290001Sglebius
462290001Sglebiusstatic void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
463290001Sglebius    ev_ssize_t n, int ok);
464290001Sglebiusstatic void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
465290001Sglebius
466290001Sglebiusstatic void
467290001Sglebiusiocp_listener_event_add(struct evconnlistener_iocp *lev)
468290001Sglebius{
469290001Sglebius	if (lev->event_added)
470290001Sglebius		return;
471290001Sglebius
472290001Sglebius	lev->event_added = 1;
473290001Sglebius	event_base_add_virtual_(lev->event_base);
474290001Sglebius}
475290001Sglebius
476290001Sglebiusstatic void
477290001Sglebiusiocp_listener_event_del(struct evconnlistener_iocp *lev)
478290001Sglebius{
479290001Sglebius	if (!lev->event_added)
480290001Sglebius		return;
481290001Sglebius
482290001Sglebius	lev->event_added = 0;
483290001Sglebius	event_base_del_virtual_(lev->event_base);
484290001Sglebius}
485290001Sglebius
486290001Sglebiusstatic struct accepting_socket *
487290001Sglebiusnew_accepting_socket(struct evconnlistener_iocp *lev, int family)
488290001Sglebius{
489290001Sglebius	struct accepting_socket *res;
490290001Sglebius	int addrlen;
491290001Sglebius	int buflen;
492290001Sglebius
493290001Sglebius	if (family == AF_INET)
494290001Sglebius		addrlen = sizeof(struct sockaddr_in);
495290001Sglebius	else if (family == AF_INET6)
496290001Sglebius		addrlen = sizeof(struct sockaddr_in6);
497290001Sglebius	else
498290001Sglebius		return NULL;
499290001Sglebius	buflen = (addrlen+16)*2;
500290001Sglebius
501290001Sglebius	res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
502290001Sglebius	if (!res)
503290001Sglebius		return NULL;
504290001Sglebius
505290001Sglebius	event_overlapped_init_(&res->overlapped, accepted_socket_cb);
506290001Sglebius	res->s = INVALID_SOCKET;
507290001Sglebius	res->lev = lev;
508290001Sglebius	res->buflen = buflen;
509290001Sglebius	res->family = family;
510290001Sglebius
511290001Sglebius	event_deferred_cb_init_(&res->deferred,
512290001Sglebius	    event_base_get_npriorities(lev->event_base) / 2,
513290001Sglebius	    accepted_socket_invoke_user_cb, res);
514290001Sglebius
515290001Sglebius	InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
516290001Sglebius
517290001Sglebius	return res;
518290001Sglebius}
519290001Sglebius
520290001Sglebiusstatic void
521290001Sglebiusfree_and_unlock_accepting_socket(struct accepting_socket *as)
522290001Sglebius{
523290001Sglebius	/* requires lock. */
524290001Sglebius	if (as->s != INVALID_SOCKET)
525290001Sglebius		closesocket(as->s);
526290001Sglebius
527290001Sglebius	LeaveCriticalSection(&as->lock);
528290001Sglebius	DeleteCriticalSection(&as->lock);
529290001Sglebius	mm_free(as);
530290001Sglebius}
531290001Sglebius
532290001Sglebiusstatic int
533290001Sglebiusstart_accepting(struct accepting_socket *as)
534290001Sglebius{
535290001Sglebius	/* requires lock */
536290001Sglebius	const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
537290001Sglebius	DWORD pending = 0;
538290001Sglebius	SOCKET s = socket(as->family, SOCK_STREAM, 0);
539290001Sglebius	int error = 0;
540290001Sglebius
541290001Sglebius	if (!as->lev->base.enabled)
542290001Sglebius		return 0;
543290001Sglebius
544290001Sglebius	if (s == INVALID_SOCKET) {
545290001Sglebius		error = WSAGetLastError();
546290001Sglebius		goto report_err;
547290001Sglebius	}
548290001Sglebius
549290001Sglebius	/* XXXX It turns out we need to do this again later.  Does this call
550290001Sglebius	 * have any effect? */
551290001Sglebius	setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
552290001Sglebius	    (char *)&as->lev->fd, sizeof(&as->lev->fd));
553290001Sglebius
554290001Sglebius	if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
555290001Sglebius		evutil_make_socket_nonblocking(s);
556290001Sglebius
557290001Sglebius	if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
558290001Sglebius		closesocket(s);
559290001Sglebius		return -1;
560290001Sglebius	}
561290001Sglebius
562290001Sglebius	as->s = s;
563290001Sglebius
564290001Sglebius	if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
565290001Sglebius		as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
566290001Sglebius	{
567290001Sglebius		/* Immediate success! */
568290001Sglebius		accepted_socket_cb(&as->overlapped, 1, 0, 1);
569290001Sglebius	} else {
570290001Sglebius		error = WSAGetLastError();
571290001Sglebius		if (error != ERROR_IO_PENDING) {
572290001Sglebius			goto report_err;
573290001Sglebius		}
574290001Sglebius	}
575290001Sglebius
576290001Sglebius	return 0;
577290001Sglebius
578290001Sglebiusreport_err:
579290001Sglebius	as->error = error;
580290001Sglebius	event_deferred_cb_schedule_(
581290001Sglebius		as->lev->event_base,
582290001Sglebius		&as->deferred);
583290001Sglebius	return 0;
584290001Sglebius}
585290001Sglebius
586290001Sglebiusstatic void
587290001Sglebiusstop_accepting(struct accepting_socket *as)
588290001Sglebius{
589290001Sglebius	/* requires lock. */
590290001Sglebius	SOCKET s = as->s;
591290001Sglebius	as->s = INVALID_SOCKET;
592290001Sglebius	closesocket(s);
593290001Sglebius}
594290001Sglebius
595290001Sglebiusstatic void
596290001Sglebiusaccepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
597290001Sglebius{
598290001Sglebius	struct accepting_socket *as = arg;
599290001Sglebius
600290001Sglebius	struct sockaddr *sa_local=NULL, *sa_remote=NULL;
601290001Sglebius	int socklen_local=0, socklen_remote=0;
602290001Sglebius	const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
603290001Sglebius	struct evconnlistener *lev = &as->lev->base;
604290001Sglebius	evutil_socket_t sock=-1;
605290001Sglebius	void *data;
606290001Sglebius	evconnlistener_cb cb=NULL;
607290001Sglebius	evconnlistener_errorcb errorcb=NULL;
608290001Sglebius	int error;
609290001Sglebius
610290001Sglebius	EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
611290001Sglebius
612290001Sglebius	LOCK(lev);
613290001Sglebius	EnterCriticalSection(&as->lock);
614290001Sglebius	if (as->free_on_cb) {
615290001Sglebius		free_and_unlock_accepting_socket(as);
616290001Sglebius		listener_decref_and_unlock(lev);
617290001Sglebius		return;
618290001Sglebius	}
619290001Sglebius
620290001Sglebius	++lev->refcnt;
621290001Sglebius
622290001Sglebius	error = as->error;
623290001Sglebius	if (error) {
624290001Sglebius		as->error = 0;
625290001Sglebius		errorcb = lev->errorcb;
626290001Sglebius	} else {
627290001Sglebius		ext->GetAcceptExSockaddrs(
628290001Sglebius			as->addrbuf, 0, as->buflen/2, as->buflen/2,
629290001Sglebius			&sa_local, &socklen_local, &sa_remote,
630290001Sglebius			&socklen_remote);
631290001Sglebius		sock = as->s;
632290001Sglebius		cb = lev->cb;
633290001Sglebius		as->s = INVALID_SOCKET;
634290001Sglebius
635290001Sglebius		/* We need to call this so getsockname, getpeername, and
636290001Sglebius		 * shutdown work correctly on the accepted socket. */
637290001Sglebius		/* XXXX handle error? */
638290001Sglebius		setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
639290001Sglebius		    (char *)&as->lev->fd, sizeof(&as->lev->fd));
640290001Sglebius	}
641290001Sglebius	data = lev->user_data;
642290001Sglebius
643290001Sglebius	LeaveCriticalSection(&as->lock);
644290001Sglebius	UNLOCK(lev);
645290001Sglebius
646290001Sglebius	if (errorcb) {
647290001Sglebius		WSASetLastError(error);
648290001Sglebius		errorcb(lev, data);
649290001Sglebius	} else if (cb) {
650290001Sglebius		cb(lev, sock, sa_remote, socklen_remote, data);
651290001Sglebius	}
652290001Sglebius
653290001Sglebius	LOCK(lev);
654290001Sglebius	if (listener_decref_and_unlock(lev))
655290001Sglebius		return;
656290001Sglebius
657290001Sglebius	EnterCriticalSection(&as->lock);
658290001Sglebius	start_accepting(as);
659290001Sglebius	LeaveCriticalSection(&as->lock);
660290001Sglebius}
661290001Sglebius
662290001Sglebiusstatic void
663290001Sglebiusaccepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
664290001Sglebius{
665290001Sglebius	struct accepting_socket *as =
666290001Sglebius	    EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
667290001Sglebius
668290001Sglebius	LOCK(&as->lev->base);
669290001Sglebius	EnterCriticalSection(&as->lock);
670290001Sglebius	if (ok) {
671290001Sglebius		/* XXXX Don't do this if some EV_MT flag is set. */
672290001Sglebius		event_deferred_cb_schedule_(
673290001Sglebius			as->lev->event_base,
674290001Sglebius			&as->deferred);
675290001Sglebius		LeaveCriticalSection(&as->lock);
676290001Sglebius	} else if (as->free_on_cb) {
677290001Sglebius		struct evconnlistener *lev = &as->lev->base;
678290001Sglebius		free_and_unlock_accepting_socket(as);
679290001Sglebius		listener_decref_and_unlock(lev);
680290001Sglebius		return;
681290001Sglebius	} else if (as->s == INVALID_SOCKET) {
682290001Sglebius		/* This is okay; we were disabled by iocp_listener_disable. */
683290001Sglebius		LeaveCriticalSection(&as->lock);
684290001Sglebius	} else {
685290001Sglebius		/* Some error on accept that we couldn't actually handle. */
686290001Sglebius		BOOL ok;
687290001Sglebius		DWORD transfer = 0, flags=0;
688290001Sglebius		event_sock_warn(as->s, "Unexpected error on AcceptEx");
689290001Sglebius		ok = WSAGetOverlappedResult(as->s, &o->overlapped,
690290001Sglebius		    &transfer, FALSE, &flags);
691290001Sglebius		if (ok) {
692290001Sglebius			/* well, that was confusing! */
693290001Sglebius			as->error = 1;
694290001Sglebius		} else {
695290001Sglebius			as->error = WSAGetLastError();
696290001Sglebius		}
697290001Sglebius		event_deferred_cb_schedule_(
698290001Sglebius			as->lev->event_base,
699290001Sglebius			&as->deferred);
700290001Sglebius		LeaveCriticalSection(&as->lock);
701290001Sglebius	}
702290001Sglebius	UNLOCK(&as->lev->base);
703290001Sglebius}
704290001Sglebius
705290001Sglebiusstatic int
706290001Sglebiusiocp_listener_enable(struct evconnlistener *lev)
707290001Sglebius{
708290001Sglebius	int i;
709290001Sglebius	struct evconnlistener_iocp *lev_iocp =
710290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
711290001Sglebius
712290001Sglebius	LOCK(lev);
713290001Sglebius	iocp_listener_event_add(lev_iocp);
714290001Sglebius	for (i = 0; i < lev_iocp->n_accepting; ++i) {
715290001Sglebius		struct accepting_socket *as = lev_iocp->accepting[i];
716290001Sglebius		if (!as)
717290001Sglebius			continue;
718290001Sglebius		EnterCriticalSection(&as->lock);
719290001Sglebius		if (!as->free_on_cb && as->s == INVALID_SOCKET)
720290001Sglebius			start_accepting(as);
721290001Sglebius		LeaveCriticalSection(&as->lock);
722290001Sglebius	}
723290001Sglebius	UNLOCK(lev);
724290001Sglebius	return 0;
725290001Sglebius}
726290001Sglebius
727290001Sglebiusstatic int
728290001Sglebiusiocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
729290001Sglebius{
730290001Sglebius	int i;
731290001Sglebius	struct evconnlistener_iocp *lev_iocp =
732290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
733290001Sglebius
734290001Sglebius	LOCK(lev);
735290001Sglebius	iocp_listener_event_del(lev_iocp);
736290001Sglebius	for (i = 0; i < lev_iocp->n_accepting; ++i) {
737290001Sglebius		struct accepting_socket *as = lev_iocp->accepting[i];
738290001Sglebius		if (!as)
739290001Sglebius			continue;
740290001Sglebius		EnterCriticalSection(&as->lock);
741290001Sglebius		if (!as->free_on_cb && as->s != INVALID_SOCKET) {
742290001Sglebius			if (shutdown)
743290001Sglebius				as->free_on_cb = 1;
744290001Sglebius			stop_accepting(as);
745290001Sglebius		}
746290001Sglebius		LeaveCriticalSection(&as->lock);
747290001Sglebius	}
748290001Sglebius
749290001Sglebius	if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
750290001Sglebius		evutil_closesocket(lev_iocp->fd);
751290001Sglebius
752290001Sglebius	UNLOCK(lev);
753290001Sglebius	return 0;
754290001Sglebius}
755290001Sglebius
756290001Sglebiusstatic int
757290001Sglebiusiocp_listener_disable(struct evconnlistener *lev)
758290001Sglebius{
759290001Sglebius	return iocp_listener_disable_impl(lev,0);
760290001Sglebius}
761290001Sglebius
762290001Sglebiusstatic void
763290001Sglebiusiocp_listener_destroy(struct evconnlistener *lev)
764290001Sglebius{
765290001Sglebius	struct evconnlistener_iocp *lev_iocp =
766290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
767290001Sglebius
768290001Sglebius	if (! lev_iocp->shutting_down) {
769290001Sglebius		lev_iocp->shutting_down = 1;
770290001Sglebius		iocp_listener_disable_impl(lev,1);
771290001Sglebius	}
772290001Sglebius
773290001Sglebius}
774290001Sglebius
775290001Sglebiusstatic evutil_socket_t
776290001Sglebiusiocp_listener_getfd(struct evconnlistener *lev)
777290001Sglebius{
778290001Sglebius	struct evconnlistener_iocp *lev_iocp =
779290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
780290001Sglebius	return lev_iocp->fd;
781290001Sglebius}
782290001Sglebiusstatic struct event_base *
783290001Sglebiusiocp_listener_getbase(struct evconnlistener *lev)
784290001Sglebius{
785290001Sglebius	struct evconnlistener_iocp *lev_iocp =
786290001Sglebius	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
787290001Sglebius	return lev_iocp->event_base;
788290001Sglebius}
789290001Sglebius
790290001Sglebiusstatic const struct evconnlistener_ops evconnlistener_iocp_ops = {
791290001Sglebius	iocp_listener_enable,
792290001Sglebius	iocp_listener_disable,
793290001Sglebius	iocp_listener_destroy,
794290001Sglebius	iocp_listener_destroy, /* shutdown */
795290001Sglebius	iocp_listener_getfd,
796290001Sglebius	iocp_listener_getbase
797290001Sglebius};
798290001Sglebius
799290001Sglebius/* XXX define some way to override this. */
800290001Sglebius#define N_SOCKETS_PER_LISTENER 4
801290001Sglebius
802290001Sglebiusstruct evconnlistener *
803290001Sglebiusevconnlistener_new_async(struct event_base *base,
804290001Sglebius    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
805290001Sglebius    evutil_socket_t fd)
806290001Sglebius{
807290001Sglebius	struct sockaddr_storage ss;
808290001Sglebius	int socklen = sizeof(ss);
809290001Sglebius	struct evconnlistener_iocp *lev;
810290001Sglebius	int i;
811290001Sglebius
812290001Sglebius	flags |= LEV_OPT_THREADSAFE;
813290001Sglebius
814290001Sglebius	if (!base || !event_base_get_iocp_(base))
815290001Sglebius		goto err;
816290001Sglebius
817290001Sglebius	/* XXXX duplicate code */
818290001Sglebius	if (backlog > 0) {
819290001Sglebius		if (listen(fd, backlog) < 0)
820290001Sglebius			goto err;
821290001Sglebius	} else if (backlog < 0) {
822290001Sglebius		if (listen(fd, 128) < 0)
823290001Sglebius			goto err;
824290001Sglebius	}
825290001Sglebius	if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
826290001Sglebius		event_sock_warn(fd, "getsockname");
827290001Sglebius		goto err;
828290001Sglebius	}
829290001Sglebius	lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
830290001Sglebius	if (!lev) {
831290001Sglebius		event_warn("calloc");
832290001Sglebius		goto err;
833290001Sglebius	}
834290001Sglebius	lev->base.ops = &evconnlistener_iocp_ops;
835290001Sglebius	lev->base.cb = cb;
836290001Sglebius	lev->base.user_data = ptr;
837290001Sglebius	lev->base.flags = flags;
838290001Sglebius	lev->base.refcnt = 1;
839290001Sglebius	lev->base.enabled = 1;
840290001Sglebius
841290001Sglebius	lev->port = event_base_get_iocp_(base);
842290001Sglebius	lev->fd = fd;
843290001Sglebius	lev->event_base = base;
844290001Sglebius
845290001Sglebius
846290001Sglebius	if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
847290001Sglebius		goto err_free_lev;
848290001Sglebius
849290001Sglebius	EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
850290001Sglebius
851290001Sglebius	lev->n_accepting = N_SOCKETS_PER_LISTENER;
852290001Sglebius	lev->accepting = mm_calloc(lev->n_accepting,
853290001Sglebius	    sizeof(struct accepting_socket *));
854290001Sglebius	if (!lev->accepting) {
855290001Sglebius		event_warn("calloc");
856290001Sglebius		goto err_delete_lock;
857290001Sglebius	}
858290001Sglebius	for (i = 0; i < lev->n_accepting; ++i) {
859290001Sglebius		lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
860290001Sglebius		if (!lev->accepting[i]) {
861290001Sglebius			event_warnx("Couldn't create accepting socket");
862290001Sglebius			goto err_free_accepting;
863290001Sglebius		}
864290001Sglebius		if (cb && start_accepting(lev->accepting[i]) < 0) {
865290001Sglebius			event_warnx("Couldn't start accepting on socket");
866290001Sglebius			EnterCriticalSection(&lev->accepting[i]->lock);
867290001Sglebius			free_and_unlock_accepting_socket(lev->accepting[i]);
868290001Sglebius			goto err_free_accepting;
869290001Sglebius		}
870290001Sglebius		++lev->base.refcnt;
871290001Sglebius	}
872290001Sglebius
873290001Sglebius	iocp_listener_event_add(lev);
874290001Sglebius
875290001Sglebius	return &lev->base;
876290001Sglebius
877290001Sglebiuserr_free_accepting:
878290001Sglebius	mm_free(lev->accepting);
879290001Sglebius	/* XXXX free the other elements. */
880290001Sglebiuserr_delete_lock:
881290001Sglebius	EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
882290001Sglebiuserr_free_lev:
883290001Sglebius	mm_free(lev);
884290001Sglebiuserr:
885290001Sglebius	/* Don't close the fd, it is caller's responsibility. */
886290001Sglebius	return NULL;
887290001Sglebius}
888290001Sglebius
889290001Sglebius#endif
890