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