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