int (*disable)(struct evconnlistener *);
void (*destroy)(struct evconnlistener *);
evutil_socket_t (*getfd)(struct evconnlistener *);
+ struct event_base *(*getbase)(struct evconnlistener *);
};
struct evconnlistener {
struct evconnlistener_iocp {
struct evconnlistener base;
evutil_socket_t fd;
+ struct event_base *event_base;
struct event_iocp_port *port;
int n_accepting;
struct accepting_socket **accepting;
};
#endif
+struct evconnlistener *
+evconnlistener_new_async(struct event_base *base,
+ evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
+ evutil_socket_t fd); /* XXXX export this? */
+
static int event_listener_enable(struct evconnlistener *);
static int event_listener_disable(struct evconnlistener *);
static void event_listener_destroy(struct evconnlistener *);
static evutil_socket_t event_listener_getfd(struct evconnlistener *);
+static struct event_base *event_listener_getbase(struct evconnlistener *);
static const struct evconnlistener_ops evconnlistener_event_ops = {
- event_listener_enable,
- event_listener_disable,
- event_listener_destroy,
- event_listener_getfd
+ event_listener_enable,
+ event_listener_disable,
+ event_listener_destroy,
+ event_listener_getfd,
+ event_listener_getbase
};
static void listener_read_cb(evutil_socket_t, short, void *);
evutil_socket_t fd)
{
struct evconnlistener_event *lev;
+#ifdef WIN32
+ if (event_base_get_iocp(base)) {
+ const struct win32_extension_fns *ext =
+ event_get_win32_extension_fns();
+ if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
+ return evconnlistener_new_async(base, cb, ptr, flags,
+ backlog, fd);
+ }
+#endif
if (backlog > 0) {
if (listen(fd, backlog) < 0)
return NULL;
return event_del(&lev_e->listener);
}
-struct event_base *
-evconnlistener_get_base(struct evconnlistener *lev)
-{
- /* XXXX UPCAST. */
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
- return event_get_base(&lev_e->listener);
-}
-
evutil_socket_t
evconnlistener_get_fd(struct evconnlistener *lev)
{
return event_get_fd(&lev_e->listener);
}
+struct event_base *
+evconnlistener_get_base(struct evconnlistener *lev)
+{
+ return lev->ops->getbase(lev);
+}
+
+static struct event_base *
+event_listener_getbase(struct evconnlistener *lev)
+{
+ struct evconnlistener_event *lev_e =
+ EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
+ return event_get_base(&lev_e->listener);
+}
+
static void
listener_read_cb(evutil_socket_t fd, short what, void *p)
{
#ifdef WIN32
struct accepting_socket {
+ CRITICAL_SECTION lock;
struct event_overlapped overlapped;
SOCKET s;
struct evconnlistener_iocp *lev;
- int buflen;
- char addrbuf[1]; /*XXX */
+ ev_uint8_t buflen;
+ ev_uint8_t family;
+ unsigned free_on_cb:1;
+ char addrbuf[1];
};
static void accepted_socket_cb(struct event_overlapped *o, uintptr_t key,
res->s = INVALID_SOCKET;
res->lev = lev;
res->buflen = buflen;
+ res->family = family;
+
+ InitializeCriticalSection(&res->lock);
+
return res;
}
+static void
+free_and_unlock_accepting_socket(struct accepting_socket *as)
+{
+ /* requires lock. */
+ if (res->s != INVALID_SOCKET)
+ closesocket(as->s);
+
+ LeaveCriticalSection(&as->lock);
+ DeleteCriticalSection(&as->lock);
+ mm_free(as);
+}
+
static int
start_accepting(struct accepting_socket *as)
{
+ int result = -1;
const struct win32_extension_fns *ext =
event_get_win32_extension_fns();
- int family = AF_INET; /* XXXX */
- SOCKET s = socket(family, SOCK_STREAM, 0);
+ SOCKET s = socket(as->family, SOCK_STREAM, 0);
DWORD pending = 0;
if (s == INVALID_SOCKET)
return -1;
evutil_make_socket_nonblocking(s);
if (event_iocp_port_associate(as->lev->port, s, 1) < 0)
- return -1;
+ goto done;
as->s = s;
&pending, &as->overlapped.overlapped)) {
/* Immediate success! */
accepted_socket_cb(&as->overlapped, 1, 0);
- return 0;
+ result = 0;
} else {
int err = WSAGetLastError();
if (err == ERROR_IO_PENDING)
- return 0;
- /* XXXX log the error */
- return -1;
+ result = 0;
+ event_sock_warn(as->lev->fd, "AcceptEx");
}
+
+done:
+ LeaveCriticalSection(&as->lock);
+ return result;
+}
+
+static void
+stop_accepting(struct accepting_socket *as)
+{
+ /* XXX */
}
static void
accepted_socket_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n)
{
/* Run this whole thing deferred unless some MT flag is set */
+ /* XXX needs locking. */
struct sockaddr *sa_local=NULL, *sa_remote=NULL;
int socklen_local=0, socklen_remote=0;
EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
const struct win32_extension_fns *ext =
event_get_win32_extension_fns();
-
EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
ext->GetAcceptExSockaddrs(as->addrbuf, 0,
iocp_listener_getfd(struct evconnlistener *lev)
{
struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
return lev_iocp->fd;
}
+static struct event_base *
+iocp_listener_getbase(struct evconnlistener *lev)
+{
+ struct evconnlistener_iocp *lev_iocp =
+ EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
+ return lev_iocp->event_basex;
+}
static const struct evconnlistener_ops evconnlistener_iocp_ops = {
- iocp_listener_enable,
- iocp_listener_disable,
- iocp_listener_destroy,
- iocp_listener_getfd
+ iocp_listener_enable,
+ iocp_listener_disable,
+ iocp_listener_destroy,
+ iocp_listener_getfd,
+ iocp_listener_getbase
};
-struct evconnlistener *
-evconnlistener_new_async(struct event_base *base,
- evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
- evutil_socket_t fd); /* XXXX Use or export this. */
-
struct evconnlistener *
evconnlistener_new_async(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
struct sockaddr_storage ss;
int socklen = sizeof(ss);
struct evconnlistener_iocp *lev;
+ if (!event_base_get_iocp(base))
+ return NULL;
+
/* XXXX duplicate code */
if (backlog > 0) {
if (listen(fd, backlog) < 0)
lev->base.user_data = ptr;
lev->base.flags = flags;
+ lev->port = event_base_get_iocp(base);
lev->fd = fd;
+ lev->event_base = base;
+
+ if (event_iocp_port_associate(lev->port, fd, 1) < 0)
+ return -1;
lev->n_accepting = 1;
lev->accepting = mm_calloc(1, sizeof(struct accepting_socket *));
return NULL;
}
- if (!start_accepting(lev->accepting[0])) {
+ if (start_accepting(lev->accepting[0]) < 0) {
event_warnx("Couldn't start accepting on socket");
- /* XXX free everything */
+ EnterCriticalSection(lev->accepting[0]);
+ free_and_unlock_accepting_socket(lev->accepting[0]);
+ mm_free(lev->accepting);
+ mm_free(lev);
+ closesocket(fd);
return NULL;
}