1275970Scy/*
2275970Scy * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
3275970Scy *
4275970Scy * Redistribution and use in source and binary forms, with or without
5275970Scy * modification, are permitted provided that the following conditions
6275970Scy * are met:
7275970Scy * 1. Redistributions of source code must retain the above copyright
8275970Scy *    notice, this list of conditions and the following disclaimer.
9275970Scy * 2. Redistributions in binary form must reproduce the above copyright
10275970Scy *    notice, this list of conditions and the following disclaimer in the
11275970Scy *    documentation and/or other materials provided with the distribution.
12275970Scy * 3. The name of the author may not be used to endorse or promote products
13275970Scy *    derived from this software without specific prior written permission.
14275970Scy *
15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25275970Scy */
26275970Scy
27275970Scy#include "event2/event-config.h"
28275970Scy#include "evconfig-private.h"
29275970Scy
30275970Scy#include <sys/types.h>
31275970Scy
32275970Scy#ifdef _WIN32
33275970Scy#ifndef _WIN32_WINNT
34275970Scy/* Minimum required for InitializeCriticalSectionAndSpinCount */
35275970Scy#define _WIN32_WINNT 0x0403
36275970Scy#endif
37275970Scy#include <winsock2.h>
38275970Scy#include <ws2tcpip.h>
39275970Scy#include <mswsock.h>
40275970Scy#endif
41275970Scy#include <errno.h>
42275970Scy#ifdef EVENT__HAVE_SYS_SOCKET_H
43275970Scy#include <sys/socket.h>
44275970Scy#endif
45275970Scy#ifdef EVENT__HAVE_FCNTL_H
46275970Scy#include <fcntl.h>
47275970Scy#endif
48275970Scy#ifdef EVENT__HAVE_UNISTD_H
49275970Scy#include <unistd.h>
50275970Scy#endif
51275970Scy
52275970Scy#include "event2/listener.h"
53275970Scy#include "event2/util.h"
54275970Scy#include "event2/event.h"
55275970Scy#include "event2/event_struct.h"
56275970Scy#include "mm-internal.h"
57275970Scy#include "util-internal.h"
58275970Scy#include "log-internal.h"
59275970Scy#include "evthread-internal.h"
60275970Scy#ifdef _WIN32
61275970Scy#include "iocp-internal.h"
62275970Scy#include "defer-internal.h"
63275970Scy#include "event-internal.h"
64275970Scy#endif
65275970Scy
66275970Scystruct evconnlistener_ops {
67275970Scy	int (*enable)(struct evconnlistener *);
68275970Scy	int (*disable)(struct evconnlistener *);
69275970Scy	void (*destroy)(struct evconnlistener *);
70275970Scy	void (*shutdown)(struct evconnlistener *);
71275970Scy	evutil_socket_t (*getfd)(struct evconnlistener *);
72275970Scy	struct event_base *(*getbase)(struct evconnlistener *);
73275970Scy};
74275970Scy
75275970Scystruct evconnlistener {
76275970Scy	const struct evconnlistener_ops *ops;
77275970Scy	void *lock;
78275970Scy	evconnlistener_cb cb;
79275970Scy	evconnlistener_errorcb errorcb;
80275970Scy	void *user_data;
81275970Scy	unsigned flags;
82275970Scy	short refcnt;
83275970Scy	int accept4_flags;
84275970Scy	unsigned enabled : 1;
85275970Scy};
86275970Scy
87275970Scystruct evconnlistener_event {
88275970Scy	struct evconnlistener base;
89275970Scy	struct event listener;
90275970Scy};
91275970Scy
92275970Scy#ifdef _WIN32
93275970Scystruct evconnlistener_iocp {
94275970Scy	struct evconnlistener base;
95275970Scy	evutil_socket_t fd;
96275970Scy	struct event_base *event_base;
97275970Scy	struct event_iocp_port *port;
98275970Scy	short n_accepting;
99275970Scy	unsigned shutting_down : 1;
100275970Scy	unsigned event_added : 1;
101275970Scy	struct accepting_socket **accepting;
102275970Scy};
103275970Scy#endif
104275970Scy
105275970Scy#define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
106275970Scy#define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
107275970Scy
108275970Scystruct evconnlistener *
109275970Scyevconnlistener_new_async(struct event_base *base,
110275970Scy    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
111275970Scy    evutil_socket_t fd); /* XXXX export this? */
112275970Scy
113275970Scystatic int event_listener_enable(struct evconnlistener *);
114275970Scystatic int event_listener_disable(struct evconnlistener *);
115275970Scystatic void event_listener_destroy(struct evconnlistener *);
116275970Scystatic evutil_socket_t event_listener_getfd(struct evconnlistener *);
117275970Scystatic struct event_base *event_listener_getbase(struct evconnlistener *);
118275970Scy
119275970Scy#if 0
120275970Scystatic void
121275970Scylistener_incref_and_lock(struct evconnlistener *listener)
122275970Scy{
123275970Scy	LOCK(listener);
124275970Scy	++listener->refcnt;
125275970Scy}
126275970Scy#endif
127275970Scy
128275970Scystatic int
129275970Scylistener_decref_and_unlock(struct evconnlistener *listener)
130275970Scy{
131275970Scy	int refcnt = --listener->refcnt;
132275970Scy	if (refcnt == 0) {
133275970Scy		listener->ops->destroy(listener);
134275970Scy		UNLOCK(listener);
135275970Scy		EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
136275970Scy		mm_free(listener);
137275970Scy		return 1;
138275970Scy	} else {
139275970Scy		UNLOCK(listener);
140275970Scy		return 0;
141275970Scy	}
142275970Scy}
143275970Scy
144275970Scystatic const struct evconnlistener_ops evconnlistener_event_ops = {
145275970Scy	event_listener_enable,
146275970Scy	event_listener_disable,
147275970Scy	event_listener_destroy,
148275970Scy	NULL, /* shutdown */
149275970Scy	event_listener_getfd,
150275970Scy	event_listener_getbase
151275970Scy};
152275970Scy
153275970Scystatic void listener_read_cb(evutil_socket_t, short, void *);
154275970Scy
155275970Scystruct evconnlistener *
156275970Scyevconnlistener_new(struct event_base *base,
157275970Scy    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
158275970Scy    evutil_socket_t fd)
159275970Scy{
160275970Scy	struct evconnlistener_event *lev;
161275970Scy
162275970Scy#ifdef _WIN32
163275970Scy	if (base && event_base_get_iocp_(base)) {
164275970Scy		const struct win32_extension_fns *ext =
165275970Scy			event_get_win32_extension_fns_();
166275970Scy		if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
167275970Scy			return evconnlistener_new_async(base, cb, ptr, flags,
168275970Scy				backlog, fd);
169275970Scy	}
170275970Scy#endif
171275970Scy
172275970Scy	if (backlog > 0) {
173275970Scy		if (listen(fd, backlog) < 0)
174275970Scy			return NULL;
175275970Scy	} else if (backlog < 0) {
176275970Scy		if (listen(fd, 128) < 0)
177275970Scy			return NULL;
178275970Scy	}
179275970Scy
180275970Scy	lev = mm_calloc(1, sizeof(struct evconnlistener_event));
181275970Scy	if (!lev)
182275970Scy		return NULL;
183275970Scy
184275970Scy	lev->base.ops = &evconnlistener_event_ops;
185275970Scy	lev->base.cb = cb;
186275970Scy	lev->base.user_data = ptr;
187275970Scy	lev->base.flags = flags;
188275970Scy	lev->base.refcnt = 1;
189275970Scy
190275970Scy	lev->base.accept4_flags = 0;
191275970Scy	if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
192275970Scy		lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
193275970Scy	if (flags & LEV_OPT_CLOSE_ON_EXEC)
194275970Scy		lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
195275970Scy
196275970Scy	if (flags & LEV_OPT_THREADSAFE) {
197275970Scy		EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
198275970Scy	}
199275970Scy
200275970Scy	event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
201275970Scy	    listener_read_cb, lev);
202275970Scy
203275970Scy	if (!(flags & LEV_OPT_DISABLED))
204275970Scy	    evconnlistener_enable(&lev->base);
205275970Scy
206275970Scy	return &lev->base;
207275970Scy}
208275970Scy
209275970Scystruct evconnlistener *
210275970Scyevconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
211275970Scy    void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
212275970Scy    int socklen)
213275970Scy{
214275970Scy	struct evconnlistener *listener;
215275970Scy	evutil_socket_t fd;
216275970Scy	int on = 1;
217275970Scy	int family = sa ? sa->sa_family : AF_UNSPEC;
218275970Scy	int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
219275970Scy
220275970Scy	if (backlog == 0)
221275970Scy		return NULL;
222275970Scy
223275970Scy	if (flags & LEV_OPT_CLOSE_ON_EXEC)
224275970Scy		socktype |= EVUTIL_SOCK_CLOEXEC;
225275970Scy
226275970Scy	fd = evutil_socket_(family, socktype, 0);
227275970Scy	if (fd == -1)
228275970Scy		return NULL;
229275970Scy
230275970Scy	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
231275970Scy		goto err;
232275970Scy
233275970Scy	if (flags & LEV_OPT_REUSEABLE) {
234275970Scy		if (evutil_make_listen_socket_reuseable(fd) < 0)
235275970Scy			goto err;
236275970Scy	}
237275970Scy
238285612Sdelphij	if (flags & LEV_OPT_REUSEABLE_PORT) {
239285612Sdelphij		if (evutil_make_listen_socket_reuseable_port(fd) < 0)
240285612Sdelphij			goto err;
241285612Sdelphij	}
242285612Sdelphij
243275970Scy	if (flags & LEV_OPT_DEFERRED_ACCEPT) {
244275970Scy		if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
245275970Scy			goto err;
246275970Scy	}
247275970Scy
248275970Scy	if (sa) {
249275970Scy		if (bind(fd, sa, socklen)<0)
250275970Scy			goto err;
251275970Scy	}
252275970Scy
253275970Scy	listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
254275970Scy	if (!listener)
255275970Scy		goto err;
256275970Scy
257275970Scy	return listener;
258275970Scyerr:
259275970Scy	evutil_closesocket(fd);
260275970Scy	return NULL;
261275970Scy}
262275970Scy
263275970Scyvoid
264275970Scyevconnlistener_free(struct evconnlistener *lev)
265275970Scy{
266275970Scy	LOCK(lev);
267275970Scy	lev->cb = NULL;
268275970Scy	lev->errorcb = NULL;
269275970Scy	if (lev->ops->shutdown)
270275970Scy		lev->ops->shutdown(lev);
271275970Scy	listener_decref_and_unlock(lev);
272275970Scy}
273275970Scy
274275970Scystatic void
275275970Scyevent_listener_destroy(struct evconnlistener *lev)
276275970Scy{
277275970Scy	struct evconnlistener_event *lev_e =
278275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
279275970Scy
280275970Scy	event_del(&lev_e->listener);
281275970Scy	if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
282275970Scy		evutil_closesocket(event_get_fd(&lev_e->listener));
283275970Scy	event_debug_unassign(&lev_e->listener);
284275970Scy}
285275970Scy
286275970Scyint
287275970Scyevconnlistener_enable(struct evconnlistener *lev)
288275970Scy{
289275970Scy	int r;
290275970Scy	LOCK(lev);
291275970Scy	lev->enabled = 1;
292275970Scy	if (lev->cb)
293275970Scy		r = lev->ops->enable(lev);
294275970Scy	else
295275970Scy		r = 0;
296275970Scy	UNLOCK(lev);
297275970Scy	return r;
298275970Scy}
299275970Scy
300275970Scyint
301275970Scyevconnlistener_disable(struct evconnlistener *lev)
302275970Scy{
303275970Scy	int r;
304275970Scy	LOCK(lev);
305275970Scy	lev->enabled = 0;
306275970Scy	r = lev->ops->disable(lev);
307275970Scy	UNLOCK(lev);
308275970Scy	return r;
309275970Scy}
310275970Scy
311275970Scystatic int
312275970Scyevent_listener_enable(struct evconnlistener *lev)
313275970Scy{
314275970Scy	struct evconnlistener_event *lev_e =
315275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
316275970Scy	return event_add(&lev_e->listener, NULL);
317275970Scy}
318275970Scy
319275970Scystatic int
320275970Scyevent_listener_disable(struct evconnlistener *lev)
321275970Scy{
322275970Scy	struct evconnlistener_event *lev_e =
323275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
324275970Scy	return event_del(&lev_e->listener);
325275970Scy}
326275970Scy
327275970Scyevutil_socket_t
328275970Scyevconnlistener_get_fd(struct evconnlistener *lev)
329275970Scy{
330275970Scy	evutil_socket_t fd;
331275970Scy	LOCK(lev);
332275970Scy	fd = lev->ops->getfd(lev);
333275970Scy	UNLOCK(lev);
334275970Scy	return fd;
335275970Scy}
336275970Scy
337275970Scystatic evutil_socket_t
338275970Scyevent_listener_getfd(struct evconnlistener *lev)
339275970Scy{
340275970Scy	struct evconnlistener_event *lev_e =
341275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
342275970Scy	return event_get_fd(&lev_e->listener);
343275970Scy}
344275970Scy
345275970Scystruct event_base *
346275970Scyevconnlistener_get_base(struct evconnlistener *lev)
347275970Scy{
348275970Scy	struct event_base *base;
349275970Scy	LOCK(lev);
350275970Scy	base = lev->ops->getbase(lev);
351275970Scy	UNLOCK(lev);
352275970Scy	return base;
353275970Scy}
354275970Scy
355275970Scystatic struct event_base *
356275970Scyevent_listener_getbase(struct evconnlistener *lev)
357275970Scy{
358275970Scy	struct evconnlistener_event *lev_e =
359275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
360275970Scy	return event_get_base(&lev_e->listener);
361275970Scy}
362275970Scy
363275970Scyvoid
364275970Scyevconnlistener_set_cb(struct evconnlistener *lev,
365275970Scy    evconnlistener_cb cb, void *arg)
366275970Scy{
367275970Scy	int enable = 0;
368275970Scy	LOCK(lev);
369275970Scy	if (lev->enabled && !lev->cb)
370275970Scy		enable = 1;
371275970Scy	lev->cb = cb;
372275970Scy	lev->user_data = arg;
373275970Scy	if (enable)
374275970Scy		evconnlistener_enable(lev);
375275970Scy	UNLOCK(lev);
376275970Scy}
377275970Scy
378275970Scyvoid
379275970Scyevconnlistener_set_error_cb(struct evconnlistener *lev,
380275970Scy    evconnlistener_errorcb errorcb)
381275970Scy{
382275970Scy	LOCK(lev);
383275970Scy	lev->errorcb = errorcb;
384275970Scy	UNLOCK(lev);
385275970Scy}
386275970Scy
387275970Scystatic void
388275970Scylistener_read_cb(evutil_socket_t fd, short what, void *p)
389275970Scy{
390275970Scy	struct evconnlistener *lev = p;
391275970Scy	int err;
392275970Scy	evconnlistener_cb cb;
393275970Scy	evconnlistener_errorcb errorcb;
394275970Scy	void *user_data;
395275970Scy	LOCK(lev);
396275970Scy	while (1) {
397275970Scy		struct sockaddr_storage ss;
398275970Scy		ev_socklen_t socklen = sizeof(ss);
399275970Scy		evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
400275970Scy		if (new_fd < 0)
401275970Scy			break;
402275970Scy		if (socklen == 0) {
403275970Scy			/* This can happen with some older linux kernels in
404275970Scy			 * response to nmap. */
405275970Scy			evutil_closesocket(new_fd);
406275970Scy			continue;
407275970Scy		}
408275970Scy
409275970Scy		if (lev->cb == NULL) {
410275970Scy			evutil_closesocket(new_fd);
411275970Scy			UNLOCK(lev);
412275970Scy			return;
413275970Scy		}
414275970Scy		++lev->refcnt;
415275970Scy		cb = lev->cb;
416275970Scy		user_data = lev->user_data;
417275970Scy		UNLOCK(lev);
418275970Scy		cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
419275970Scy		    user_data);
420275970Scy		LOCK(lev);
421275970Scy		if (lev->refcnt == 1) {
422275970Scy			int freed = listener_decref_and_unlock(lev);
423275970Scy			EVUTIL_ASSERT(freed);
424285612Sdelphij
425285612Sdelphij			evutil_closesocket(new_fd);
426275970Scy			return;
427275970Scy		}
428275970Scy		--lev->refcnt;
429275970Scy	}
430275970Scy	err = evutil_socket_geterror(fd);
431275970Scy	if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
432275970Scy		UNLOCK(lev);
433275970Scy		return;
434275970Scy	}
435275970Scy	if (lev->errorcb != NULL) {
436275970Scy		++lev->refcnt;
437275970Scy		errorcb = lev->errorcb;
438275970Scy		user_data = lev->user_data;
439275970Scy		UNLOCK(lev);
440275970Scy		errorcb(lev, user_data);
441275970Scy		LOCK(lev);
442275970Scy		listener_decref_and_unlock(lev);
443275970Scy	} else {
444275970Scy		event_sock_warn(fd, "Error from accept() call");
445275970Scy	}
446275970Scy}
447275970Scy
448275970Scy#ifdef _WIN32
449275970Scystruct accepting_socket {
450275970Scy	CRITICAL_SECTION lock;
451275970Scy	struct event_overlapped overlapped;
452275970Scy	SOCKET s;
453275970Scy	int error;
454275970Scy	struct event_callback deferred;
455275970Scy	struct evconnlistener_iocp *lev;
456275970Scy	ev_uint8_t buflen;
457275970Scy	ev_uint8_t family;
458275970Scy	unsigned free_on_cb:1;
459275970Scy	char addrbuf[1];
460275970Scy};
461275970Scy
462275970Scystatic void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
463275970Scy    ev_ssize_t n, int ok);
464275970Scystatic void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
465275970Scy
466275970Scystatic void
467275970Scyiocp_listener_event_add(struct evconnlistener_iocp *lev)
468275970Scy{
469275970Scy	if (lev->event_added)
470275970Scy		return;
471275970Scy
472275970Scy	lev->event_added = 1;
473275970Scy	event_base_add_virtual_(lev->event_base);
474275970Scy}
475275970Scy
476275970Scystatic void
477275970Scyiocp_listener_event_del(struct evconnlistener_iocp *lev)
478275970Scy{
479275970Scy	if (!lev->event_added)
480275970Scy		return;
481275970Scy
482275970Scy	lev->event_added = 0;
483275970Scy	event_base_del_virtual_(lev->event_base);
484275970Scy}
485275970Scy
486275970Scystatic struct accepting_socket *
487275970Scynew_accepting_socket(struct evconnlistener_iocp *lev, int family)
488275970Scy{
489275970Scy	struct accepting_socket *res;
490275970Scy	int addrlen;
491275970Scy	int buflen;
492275970Scy
493275970Scy	if (family == AF_INET)
494275970Scy		addrlen = sizeof(struct sockaddr_in);
495275970Scy	else if (family == AF_INET6)
496275970Scy		addrlen = sizeof(struct sockaddr_in6);
497275970Scy	else
498275970Scy		return NULL;
499275970Scy	buflen = (addrlen+16)*2;
500275970Scy
501275970Scy	res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
502275970Scy	if (!res)
503275970Scy		return NULL;
504275970Scy
505275970Scy	event_overlapped_init_(&res->overlapped, accepted_socket_cb);
506275970Scy	res->s = INVALID_SOCKET;
507275970Scy	res->lev = lev;
508275970Scy	res->buflen = buflen;
509275970Scy	res->family = family;
510275970Scy
511275970Scy	event_deferred_cb_init_(&res->deferred,
512275970Scy	    event_base_get_npriorities(lev->event_base) / 2,
513275970Scy	    accepted_socket_invoke_user_cb, res);
514275970Scy
515275970Scy	InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
516275970Scy
517275970Scy	return res;
518275970Scy}
519275970Scy
520275970Scystatic void
521275970Scyfree_and_unlock_accepting_socket(struct accepting_socket *as)
522275970Scy{
523275970Scy	/* requires lock. */
524275970Scy	if (as->s != INVALID_SOCKET)
525275970Scy		closesocket(as->s);
526275970Scy
527275970Scy	LeaveCriticalSection(&as->lock);
528275970Scy	DeleteCriticalSection(&as->lock);
529275970Scy	mm_free(as);
530275970Scy}
531275970Scy
532275970Scystatic int
533275970Scystart_accepting(struct accepting_socket *as)
534275970Scy{
535275970Scy	/* requires lock */
536275970Scy	const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
537275970Scy	DWORD pending = 0;
538275970Scy	SOCKET s = socket(as->family, SOCK_STREAM, 0);
539275970Scy	int error = 0;
540275970Scy
541275970Scy	if (!as->lev->base.enabled)
542275970Scy		return 0;
543275970Scy
544275970Scy	if (s == INVALID_SOCKET) {
545275970Scy		error = WSAGetLastError();
546275970Scy		goto report_err;
547275970Scy	}
548275970Scy
549275970Scy	/* XXXX It turns out we need to do this again later.  Does this call
550275970Scy	 * have any effect? */
551275970Scy	setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
552275970Scy	    (char *)&as->lev->fd, sizeof(&as->lev->fd));
553275970Scy
554275970Scy	if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
555275970Scy		evutil_make_socket_nonblocking(s);
556275970Scy
557275970Scy	if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
558275970Scy		closesocket(s);
559275970Scy		return -1;
560275970Scy	}
561275970Scy
562275970Scy	as->s = s;
563275970Scy
564275970Scy	if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
565275970Scy		as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
566275970Scy	{
567275970Scy		/* Immediate success! */
568275970Scy		accepted_socket_cb(&as->overlapped, 1, 0, 1);
569275970Scy	} else {
570275970Scy		error = WSAGetLastError();
571275970Scy		if (error != ERROR_IO_PENDING) {
572275970Scy			goto report_err;
573275970Scy		}
574275970Scy	}
575275970Scy
576275970Scy	return 0;
577275970Scy
578275970Scyreport_err:
579275970Scy	as->error = error;
580275970Scy	event_deferred_cb_schedule_(
581275970Scy		as->lev->event_base,
582275970Scy		&as->deferred);
583275970Scy	return 0;
584275970Scy}
585275970Scy
586275970Scystatic void
587275970Scystop_accepting(struct accepting_socket *as)
588275970Scy{
589275970Scy	/* requires lock. */
590275970Scy	SOCKET s = as->s;
591275970Scy	as->s = INVALID_SOCKET;
592275970Scy	closesocket(s);
593275970Scy}
594275970Scy
595275970Scystatic void
596275970Scyaccepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
597275970Scy{
598275970Scy	struct accepting_socket *as = arg;
599275970Scy
600275970Scy	struct sockaddr *sa_local=NULL, *sa_remote=NULL;
601275970Scy	int socklen_local=0, socklen_remote=0;
602275970Scy	const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
603275970Scy	struct evconnlistener *lev = &as->lev->base;
604275970Scy	evutil_socket_t sock=-1;
605275970Scy	void *data;
606275970Scy	evconnlistener_cb cb=NULL;
607275970Scy	evconnlistener_errorcb errorcb=NULL;
608275970Scy	int error;
609275970Scy
610275970Scy	EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
611275970Scy
612275970Scy	LOCK(lev);
613275970Scy	EnterCriticalSection(&as->lock);
614275970Scy	if (as->free_on_cb) {
615275970Scy		free_and_unlock_accepting_socket(as);
616275970Scy		listener_decref_and_unlock(lev);
617275970Scy		return;
618275970Scy	}
619275970Scy
620275970Scy	++lev->refcnt;
621275970Scy
622275970Scy	error = as->error;
623275970Scy	if (error) {
624275970Scy		as->error = 0;
625275970Scy		errorcb = lev->errorcb;
626275970Scy	} else {
627275970Scy		ext->GetAcceptExSockaddrs(
628275970Scy			as->addrbuf, 0, as->buflen/2, as->buflen/2,
629275970Scy			&sa_local, &socklen_local, &sa_remote,
630275970Scy			&socklen_remote);
631275970Scy		sock = as->s;
632275970Scy		cb = lev->cb;
633275970Scy		as->s = INVALID_SOCKET;
634275970Scy
635275970Scy		/* We need to call this so getsockname, getpeername, and
636275970Scy		 * shutdown work correctly on the accepted socket. */
637275970Scy		/* XXXX handle error? */
638275970Scy		setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
639275970Scy		    (char *)&as->lev->fd, sizeof(&as->lev->fd));
640275970Scy	}
641275970Scy	data = lev->user_data;
642275970Scy
643275970Scy	LeaveCriticalSection(&as->lock);
644275970Scy	UNLOCK(lev);
645275970Scy
646275970Scy	if (errorcb) {
647275970Scy		WSASetLastError(error);
648275970Scy		errorcb(lev, data);
649275970Scy	} else if (cb) {
650275970Scy		cb(lev, sock, sa_remote, socklen_remote, data);
651275970Scy	}
652275970Scy
653275970Scy	LOCK(lev);
654275970Scy	if (listener_decref_and_unlock(lev))
655275970Scy		return;
656275970Scy
657275970Scy	EnterCriticalSection(&as->lock);
658275970Scy	start_accepting(as);
659275970Scy	LeaveCriticalSection(&as->lock);
660275970Scy}
661275970Scy
662275970Scystatic void
663275970Scyaccepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
664275970Scy{
665275970Scy	struct accepting_socket *as =
666275970Scy	    EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
667275970Scy
668275970Scy	LOCK(&as->lev->base);
669275970Scy	EnterCriticalSection(&as->lock);
670275970Scy	if (ok) {
671275970Scy		/* XXXX Don't do this if some EV_MT flag is set. */
672275970Scy		event_deferred_cb_schedule_(
673275970Scy			as->lev->event_base,
674275970Scy			&as->deferred);
675275970Scy		LeaveCriticalSection(&as->lock);
676275970Scy	} else if (as->free_on_cb) {
677275970Scy		struct evconnlistener *lev = &as->lev->base;
678275970Scy		free_and_unlock_accepting_socket(as);
679275970Scy		listener_decref_and_unlock(lev);
680275970Scy		return;
681275970Scy	} else if (as->s == INVALID_SOCKET) {
682275970Scy		/* This is okay; we were disabled by iocp_listener_disable. */
683275970Scy		LeaveCriticalSection(&as->lock);
684275970Scy	} else {
685275970Scy		/* Some error on accept that we couldn't actually handle. */
686275970Scy		BOOL ok;
687275970Scy		DWORD transfer = 0, flags=0;
688275970Scy		event_sock_warn(as->s, "Unexpected error on AcceptEx");
689275970Scy		ok = WSAGetOverlappedResult(as->s, &o->overlapped,
690275970Scy		    &transfer, FALSE, &flags);
691275970Scy		if (ok) {
692275970Scy			/* well, that was confusing! */
693275970Scy			as->error = 1;
694275970Scy		} else {
695275970Scy			as->error = WSAGetLastError();
696275970Scy		}
697275970Scy		event_deferred_cb_schedule_(
698275970Scy			as->lev->event_base,
699275970Scy			&as->deferred);
700275970Scy		LeaveCriticalSection(&as->lock);
701275970Scy	}
702275970Scy	UNLOCK(&as->lev->base);
703275970Scy}
704275970Scy
705275970Scystatic int
706275970Scyiocp_listener_enable(struct evconnlistener *lev)
707275970Scy{
708275970Scy	int i;
709275970Scy	struct evconnlistener_iocp *lev_iocp =
710275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
711275970Scy
712275970Scy	LOCK(lev);
713275970Scy	iocp_listener_event_add(lev_iocp);
714275970Scy	for (i = 0; i < lev_iocp->n_accepting; ++i) {
715275970Scy		struct accepting_socket *as = lev_iocp->accepting[i];
716275970Scy		if (!as)
717275970Scy			continue;
718275970Scy		EnterCriticalSection(&as->lock);
719275970Scy		if (!as->free_on_cb && as->s == INVALID_SOCKET)
720275970Scy			start_accepting(as);
721275970Scy		LeaveCriticalSection(&as->lock);
722275970Scy	}
723275970Scy	UNLOCK(lev);
724275970Scy	return 0;
725275970Scy}
726275970Scy
727275970Scystatic int
728275970Scyiocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
729275970Scy{
730275970Scy	int i;
731275970Scy	struct evconnlistener_iocp *lev_iocp =
732275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
733275970Scy
734275970Scy	LOCK(lev);
735275970Scy	iocp_listener_event_del(lev_iocp);
736275970Scy	for (i = 0; i < lev_iocp->n_accepting; ++i) {
737275970Scy		struct accepting_socket *as = lev_iocp->accepting[i];
738275970Scy		if (!as)
739275970Scy			continue;
740275970Scy		EnterCriticalSection(&as->lock);
741275970Scy		if (!as->free_on_cb && as->s != INVALID_SOCKET) {
742275970Scy			if (shutdown)
743275970Scy				as->free_on_cb = 1;
744275970Scy			stop_accepting(as);
745275970Scy		}
746275970Scy		LeaveCriticalSection(&as->lock);
747275970Scy	}
748275970Scy
749275970Scy	if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
750275970Scy		evutil_closesocket(lev_iocp->fd);
751275970Scy
752275970Scy	UNLOCK(lev);
753275970Scy	return 0;
754275970Scy}
755275970Scy
756275970Scystatic int
757275970Scyiocp_listener_disable(struct evconnlistener *lev)
758275970Scy{
759275970Scy	return iocp_listener_disable_impl(lev,0);
760275970Scy}
761275970Scy
762275970Scystatic void
763275970Scyiocp_listener_destroy(struct evconnlistener *lev)
764275970Scy{
765275970Scy	struct evconnlistener_iocp *lev_iocp =
766275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
767275970Scy
768275970Scy	if (! lev_iocp->shutting_down) {
769275970Scy		lev_iocp->shutting_down = 1;
770275970Scy		iocp_listener_disable_impl(lev,1);
771275970Scy	}
772275970Scy
773275970Scy}
774275970Scy
775275970Scystatic evutil_socket_t
776275970Scyiocp_listener_getfd(struct evconnlistener *lev)
777275970Scy{
778275970Scy	struct evconnlistener_iocp *lev_iocp =
779275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
780275970Scy	return lev_iocp->fd;
781275970Scy}
782275970Scystatic struct event_base *
783275970Scyiocp_listener_getbase(struct evconnlistener *lev)
784275970Scy{
785275970Scy	struct evconnlistener_iocp *lev_iocp =
786275970Scy	    EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
787275970Scy	return lev_iocp->event_base;
788275970Scy}
789275970Scy
790275970Scystatic const struct evconnlistener_ops evconnlistener_iocp_ops = {
791275970Scy	iocp_listener_enable,
792275970Scy	iocp_listener_disable,
793275970Scy	iocp_listener_destroy,
794275970Scy	iocp_listener_destroy, /* shutdown */
795275970Scy	iocp_listener_getfd,
796275970Scy	iocp_listener_getbase
797275970Scy};
798275970Scy
799275970Scy/* XXX define some way to override this. */
800275970Scy#define N_SOCKETS_PER_LISTENER 4
801275970Scy
802275970Scystruct evconnlistener *
803275970Scyevconnlistener_new_async(struct event_base *base,
804275970Scy    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
805275970Scy    evutil_socket_t fd)
806275970Scy{
807275970Scy	struct sockaddr_storage ss;
808275970Scy	int socklen = sizeof(ss);
809275970Scy	struct evconnlistener_iocp *lev;
810275970Scy	int i;
811275970Scy
812275970Scy	flags |= LEV_OPT_THREADSAFE;
813275970Scy
814275970Scy	if (!base || !event_base_get_iocp_(base))
815275970Scy		goto err;
816275970Scy
817275970Scy	/* XXXX duplicate code */
818275970Scy	if (backlog > 0) {
819275970Scy		if (listen(fd, backlog) < 0)
820275970Scy			goto err;
821275970Scy	} else if (backlog < 0) {
822275970Scy		if (listen(fd, 128) < 0)
823275970Scy			goto err;
824275970Scy	}
825275970Scy	if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
826275970Scy		event_sock_warn(fd, "getsockname");
827275970Scy		goto err;
828275970Scy	}
829275970Scy	lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
830275970Scy	if (!lev) {
831275970Scy		event_warn("calloc");
832275970Scy		goto err;
833275970Scy	}
834275970Scy	lev->base.ops = &evconnlistener_iocp_ops;
835275970Scy	lev->base.cb = cb;
836275970Scy	lev->base.user_data = ptr;
837275970Scy	lev->base.flags = flags;
838275970Scy	lev->base.refcnt = 1;
839275970Scy	lev->base.enabled = 1;
840275970Scy
841275970Scy	lev->port = event_base_get_iocp_(base);
842275970Scy	lev->fd = fd;
843275970Scy	lev->event_base = base;
844275970Scy
845275970Scy
846275970Scy	if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
847275970Scy		goto err_free_lev;
848275970Scy
849275970Scy	EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
850275970Scy
851275970Scy	lev->n_accepting = N_SOCKETS_PER_LISTENER;
852275970Scy	lev->accepting = mm_calloc(lev->n_accepting,
853275970Scy	    sizeof(struct accepting_socket *));
854275970Scy	if (!lev->accepting) {
855275970Scy		event_warn("calloc");
856275970Scy		goto err_delete_lock;
857275970Scy	}
858275970Scy	for (i = 0; i < lev->n_accepting; ++i) {
859275970Scy		lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
860275970Scy		if (!lev->accepting[i]) {
861275970Scy			event_warnx("Couldn't create accepting socket");
862275970Scy			goto err_free_accepting;
863275970Scy		}
864275970Scy		if (cb && start_accepting(lev->accepting[i]) < 0) {
865275970Scy			event_warnx("Couldn't start accepting on socket");
866275970Scy			EnterCriticalSection(&lev->accepting[i]->lock);
867275970Scy			free_and_unlock_accepting_socket(lev->accepting[i]);
868275970Scy			goto err_free_accepting;
869275970Scy		}
870275970Scy		++lev->base.refcnt;
871275970Scy	}
872275970Scy
873275970Scy	iocp_listener_event_add(lev);
874275970Scy
875275970Scy	return &lev->base;
876275970Scy
877275970Scyerr_free_accepting:
878275970Scy	mm_free(lev->accepting);
879275970Scy	/* XXXX free the other elements. */
880275970Scyerr_delete_lock:
881275970Scy	EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
882275970Scyerr_free_lev:
883275970Scy	mm_free(lev);
884275970Scyerr:
885275970Scy	/* Don't close the fd, it is caller's responsibility. */
886275970Scy	return NULL;
887275970Scy}
888275970Scy
889275970Scy#endif
890