1659d54d5SNick Mathewson /*
2e49e2891SNick Mathewson * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
3659d54d5SNick Mathewson *
4659d54d5SNick Mathewson * Redistribution and use in source and binary forms, with or without
5659d54d5SNick Mathewson * modification, are permitted provided that the following conditions
6659d54d5SNick Mathewson * are met:
7659d54d5SNick Mathewson * 1. Redistributions of source code must retain the above copyright
8659d54d5SNick Mathewson * notice, this list of conditions and the following disclaimer.
9659d54d5SNick Mathewson * 2. Redistributions in binary form must reproduce the above copyright
10659d54d5SNick Mathewson * notice, this list of conditions and the following disclaimer in the
11659d54d5SNick Mathewson * documentation and/or other materials provided with the distribution.
12659d54d5SNick Mathewson * 3. The name of the author may not be used to endorse or promote products
13659d54d5SNick Mathewson * derived from this software without specific prior written permission.
14659d54d5SNick Mathewson *
15659d54d5SNick Mathewson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16659d54d5SNick Mathewson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17659d54d5SNick Mathewson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18659d54d5SNick Mathewson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19659d54d5SNick Mathewson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20659d54d5SNick Mathewson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21659d54d5SNick Mathewson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22659d54d5SNick Mathewson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23659d54d5SNick Mathewson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24659d54d5SNick Mathewson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25659d54d5SNick Mathewson */
26659d54d5SNick Mathewson
27ec347b92SNick Mathewson #include "event2/event-config.h"
280915ca0aSKevin Bowling #include "evconfig-private.h"
290915ca0aSKevin Bowling
300915ca0aSKevin Bowling #include <sys/types.h>
31659d54d5SNick Mathewson
329f560bfaSNick Mathewson #ifdef _WIN32
33816115a1SPeter Rosin #ifndef _WIN32_WINNT
34816115a1SPeter Rosin /* Minimum required for InitializeCriticalSectionAndSpinCount */
35816115a1SPeter Rosin #define _WIN32_WINNT 0x0403
36816115a1SPeter Rosin #endif
37659d54d5SNick Mathewson #include <winsock2.h>
38*9559349cSyuangongji #include <winerror.h>
3920f5bdfdSNick Mathewson #include <ws2tcpip.h>
4020f5bdfdSNick Mathewson #include <mswsock.h>
41659d54d5SNick Mathewson #endif
42659d54d5SNick Mathewson #include <errno.h>
4368120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_SOCKET_H
44659d54d5SNick Mathewson #include <sys/socket.h>
45659d54d5SNick Mathewson #endif
4668120d9bSNick Mathewson #ifdef EVENT__HAVE_FCNTL_H
47659d54d5SNick Mathewson #include <fcntl.h>
48659d54d5SNick Mathewson #endif
4968120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
50659d54d5SNick Mathewson #include <unistd.h>
51659d54d5SNick Mathewson #endif
52659d54d5SNick Mathewson
53fbe64f21SEvan Jones #include "event2/listener.h"
54fbe64f21SEvan Jones #include "event2/util.h"
55fbe64f21SEvan Jones #include "event2/event.h"
56fbe64f21SEvan Jones #include "event2/event_struct.h"
57659d54d5SNick Mathewson #include "mm-internal.h"
58659d54d5SNick Mathewson #include "util-internal.h"
59659d54d5SNick Mathewson #include "log-internal.h"
60127d4f21SNick Mathewson #include "evthread-internal.h"
619f560bfaSNick Mathewson #ifdef _WIN32
6220f5bdfdSNick Mathewson #include "iocp-internal.h"
63e794d716SNick Mathewson #include "defer-internal.h"
647b40a000SChristopher Davis #include "event-internal.h"
6520f5bdfdSNick Mathewson #endif
6620f5bdfdSNick Mathewson
6720f5bdfdSNick Mathewson struct evconnlistener_ops {
6820f5bdfdSNick Mathewson int (*enable)(struct evconnlistener *);
6920f5bdfdSNick Mathewson int (*disable)(struct evconnlistener *);
7020f5bdfdSNick Mathewson void (*destroy)(struct evconnlistener *);
71127d4f21SNick Mathewson void (*shutdown)(struct evconnlistener *);
7220f5bdfdSNick Mathewson evutil_socket_t (*getfd)(struct evconnlistener *);
735d2c1650SNick Mathewson struct event_base *(*getbase)(struct evconnlistener *);
7420f5bdfdSNick Mathewson };
75659d54d5SNick Mathewson
76659d54d5SNick Mathewson struct evconnlistener {
7720f5bdfdSNick Mathewson const struct evconnlistener_ops *ops;
78127d4f21SNick Mathewson void *lock;
79659d54d5SNick Mathewson evconnlistener_cb cb;
80c4be8d82SSimon Perreault evconnlistener_errorcb errorcb;
81659d54d5SNick Mathewson void *user_data;
82659d54d5SNick Mathewson unsigned flags;
8346ee061cSNick Mathewson short refcnt;
847e9e2893SNick Mathewson int accept4_flags;
8546ee061cSNick Mathewson unsigned enabled : 1;
86659d54d5SNick Mathewson };
87659d54d5SNick Mathewson
8820f5bdfdSNick Mathewson struct evconnlistener_event {
8920f5bdfdSNick Mathewson struct evconnlistener base;
9020f5bdfdSNick Mathewson struct event listener;
9120f5bdfdSNick Mathewson };
9220f5bdfdSNick Mathewson
939f560bfaSNick Mathewson #ifdef _WIN32
9420f5bdfdSNick Mathewson struct evconnlistener_iocp {
9520f5bdfdSNick Mathewson struct evconnlistener base;
9620f5bdfdSNick Mathewson evutil_socket_t fd;
975d2c1650SNick Mathewson struct event_base *event_base;
9820f5bdfdSNick Mathewson struct event_iocp_port *port;
99127d4f21SNick Mathewson short n_accepting;
10012057035SNick Mathewson unsigned shutting_down : 1;
1017b40a000SChristopher Davis unsigned event_added : 1;
10220f5bdfdSNick Mathewson struct accepting_socket **accepting;
10320f5bdfdSNick Mathewson };
10420f5bdfdSNick Mathewson #endif
10520f5bdfdSNick Mathewson
106127d4f21SNick Mathewson #define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
107127d4f21SNick Mathewson #define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
108127d4f21SNick Mathewson
1095d2c1650SNick Mathewson struct evconnlistener *
1105d2c1650SNick Mathewson evconnlistener_new_async(struct event_base *base,
1115d2c1650SNick Mathewson evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
1125d2c1650SNick Mathewson evutil_socket_t fd); /* XXXX export this? */
1135d2c1650SNick Mathewson
11420f5bdfdSNick Mathewson static int event_listener_enable(struct evconnlistener *);
11520f5bdfdSNick Mathewson static int event_listener_disable(struct evconnlistener *);
11620f5bdfdSNick Mathewson static void event_listener_destroy(struct evconnlistener *);
11720f5bdfdSNick Mathewson static evutil_socket_t event_listener_getfd(struct evconnlistener *);
1185d2c1650SNick Mathewson static struct event_base *event_listener_getbase(struct evconnlistener *);
11920f5bdfdSNick Mathewson
120127d4f21SNick Mathewson #if 0
121127d4f21SNick Mathewson static void
122127d4f21SNick Mathewson listener_incref_and_lock(struct evconnlistener *listener)
123127d4f21SNick Mathewson {
124127d4f21SNick Mathewson LOCK(listener);
125127d4f21SNick Mathewson ++listener->refcnt;
126127d4f21SNick Mathewson }
127127d4f21SNick Mathewson #endif
128127d4f21SNick Mathewson
129127d4f21SNick Mathewson static int
listener_decref_and_unlock(struct evconnlistener * listener)130127d4f21SNick Mathewson listener_decref_and_unlock(struct evconnlistener *listener)
131127d4f21SNick Mathewson {
132127d4f21SNick Mathewson int refcnt = --listener->refcnt;
133127d4f21SNick Mathewson if (refcnt == 0) {
134127d4f21SNick Mathewson listener->ops->destroy(listener);
135127d4f21SNick Mathewson UNLOCK(listener);
136127d4f21SNick Mathewson EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
137127d4f21SNick Mathewson mm_free(listener);
138127d4f21SNick Mathewson return 1;
139127d4f21SNick Mathewson } else {
140127d4f21SNick Mathewson UNLOCK(listener);
141127d4f21SNick Mathewson return 0;
142127d4f21SNick Mathewson }
143127d4f21SNick Mathewson }
144127d4f21SNick Mathewson
14520f5bdfdSNick Mathewson static const struct evconnlistener_ops evconnlistener_event_ops = {
14620f5bdfdSNick Mathewson event_listener_enable,
14720f5bdfdSNick Mathewson event_listener_disable,
14820f5bdfdSNick Mathewson event_listener_destroy,
149127d4f21SNick Mathewson NULL, /* shutdown */
1505d2c1650SNick Mathewson event_listener_getfd,
1515d2c1650SNick Mathewson event_listener_getbase
15220f5bdfdSNick Mathewson };
15320f5bdfdSNick Mathewson
154659d54d5SNick Mathewson static void listener_read_cb(evutil_socket_t, short, void *);
155659d54d5SNick Mathewson
156659d54d5SNick Mathewson struct evconnlistener *
evconnlistener_new(struct event_base * base,evconnlistener_cb cb,void * ptr,unsigned flags,int backlog,evutil_socket_t fd)157659d54d5SNick Mathewson evconnlistener_new(struct event_base *base,
158659d54d5SNick Mathewson evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
159659d54d5SNick Mathewson evutil_socket_t fd)
160659d54d5SNick Mathewson {
16120f5bdfdSNick Mathewson struct evconnlistener_event *lev;
162510ab6bcSJardel Weyrich
1639f560bfaSNick Mathewson #ifdef _WIN32
1648ac3c4c2SNick Mathewson if (base && event_base_get_iocp_(base)) {
1655d2c1650SNick Mathewson const struct win32_extension_fns *ext =
1668ac3c4c2SNick Mathewson event_get_win32_extension_fns_();
1675d2c1650SNick Mathewson if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
1685d2c1650SNick Mathewson return evconnlistener_new_async(base, cb, ptr, flags,
1695d2c1650SNick Mathewson backlog, fd);
1705d2c1650SNick Mathewson }
1715d2c1650SNick Mathewson #endif
172510ab6bcSJardel Weyrich
173659d54d5SNick Mathewson if (backlog > 0) {
174659d54d5SNick Mathewson if (listen(fd, backlog) < 0)
175659d54d5SNick Mathewson return NULL;
176ed1bbc7aSNick Mathewson } else if (backlog < 0) {
177ed1bbc7aSNick Mathewson if (listen(fd, 128) < 0)
178ed1bbc7aSNick Mathewson return NULL;
179659d54d5SNick Mathewson }
180510ab6bcSJardel Weyrich
18120f5bdfdSNick Mathewson lev = mm_calloc(1, sizeof(struct evconnlistener_event));
182659d54d5SNick Mathewson if (!lev)
183659d54d5SNick Mathewson return NULL;
184510ab6bcSJardel Weyrich
18520f5bdfdSNick Mathewson lev->base.ops = &evconnlistener_event_ops;
18620f5bdfdSNick Mathewson lev->base.cb = cb;
18720f5bdfdSNick Mathewson lev->base.user_data = ptr;
18820f5bdfdSNick Mathewson lev->base.flags = flags;
189127d4f21SNick Mathewson lev->base.refcnt = 1;
190127d4f21SNick Mathewson
1917e9e2893SNick Mathewson lev->base.accept4_flags = 0;
1927e9e2893SNick Mathewson if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
1937e9e2893SNick Mathewson lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
1944970329aSNick Mathewson if (flags & LEV_OPT_CLOSE_ON_EXEC)
1954970329aSNick Mathewson lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
1967e9e2893SNick Mathewson
197127d4f21SNick Mathewson if (flags & LEV_OPT_THREADSAFE) {
198127d4f21SNick Mathewson EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
199127d4f21SNick Mathewson }
200510ab6bcSJardel Weyrich
201659d54d5SNick Mathewson event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
202659d54d5SNick Mathewson listener_read_cb, lev);
20346ee061cSNick Mathewson
2049593a33fSAlexander Drozdov if (!(flags & LEV_OPT_DISABLED))
20520f5bdfdSNick Mathewson evconnlistener_enable(&lev->base);
206510ab6bcSJardel Weyrich
20720f5bdfdSNick Mathewson return &lev->base;
208659d54d5SNick Mathewson }
209659d54d5SNick Mathewson
210659d54d5SNick Mathewson struct evconnlistener *
evconnlistener_new_bind(struct event_base * base,evconnlistener_cb cb,void * ptr,unsigned flags,int backlog,const struct sockaddr * sa,int socklen)21120f5bdfdSNick Mathewson evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
21220f5bdfdSNick Mathewson void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
21320f5bdfdSNick Mathewson int socklen)
214659d54d5SNick Mathewson {
215fec66f96SJardel Weyrich struct evconnlistener *listener;
216659d54d5SNick Mathewson evutil_socket_t fd;
217659d54d5SNick Mathewson int on = 1;
218659d54d5SNick Mathewson int family = sa ? sa->sa_family : AF_UNSPEC;
2197e9e2893SNick Mathewson int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
220659d54d5SNick Mathewson
2217e3ea82eSNick Mathewson if (backlog == 0)
2227e3ea82eSNick Mathewson return NULL;
223fec66f96SJardel Weyrich
2247e9e2893SNick Mathewson if (flags & LEV_OPT_CLOSE_ON_EXEC)
2257e9e2893SNick Mathewson socktype |= EVUTIL_SOCK_CLOEXEC;
2267e9e2893SNick Mathewson
2278ac3c4c2SNick Mathewson fd = evutil_socket_(family, socktype, 0);
228659d54d5SNick Mathewson if (fd == -1)
229659d54d5SNick Mathewson return NULL;
230fec66f96SJardel Weyrich
231737f113aSNick Mathewson if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
232737f113aSNick Mathewson goto err;
233737f113aSNick Mathewson
234659d54d5SNick Mathewson if (flags & LEV_OPT_REUSEABLE) {
235737f113aSNick Mathewson if (evutil_make_listen_socket_reuseable(fd) < 0)
236737f113aSNick Mathewson goto err;
237659d54d5SNick Mathewson }
238659d54d5SNick Mathewson
239b625361aSMaciej Soltysiak if (flags & LEV_OPT_REUSEABLE_PORT) {
240b625361aSMaciej Soltysiak if (evutil_make_listen_socket_reuseable_port(fd) < 0)
241b625361aSMaciej Soltysiak goto err;
242b625361aSMaciej Soltysiak }
243b625361aSMaciej Soltysiak
2445880e4a1SMark Ellzey if (flags & LEV_OPT_DEFERRED_ACCEPT) {
245737f113aSNick Mathewson if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
246737f113aSNick Mathewson goto err;
2475880e4a1SMark Ellzey }
2485880e4a1SMark Ellzey
249ba148796SMurat Demirten if (flags & LEV_OPT_BIND_IPV6ONLY) {
250ba148796SMurat Demirten if (evutil_make_listen_socket_ipv6only(fd) < 0)
251ba148796SMurat Demirten goto err;
252ba148796SMurat Demirten }
253ba148796SMurat Demirten
254659d54d5SNick Mathewson if (sa) {
255737f113aSNick Mathewson if (bind(fd, sa, socklen)<0)
256737f113aSNick Mathewson goto err;
257659d54d5SNick Mathewson }
258659d54d5SNick Mathewson
259fec66f96SJardel Weyrich listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
260737f113aSNick Mathewson if (!listener)
261737f113aSNick Mathewson goto err;
262fec66f96SJardel Weyrich
263fec66f96SJardel Weyrich return listener;
264737f113aSNick Mathewson err:
265737f113aSNick Mathewson evutil_closesocket(fd);
266737f113aSNick Mathewson return NULL;
267659d54d5SNick Mathewson }
268659d54d5SNick Mathewson
269659d54d5SNick Mathewson void
evconnlistener_free(struct evconnlistener * lev)270659d54d5SNick Mathewson evconnlistener_free(struct evconnlistener *lev)
271659d54d5SNick Mathewson {
272127d4f21SNick Mathewson LOCK(lev);
273127d4f21SNick Mathewson lev->cb = NULL;
274127d4f21SNick Mathewson lev->errorcb = NULL;
275127d4f21SNick Mathewson if (lev->ops->shutdown)
276127d4f21SNick Mathewson lev->ops->shutdown(lev);
277127d4f21SNick Mathewson listener_decref_and_unlock(lev);
278659d54d5SNick Mathewson }
279659d54d5SNick Mathewson
28020f5bdfdSNick Mathewson static void
event_listener_destroy(struct evconnlistener * lev)28120f5bdfdSNick Mathewson event_listener_destroy(struct evconnlistener *lev)
28220f5bdfdSNick Mathewson {
28320f5bdfdSNick Mathewson struct evconnlistener_event *lev_e =
28420f5bdfdSNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
28520f5bdfdSNick Mathewson
28620f5bdfdSNick Mathewson event_del(&lev_e->listener);
28720f5bdfdSNick Mathewson if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
288899c1dccSSebastian Sjöberg evutil_closesocket(event_get_fd(&lev_e->listener));
289a19b4a05SNick Mathewson event_debug_unassign(&lev_e->listener);
29020f5bdfdSNick Mathewson }
29120f5bdfdSNick Mathewson
292659d54d5SNick Mathewson int
evconnlistener_enable(struct evconnlistener * lev)293659d54d5SNick Mathewson evconnlistener_enable(struct evconnlistener *lev)
294659d54d5SNick Mathewson {
295127d4f21SNick Mathewson int r;
296127d4f21SNick Mathewson LOCK(lev);
29746ee061cSNick Mathewson lev->enabled = 1;
29846ee061cSNick Mathewson if (lev->cb)
299127d4f21SNick Mathewson r = lev->ops->enable(lev);
30046ee061cSNick Mathewson else
30146ee061cSNick Mathewson r = 0;
302127d4f21SNick Mathewson UNLOCK(lev);
303127d4f21SNick Mathewson return r;
304659d54d5SNick Mathewson }
305659d54d5SNick Mathewson
306659d54d5SNick Mathewson int
evconnlistener_disable(struct evconnlistener * lev)307659d54d5SNick Mathewson evconnlistener_disable(struct evconnlistener *lev)
308659d54d5SNick Mathewson {
309127d4f21SNick Mathewson int r;
310127d4f21SNick Mathewson LOCK(lev);
31146ee061cSNick Mathewson lev->enabled = 0;
312127d4f21SNick Mathewson r = lev->ops->disable(lev);
313127d4f21SNick Mathewson UNLOCK(lev);
314127d4f21SNick Mathewson return r;
31520f5bdfdSNick Mathewson }
31620f5bdfdSNick Mathewson
31720f5bdfdSNick Mathewson static int
event_listener_enable(struct evconnlistener * lev)31820f5bdfdSNick Mathewson event_listener_enable(struct evconnlistener *lev)
31920f5bdfdSNick Mathewson {
32020f5bdfdSNick Mathewson struct evconnlistener_event *lev_e =
32120f5bdfdSNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
32220f5bdfdSNick Mathewson return event_add(&lev_e->listener, NULL);
32320f5bdfdSNick Mathewson }
32420f5bdfdSNick Mathewson
32520f5bdfdSNick Mathewson static int
event_listener_disable(struct evconnlistener * lev)32620f5bdfdSNick Mathewson event_listener_disable(struct evconnlistener *lev)
32720f5bdfdSNick Mathewson {
32820f5bdfdSNick Mathewson struct evconnlistener_event *lev_e =
32920f5bdfdSNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
33020f5bdfdSNick Mathewson return event_del(&lev_e->listener);
331659d54d5SNick Mathewson }
332659d54d5SNick Mathewson
33375fe762eSNick Mathewson evutil_socket_t
evconnlistener_get_fd(struct evconnlistener * lev)33475fe762eSNick Mathewson evconnlistener_get_fd(struct evconnlistener *lev)
33575fe762eSNick Mathewson {
336127d4f21SNick Mathewson evutil_socket_t fd;
337127d4f21SNick Mathewson LOCK(lev);
338127d4f21SNick Mathewson fd = lev->ops->getfd(lev);
339127d4f21SNick Mathewson UNLOCK(lev);
340127d4f21SNick Mathewson return fd;
34120f5bdfdSNick Mathewson }
34220f5bdfdSNick Mathewson
34320f5bdfdSNick Mathewson static evutil_socket_t
event_listener_getfd(struct evconnlistener * lev)34420f5bdfdSNick Mathewson event_listener_getfd(struct evconnlistener *lev)
34520f5bdfdSNick Mathewson {
34620f5bdfdSNick Mathewson struct evconnlistener_event *lev_e =
34720f5bdfdSNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
34820f5bdfdSNick Mathewson return event_get_fd(&lev_e->listener);
34975fe762eSNick Mathewson }
35075fe762eSNick Mathewson
3515d2c1650SNick Mathewson struct event_base *
evconnlistener_get_base(struct evconnlistener * lev)3525d2c1650SNick Mathewson evconnlistener_get_base(struct evconnlistener *lev)
3535d2c1650SNick Mathewson {
354127d4f21SNick Mathewson struct event_base *base;
355127d4f21SNick Mathewson LOCK(lev);
356127d4f21SNick Mathewson base = lev->ops->getbase(lev);
357127d4f21SNick Mathewson UNLOCK(lev);
358127d4f21SNick Mathewson return base;
3595d2c1650SNick Mathewson }
3605d2c1650SNick Mathewson
3615d2c1650SNick Mathewson static struct event_base *
event_listener_getbase(struct evconnlistener * lev)3625d2c1650SNick Mathewson event_listener_getbase(struct evconnlistener *lev)
3635d2c1650SNick Mathewson {
3645d2c1650SNick Mathewson struct evconnlistener_event *lev_e =
3655d2c1650SNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
3665d2c1650SNick Mathewson return event_get_base(&lev_e->listener);
3675d2c1650SNick Mathewson }
3685d2c1650SNick Mathewson
36946ee061cSNick Mathewson void
evconnlistener_set_cb(struct evconnlistener * lev,evconnlistener_cb cb,void * arg)37046ee061cSNick Mathewson evconnlistener_set_cb(struct evconnlistener *lev,
37146ee061cSNick Mathewson evconnlistener_cb cb, void *arg)
37246ee061cSNick Mathewson {
37346ee061cSNick Mathewson int enable = 0;
37446ee061cSNick Mathewson LOCK(lev);
37546ee061cSNick Mathewson if (lev->enabled && !lev->cb)
37646ee061cSNick Mathewson enable = 1;
37746ee061cSNick Mathewson lev->cb = cb;
37846ee061cSNick Mathewson lev->user_data = arg;
37946ee061cSNick Mathewson if (enable)
38046ee061cSNick Mathewson evconnlistener_enable(lev);
38146ee061cSNick Mathewson UNLOCK(lev);
38246ee061cSNick Mathewson }
38346ee061cSNick Mathewson
38446ee061cSNick Mathewson void
evconnlistener_set_error_cb(struct evconnlistener * lev,evconnlistener_errorcb errorcb)38546ee061cSNick Mathewson evconnlistener_set_error_cb(struct evconnlistener *lev,
386c4be8d82SSimon Perreault evconnlistener_errorcb errorcb)
387c4be8d82SSimon Perreault {
388127d4f21SNick Mathewson LOCK(lev);
389c4be8d82SSimon Perreault lev->errorcb = errorcb;
390127d4f21SNick Mathewson UNLOCK(lev);
391c4be8d82SSimon Perreault }
392c4be8d82SSimon Perreault
393659d54d5SNick Mathewson static void
listener_read_cb(evutil_socket_t fd,short what,void * p)394659d54d5SNick Mathewson listener_read_cb(evutil_socket_t fd, short what, void *p)
395659d54d5SNick Mathewson {
396659d54d5SNick Mathewson struct evconnlistener *lev = p;
397659d54d5SNick Mathewson int err;
398127d4f21SNick Mathewson evconnlistener_cb cb;
399127d4f21SNick Mathewson evconnlistener_errorcb errorcb;
400127d4f21SNick Mathewson void *user_data;
401127d4f21SNick Mathewson LOCK(lev);
402659d54d5SNick Mathewson while (1) {
403659d54d5SNick Mathewson struct sockaddr_storage ss;
40492385a9fSNick Mathewson ev_socklen_t socklen = sizeof(ss);
4058ac3c4c2SNick Mathewson evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
406659d54d5SNick Mathewson if (new_fd < 0)
407659d54d5SNick Mathewson break;
408ecfc720aSNick Mathewson if (socklen == 0) {
409ecfc720aSNick Mathewson /* This can happen with some older linux kernels in
410ecfc720aSNick Mathewson * response to nmap. */
411ecfc720aSNick Mathewson evutil_closesocket(new_fd);
412ecfc720aSNick Mathewson continue;
413ecfc720aSNick Mathewson }
414659d54d5SNick Mathewson
415127d4f21SNick Mathewson if (lev->cb == NULL) {
41669db2610SNick Mathewson evutil_closesocket(new_fd);
417127d4f21SNick Mathewson UNLOCK(lev);
418127d4f21SNick Mathewson return;
419127d4f21SNick Mathewson }
420127d4f21SNick Mathewson ++lev->refcnt;
421127d4f21SNick Mathewson cb = lev->cb;
422127d4f21SNick Mathewson user_data = lev->user_data;
423127d4f21SNick Mathewson UNLOCK(lev);
424127d4f21SNick Mathewson cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
425127d4f21SNick Mathewson user_data);
426127d4f21SNick Mathewson LOCK(lev);
427127d4f21SNick Mathewson if (lev->refcnt == 1) {
428127d4f21SNick Mathewson int freed = listener_decref_and_unlock(lev);
429127d4f21SNick Mathewson EVUTIL_ASSERT(freed);
430127d4f21SNick Mathewson return;
431127d4f21SNick Mathewson }
432127d4f21SNick Mathewson --lev->refcnt;
433df2ed13fSAzat Khuzhin if (!lev->enabled) {
434df2ed13fSAzat Khuzhin /* the callback could have disabled the listener */
435df2ed13fSAzat Khuzhin UNLOCK(lev);
436df2ed13fSAzat Khuzhin return;
437df2ed13fSAzat Khuzhin }
438659d54d5SNick Mathewson }
439659d54d5SNick Mathewson err = evutil_socket_geterror(fd);
440127d4f21SNick Mathewson if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
441127d4f21SNick Mathewson UNLOCK(lev);
442659d54d5SNick Mathewson return;
443127d4f21SNick Mathewson }
444127d4f21SNick Mathewson if (lev->errorcb != NULL) {
445127d4f21SNick Mathewson ++lev->refcnt;
446127d4f21SNick Mathewson errorcb = lev->errorcb;
447127d4f21SNick Mathewson user_data = lev->user_data;
448127d4f21SNick Mathewson UNLOCK(lev);
449127d4f21SNick Mathewson errorcb(lev, user_data);
450127d4f21SNick Mathewson LOCK(lev);
451127d4f21SNick Mathewson listener_decref_and_unlock(lev);
452127d4f21SNick Mathewson } else {
453659d54d5SNick Mathewson event_sock_warn(fd, "Error from accept() call");
4542a71b332SAzat Khuzhin UNLOCK(lev);
455659d54d5SNick Mathewson }
456127d4f21SNick Mathewson }
45720f5bdfdSNick Mathewson
4589f560bfaSNick Mathewson #ifdef _WIN32
45920f5bdfdSNick Mathewson struct accepting_socket {
4605d2c1650SNick Mathewson CRITICAL_SECTION lock;
46120f5bdfdSNick Mathewson struct event_overlapped overlapped;
46220f5bdfdSNick Mathewson SOCKET s;
463127d4f21SNick Mathewson int error;
464a4079aa8SNick Mathewson struct event_callback deferred;
46520f5bdfdSNick Mathewson struct evconnlistener_iocp *lev;
4665d2c1650SNick Mathewson ev_uint8_t buflen;
4675d2c1650SNick Mathewson ev_uint8_t family;
4685d2c1650SNick Mathewson unsigned free_on_cb:1;
4695d2c1650SNick Mathewson char addrbuf[1];
47020f5bdfdSNick Mathewson };
47120f5bdfdSNick Mathewson
472cef61a2fSNick Mathewson static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
473a84c87d7SNick Mathewson ev_ssize_t n, int ok);
474a4079aa8SNick Mathewson static void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
47520f5bdfdSNick Mathewson
4767b40a000SChristopher Davis static void
iocp_listener_event_add(struct evconnlistener_iocp * lev)4777b40a000SChristopher Davis iocp_listener_event_add(struct evconnlistener_iocp *lev)
4787b40a000SChristopher Davis {
4797b40a000SChristopher Davis if (lev->event_added)
4807b40a000SChristopher Davis return;
4817b40a000SChristopher Davis
4827b40a000SChristopher Davis lev->event_added = 1;
4838ac3c4c2SNick Mathewson event_base_add_virtual_(lev->event_base);
4847b40a000SChristopher Davis }
4857b40a000SChristopher Davis
4867b40a000SChristopher Davis static void
iocp_listener_event_del(struct evconnlistener_iocp * lev)4877b40a000SChristopher Davis iocp_listener_event_del(struct evconnlistener_iocp *lev)
4887b40a000SChristopher Davis {
4897b40a000SChristopher Davis if (!lev->event_added)
4907b40a000SChristopher Davis return;
4917b40a000SChristopher Davis
4927b40a000SChristopher Davis lev->event_added = 0;
4938ac3c4c2SNick Mathewson event_base_del_virtual_(lev->event_base);
4947b40a000SChristopher Davis }
4957b40a000SChristopher Davis
49620f5bdfdSNick Mathewson static struct accepting_socket *
new_accepting_socket(struct evconnlistener_iocp * lev,int family)49720f5bdfdSNick Mathewson new_accepting_socket(struct evconnlistener_iocp *lev, int family)
49820f5bdfdSNick Mathewson {
49920f5bdfdSNick Mathewson struct accepting_socket *res;
50020f5bdfdSNick Mathewson int addrlen;
50120f5bdfdSNick Mathewson int buflen;
502510ab6bcSJardel Weyrich
50320f5bdfdSNick Mathewson if (family == AF_INET)
50420f5bdfdSNick Mathewson addrlen = sizeof(struct sockaddr_in);
50520f5bdfdSNick Mathewson else if (family == AF_INET6)
50620f5bdfdSNick Mathewson addrlen = sizeof(struct sockaddr_in6);
50720f5bdfdSNick Mathewson else
50820f5bdfdSNick Mathewson return NULL;
50920f5bdfdSNick Mathewson buflen = (addrlen+16)*2;
51020f5bdfdSNick Mathewson
51120f5bdfdSNick Mathewson res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
51220f5bdfdSNick Mathewson if (!res)
51320f5bdfdSNick Mathewson return NULL;
51420f5bdfdSNick Mathewson
5158ac3c4c2SNick Mathewson event_overlapped_init_(&res->overlapped, accepted_socket_cb);
516e66078a0SAzat Khuzhin res->s = EVUTIL_INVALID_SOCKET;
51720f5bdfdSNick Mathewson res->lev = lev;
51820f5bdfdSNick Mathewson res->buflen = buflen;
5195d2c1650SNick Mathewson res->family = family;
5205d2c1650SNick Mathewson
5218ac3c4c2SNick Mathewson event_deferred_cb_init_(&res->deferred,
522cdb47db9SNick Mathewson event_base_get_npriorities(lev->event_base) / 2,
5230aa6f513SNick Mathewson accepted_socket_invoke_user_cb, res);
5240aa6f513SNick Mathewson
525cb52838fSNick Mathewson InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
5265d2c1650SNick Mathewson
52720f5bdfdSNick Mathewson return res;
52820f5bdfdSNick Mathewson }
52920f5bdfdSNick Mathewson
5305d2c1650SNick Mathewson static void
free_and_unlock_accepting_socket(struct accepting_socket * as)5315d2c1650SNick Mathewson free_and_unlock_accepting_socket(struct accepting_socket *as)
5325d2c1650SNick Mathewson {
5335d2c1650SNick Mathewson /* requires lock. */
534e66078a0SAzat Khuzhin if (as->s != EVUTIL_INVALID_SOCKET)
5355d2c1650SNick Mathewson closesocket(as->s);
5365d2c1650SNick Mathewson
5375d2c1650SNick Mathewson LeaveCriticalSection(&as->lock);
5385d2c1650SNick Mathewson DeleteCriticalSection(&as->lock);
5395d2c1650SNick Mathewson mm_free(as);
5405d2c1650SNick Mathewson }
5415d2c1650SNick Mathewson
54220f5bdfdSNick Mathewson static int
start_accepting(struct accepting_socket * as)54320f5bdfdSNick Mathewson start_accepting(struct accepting_socket *as)
54420f5bdfdSNick Mathewson {
545e794d716SNick Mathewson /* requires lock */
5468ac3c4c2SNick Mathewson const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
54720f5bdfdSNick Mathewson DWORD pending = 0;
5484367a33aSJardel Weyrich SOCKET s = socket(as->family, SOCK_STREAM, 0);
549127d4f21SNick Mathewson int error = 0;
55062b429afSChristopher Davis
55146ee061cSNick Mathewson if (!as->lev->base.enabled)
55262b429afSChristopher Davis return 0;
55362b429afSChristopher Davis
554e66078a0SAzat Khuzhin if (s == EVUTIL_INVALID_SOCKET) {
555127d4f21SNick Mathewson error = WSAGetLastError();
556127d4f21SNick Mathewson goto report_err;
557127d4f21SNick Mathewson }
55820f5bdfdSNick Mathewson
55952aa419bSNick Mathewson /* XXXX It turns out we need to do this again later. Does this call
56052aa419bSNick Mathewson * have any effect? */
5614367a33aSJardel Weyrich setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
5624367a33aSJardel Weyrich (char *)&as->lev->fd, sizeof(&as->lev->fd));
56320f5bdfdSNick Mathewson
56420f5bdfdSNick Mathewson if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
56520f5bdfdSNick Mathewson evutil_make_socket_nonblocking(s);
56620f5bdfdSNick Mathewson
5678ac3c4c2SNick Mathewson if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
5684367a33aSJardel Weyrich closesocket(s);
5694367a33aSJardel Weyrich return -1;
5704367a33aSJardel Weyrich }
57120f5bdfdSNick Mathewson
57220f5bdfdSNick Mathewson as->s = s;
57320f5bdfdSNick Mathewson
57420f5bdfdSNick Mathewson if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
5754367a33aSJardel Weyrich as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
5764367a33aSJardel Weyrich {
57720f5bdfdSNick Mathewson /* Immediate success! */
578a84c87d7SNick Mathewson accepted_socket_cb(&as->overlapped, 1, 0, 1);
57920f5bdfdSNick Mathewson } else {
580127d4f21SNick Mathewson error = WSAGetLastError();
581127d4f21SNick Mathewson if (error != ERROR_IO_PENDING) {
582127d4f21SNick Mathewson goto report_err;
5834367a33aSJardel Weyrich }
58420f5bdfdSNick Mathewson }
5855d2c1650SNick Mathewson
5864367a33aSJardel Weyrich return 0;
587127d4f21SNick Mathewson
588127d4f21SNick Mathewson report_err:
589127d4f21SNick Mathewson as->error = error;
5908ac3c4c2SNick Mathewson event_deferred_cb_schedule_(
591a4079aa8SNick Mathewson as->lev->event_base,
592127d4f21SNick Mathewson &as->deferred);
593127d4f21SNick Mathewson return 0;
5945d2c1650SNick Mathewson }
5955d2c1650SNick Mathewson
5965d2c1650SNick Mathewson static void
stop_accepting(struct accepting_socket * as)5975d2c1650SNick Mathewson stop_accepting(struct accepting_socket *as)
5985d2c1650SNick Mathewson {
599e794d716SNick Mathewson /* requires lock. */
600e794d716SNick Mathewson SOCKET s = as->s;
601e66078a0SAzat Khuzhin as->s = EVUTIL_INVALID_SOCKET;
602e794d716SNick Mathewson closesocket(s);
60320f5bdfdSNick Mathewson }
604e794d716SNick Mathewson
605e794d716SNick Mathewson static void
accepted_socket_invoke_user_cb(struct event_callback * dcb,void * arg)606a4079aa8SNick Mathewson accepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
607e794d716SNick Mathewson {
6080aa6f513SNick Mathewson struct accepting_socket *as = arg;
6090aa6f513SNick Mathewson
6100aa6f513SNick Mathewson struct sockaddr *sa_local=NULL, *sa_remote=NULL;
6110aa6f513SNick Mathewson int socklen_local=0, socklen_remote=0;
6128ac3c4c2SNick Mathewson const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
613127d4f21SNick Mathewson struct evconnlistener *lev = &as->lev->base;
614127d4f21SNick Mathewson evutil_socket_t sock=-1;
615127d4f21SNick Mathewson void *data;
616127d4f21SNick Mathewson evconnlistener_cb cb=NULL;
617127d4f21SNick Mathewson evconnlistener_errorcb errorcb=NULL;
618127d4f21SNick Mathewson int error;
6190aa6f513SNick Mathewson
6200aa6f513SNick Mathewson EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
621e794d716SNick Mathewson
622127d4f21SNick Mathewson LOCK(lev);
623e794d716SNick Mathewson EnterCriticalSection(&as->lock);
6240aa6f513SNick Mathewson if (as->free_on_cb) {
6250aa6f513SNick Mathewson free_and_unlock_accepting_socket(as);
626127d4f21SNick Mathewson listener_decref_and_unlock(lev);
6270aa6f513SNick Mathewson return;
6280aa6f513SNick Mathewson }
6290aa6f513SNick Mathewson
630127d4f21SNick Mathewson ++lev->refcnt;
631127d4f21SNick Mathewson
632127d4f21SNick Mathewson error = as->error;
633127d4f21SNick Mathewson if (error) {
634127d4f21SNick Mathewson as->error = 0;
635127d4f21SNick Mathewson errorcb = lev->errorcb;
636127d4f21SNick Mathewson } else {
637510ab6bcSJardel Weyrich ext->GetAcceptExSockaddrs(
638510ab6bcSJardel Weyrich as->addrbuf, 0, as->buflen/2, as->buflen/2,
639127d4f21SNick Mathewson &sa_local, &socklen_local, &sa_remote,
640127d4f21SNick Mathewson &socklen_remote);
641127d4f21SNick Mathewson sock = as->s;
642127d4f21SNick Mathewson cb = lev->cb;
643e66078a0SAzat Khuzhin as->s = EVUTIL_INVALID_SOCKET;
64452aa419bSNick Mathewson
64552aa419bSNick Mathewson /* We need to call this so getsockname, getpeername, and
64652aa419bSNick Mathewson * shutdown work correctly on the accepted socket. */
64752aa419bSNick Mathewson /* XXXX handle error? */
6482599b2d5SKelly Brock setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
64952aa419bSNick Mathewson (char *)&as->lev->fd, sizeof(&as->lev->fd));
650127d4f21SNick Mathewson }
651127d4f21SNick Mathewson data = lev->user_data;
652e794d716SNick Mathewson
653127d4f21SNick Mathewson LeaveCriticalSection(&as->lock);
654127d4f21SNick Mathewson UNLOCK(lev);
655127d4f21SNick Mathewson
656127d4f21SNick Mathewson if (errorcb) {
657127d4f21SNick Mathewson WSASetLastError(error);
658127d4f21SNick Mathewson errorcb(lev, data);
65946ee061cSNick Mathewson } else if (cb) {
660127d4f21SNick Mathewson cb(lev, sock, sa_remote, socklen_remote, data);
661127d4f21SNick Mathewson }
662127d4f21SNick Mathewson
663127d4f21SNick Mathewson LOCK(lev);
664127d4f21SNick Mathewson if (listener_decref_and_unlock(lev))
665127d4f21SNick Mathewson return;
666127d4f21SNick Mathewson
667127d4f21SNick Mathewson EnterCriticalSection(&as->lock);
668127d4f21SNick Mathewson start_accepting(as);
669e794d716SNick Mathewson LeaveCriticalSection(&as->lock);
670e794d716SNick Mathewson }
67120f5bdfdSNick Mathewson
67220f5bdfdSNick Mathewson static void
accepted_socket_cb(struct event_overlapped * o,ev_uintptr_t key,ev_ssize_t n,int ok)673cef61a2fSNick Mathewson accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
67420f5bdfdSNick Mathewson {
67520f5bdfdSNick Mathewson struct accepting_socket *as =
67620f5bdfdSNick Mathewson EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
67720f5bdfdSNick Mathewson
678127d4f21SNick Mathewson LOCK(&as->lev->base);
679e794d716SNick Mathewson EnterCriticalSection(&as->lock);
680e794d716SNick Mathewson if (ok) {
681e794d716SNick Mathewson /* XXXX Don't do this if some EV_MT flag is set. */
6828ac3c4c2SNick Mathewson event_deferred_cb_schedule_(
683a4079aa8SNick Mathewson as->lev->event_base,
684e794d716SNick Mathewson &as->deferred);
685e794d716SNick Mathewson LeaveCriticalSection(&as->lock);
6860aa6f513SNick Mathewson } else if (as->free_on_cb) {
687127d4f21SNick Mathewson struct evconnlistener *lev = &as->lev->base;
688e794d716SNick Mathewson free_and_unlock_accepting_socket(as);
689127d4f21SNick Mathewson listener_decref_and_unlock(lev);
690127d4f21SNick Mathewson return;
691e66078a0SAzat Khuzhin } else if (as->s == EVUTIL_INVALID_SOCKET) {
692e794d716SNick Mathewson /* This is okay; we were disabled by iocp_listener_disable. */
693e794d716SNick Mathewson LeaveCriticalSection(&as->lock);
694e794d716SNick Mathewson } else {
695e794d716SNick Mathewson /* Some error on accept that we couldn't actually handle. */
696127d4f21SNick Mathewson BOOL ok;
697127d4f21SNick Mathewson DWORD transfer = 0, flags=0;
6980aa6f513SNick Mathewson event_sock_warn(as->s, "Unexpected error on AcceptEx");
699127d4f21SNick Mathewson ok = WSAGetOverlappedResult(as->s, &o->overlapped,
700127d4f21SNick Mathewson &transfer, FALSE, &flags);
701127d4f21SNick Mathewson if (ok) {
702127d4f21SNick Mathewson /* well, that was confusing! */
703127d4f21SNick Mathewson as->error = 1;
704127d4f21SNick Mathewson } else {
705127d4f21SNick Mathewson as->error = WSAGetLastError();
70620f5bdfdSNick Mathewson }
7078ac3c4c2SNick Mathewson event_deferred_cb_schedule_(
708a4079aa8SNick Mathewson as->lev->event_base,
709127d4f21SNick Mathewson &as->deferred);
710127d4f21SNick Mathewson LeaveCriticalSection(&as->lock);
711127d4f21SNick Mathewson }
712127d4f21SNick Mathewson UNLOCK(&as->lev->base);
713e794d716SNick Mathewson }
71420f5bdfdSNick Mathewson
71520f5bdfdSNick Mathewson static int
iocp_listener_enable(struct evconnlistener * lev)71620f5bdfdSNick Mathewson iocp_listener_enable(struct evconnlistener *lev)
71720f5bdfdSNick Mathewson {
718e794d716SNick Mathewson int i;
719e794d716SNick Mathewson struct evconnlistener_iocp *lev_iocp =
720e794d716SNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
721e794d716SNick Mathewson
722127d4f21SNick Mathewson LOCK(lev);
7237b40a000SChristopher Davis iocp_listener_event_add(lev_iocp);
7240aa6f513SNick Mathewson for (i = 0; i < lev_iocp->n_accepting; ++i) {
725e794d716SNick Mathewson struct accepting_socket *as = lev_iocp->accepting[i];
726e794d716SNick Mathewson if (!as)
727e794d716SNick Mathewson continue;
728e794d716SNick Mathewson EnterCriticalSection(&as->lock);
729e66078a0SAzat Khuzhin if (!as->free_on_cb && as->s == EVUTIL_INVALID_SOCKET)
730127d4f21SNick Mathewson start_accepting(as);
731e794d716SNick Mathewson LeaveCriticalSection(&as->lock);
732e794d716SNick Mathewson }
733127d4f21SNick Mathewson UNLOCK(lev);
73420f5bdfdSNick Mathewson return 0;
73520f5bdfdSNick Mathewson }
736e794d716SNick Mathewson
73720f5bdfdSNick Mathewson static int
iocp_listener_disable_impl(struct evconnlistener * lev,int shutdown)738e794d716SNick Mathewson iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
73920f5bdfdSNick Mathewson {
740e794d716SNick Mathewson int i;
741e794d716SNick Mathewson struct evconnlistener_iocp *lev_iocp =
742e794d716SNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
743e794d716SNick Mathewson
744127d4f21SNick Mathewson LOCK(lev);
7457b40a000SChristopher Davis iocp_listener_event_del(lev_iocp);
7460aa6f513SNick Mathewson for (i = 0; i < lev_iocp->n_accepting; ++i) {
747e794d716SNick Mathewson struct accepting_socket *as = lev_iocp->accepting[i];
748e794d716SNick Mathewson if (!as)
749e794d716SNick Mathewson continue;
750e794d716SNick Mathewson EnterCriticalSection(&as->lock);
751e66078a0SAzat Khuzhin if (!as->free_on_cb && as->s != EVUTIL_INVALID_SOCKET) {
752e794d716SNick Mathewson if (shutdown)
753e794d716SNick Mathewson as->free_on_cb = 1;
754e794d716SNick Mathewson stop_accepting(as);
755e794d716SNick Mathewson }
756e794d716SNick Mathewson LeaveCriticalSection(&as->lock);
757e794d716SNick Mathewson }
758cb853ea3SJuan Pablo Fernandez
759cb853ea3SJuan Pablo Fernandez if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
760cb853ea3SJuan Pablo Fernandez evutil_closesocket(lev_iocp->fd);
761cb853ea3SJuan Pablo Fernandez
762127d4f21SNick Mathewson UNLOCK(lev);
76320f5bdfdSNick Mathewson return 0;
76420f5bdfdSNick Mathewson }
765e794d716SNick Mathewson
766e794d716SNick Mathewson static int
iocp_listener_disable(struct evconnlistener * lev)7670aa6f513SNick Mathewson iocp_listener_disable(struct evconnlistener *lev)
768e794d716SNick Mathewson {
769e794d716SNick Mathewson return iocp_listener_disable_impl(lev,0);
770e794d716SNick Mathewson }
771127d4f21SNick Mathewson
77220f5bdfdSNick Mathewson static void
iocp_listener_destroy(struct evconnlistener * lev)77320f5bdfdSNick Mathewson iocp_listener_destroy(struct evconnlistener *lev)
77420f5bdfdSNick Mathewson {
775127d4f21SNick Mathewson struct evconnlistener_iocp *lev_iocp =
776127d4f21SNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
777127d4f21SNick Mathewson
778127d4f21SNick Mathewson if (! lev_iocp->shutting_down) {
779127d4f21SNick Mathewson lev_iocp->shutting_down = 1;
780e794d716SNick Mathewson iocp_listener_disable_impl(lev,1);
78120f5bdfdSNick Mathewson }
782e794d716SNick Mathewson
783127d4f21SNick Mathewson }
784127d4f21SNick Mathewson
78520f5bdfdSNick Mathewson static evutil_socket_t
iocp_listener_getfd(struct evconnlistener * lev)78620f5bdfdSNick Mathewson iocp_listener_getfd(struct evconnlistener *lev)
78720f5bdfdSNick Mathewson {
78820f5bdfdSNick Mathewson struct evconnlistener_iocp *lev_iocp =
78920f5bdfdSNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
79020f5bdfdSNick Mathewson return lev_iocp->fd;
79120f5bdfdSNick Mathewson }
7925d2c1650SNick Mathewson static struct event_base *
iocp_listener_getbase(struct evconnlistener * lev)7935d2c1650SNick Mathewson iocp_listener_getbase(struct evconnlistener *lev)
7945d2c1650SNick Mathewson {
7955d2c1650SNick Mathewson struct evconnlistener_iocp *lev_iocp =
7965d2c1650SNick Mathewson EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
7979a772148SNick Mathewson return lev_iocp->event_base;
7985d2c1650SNick Mathewson }
79920f5bdfdSNick Mathewson
80020f5bdfdSNick Mathewson static const struct evconnlistener_ops evconnlistener_iocp_ops = {
80120f5bdfdSNick Mathewson iocp_listener_enable,
80220f5bdfdSNick Mathewson iocp_listener_disable,
80320f5bdfdSNick Mathewson iocp_listener_destroy,
804127d4f21SNick Mathewson iocp_listener_destroy, /* shutdown */
8055d2c1650SNick Mathewson iocp_listener_getfd,
8065d2c1650SNick Mathewson iocp_listener_getbase
80720f5bdfdSNick Mathewson };
80820f5bdfdSNick Mathewson
8090aa6f513SNick Mathewson /* XXX define some way to override this. */
8100aa6f513SNick Mathewson #define N_SOCKETS_PER_LISTENER 4
8110aa6f513SNick Mathewson
81220f5bdfdSNick Mathewson struct evconnlistener *
evconnlistener_new_async(struct event_base * base,evconnlistener_cb cb,void * ptr,unsigned flags,int backlog,evutil_socket_t fd)81320f5bdfdSNick Mathewson evconnlistener_new_async(struct event_base *base,
81420f5bdfdSNick Mathewson evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
81520f5bdfdSNick Mathewson evutil_socket_t fd)
81620f5bdfdSNick Mathewson {
81720f5bdfdSNick Mathewson struct sockaddr_storage ss;
81820f5bdfdSNick Mathewson int socklen = sizeof(ss);
81920f5bdfdSNick Mathewson struct evconnlistener_iocp *lev;
8200aa6f513SNick Mathewson int i;
8210aa6f513SNick Mathewson
822127d4f21SNick Mathewson flags |= LEV_OPT_THREADSAFE;
823127d4f21SNick Mathewson
8248ac3c4c2SNick Mathewson if (!base || !event_base_get_iocp_(base))
825fec66f96SJardel Weyrich goto err;
8265d2c1650SNick Mathewson
82720f5bdfdSNick Mathewson /* XXXX duplicate code */
82820f5bdfdSNick Mathewson if (backlog > 0) {
82920f5bdfdSNick Mathewson if (listen(fd, backlog) < 0)
830fec66f96SJardel Weyrich goto err;
83120f5bdfdSNick Mathewson } else if (backlog < 0) {
83220f5bdfdSNick Mathewson if (listen(fd, 128) < 0)
833fec66f96SJardel Weyrich goto err;
83420f5bdfdSNick Mathewson }
83520f5bdfdSNick Mathewson if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
83620f5bdfdSNick Mathewson event_sock_warn(fd, "getsockname");
837fec66f96SJardel Weyrich goto err;
83820f5bdfdSNick Mathewson }
839481ef920SNick Mathewson lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
84020f5bdfdSNick Mathewson if (!lev) {
84120f5bdfdSNick Mathewson event_warn("calloc");
842fec66f96SJardel Weyrich goto err;
84320f5bdfdSNick Mathewson }
84420f5bdfdSNick Mathewson lev->base.ops = &evconnlistener_iocp_ops;
84520f5bdfdSNick Mathewson lev->base.cb = cb;
84620f5bdfdSNick Mathewson lev->base.user_data = ptr;
84720f5bdfdSNick Mathewson lev->base.flags = flags;
848127d4f21SNick Mathewson lev->base.refcnt = 1;
84946ee061cSNick Mathewson lev->base.enabled = 1;
85020f5bdfdSNick Mathewson
8518ac3c4c2SNick Mathewson lev->port = event_base_get_iocp_(base);
85220f5bdfdSNick Mathewson lev->fd = fd;
8535d2c1650SNick Mathewson lev->event_base = base;
85446ee061cSNick Mathewson
8555d2c1650SNick Mathewson
8568ac3c4c2SNick Mathewson if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
857fec66f96SJardel Weyrich goto err_free_lev;
85820f5bdfdSNick Mathewson
859127d4f21SNick Mathewson EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
8600aa6f513SNick Mathewson
8610aa6f513SNick Mathewson lev->n_accepting = N_SOCKETS_PER_LISTENER;
8620aa6f513SNick Mathewson lev->accepting = mm_calloc(lev->n_accepting,
8630aa6f513SNick Mathewson sizeof(struct accepting_socket *));
86420f5bdfdSNick Mathewson if (!lev->accepting) {
86520f5bdfdSNick Mathewson event_warn("calloc");
866fec66f96SJardel Weyrich goto err_delete_lock;
86720f5bdfdSNick Mathewson }
8680aa6f513SNick Mathewson for (i = 0; i < lev->n_accepting; ++i) {
8690aa6f513SNick Mathewson lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
8700aa6f513SNick Mathewson if (!lev->accepting[i]) {
87120f5bdfdSNick Mathewson event_warnx("Couldn't create accepting socket");
872fec66f96SJardel Weyrich goto err_free_accepting;
87320f5bdfdSNick Mathewson }
87446ee061cSNick Mathewson if (cb && start_accepting(lev->accepting[i]) < 0) {
87520f5bdfdSNick Mathewson event_warnx("Couldn't start accepting on socket");
8760aa6f513SNick Mathewson EnterCriticalSection(&lev->accepting[i]->lock);
8770aa6f513SNick Mathewson free_and_unlock_accepting_socket(lev->accepting[i]);
878fec66f96SJardel Weyrich goto err_free_accepting;
87920f5bdfdSNick Mathewson }
880127d4f21SNick Mathewson ++lev->base.refcnt;
8810aa6f513SNick Mathewson }
88220f5bdfdSNick Mathewson
8837b40a000SChristopher Davis iocp_listener_event_add(lev);
8847b40a000SChristopher Davis
88520f5bdfdSNick Mathewson return &lev->base;
886fec66f96SJardel Weyrich
887fec66f96SJardel Weyrich err_free_accepting:
888fec66f96SJardel Weyrich mm_free(lev->accepting);
889fec66f96SJardel Weyrich /* XXXX free the other elements. */
890fec66f96SJardel Weyrich err_delete_lock:
891127d4f21SNick Mathewson EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
892fec66f96SJardel Weyrich err_free_lev:
893fec66f96SJardel Weyrich mm_free(lev);
894fec66f96SJardel Weyrich err:
895fec66f96SJardel Weyrich /* Don't close the fd, it is caller's responsibility. */
896fec66f96SJardel Weyrich return NULL;
89720f5bdfdSNick Mathewson }
89820f5bdfdSNick Mathewson
89920f5bdfdSNick Mathewson #endif
900