rendered paste bodydiff --git a/libevent/event_iocp.c b/libevent/event_iocp.c
index 4c144af..6104344 100644
--- a/libevent/event_iocp.c
+++ b/libevent/event_iocp.c
@@ -28,6 +28,7 @@
#include <windows.h>
#include <process.h>
#include <stdio.h>
+#include <mswsock.h>
#include "event2/util.h"
#include "util-internal.h"
@@ -98,12 +99,72 @@ event_iocp_port_associate(struct event_iocp_port *port, evutil_socket_t fd,
return 0;
}
+static void *
+get_extention_function(SOCKET s, const GUID *which_fn)
+{
+ void *ptr = NULL;
+ DWORD bytes;
+ WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINER,
+ which_fn, sizeof(*which_fn),
+ &ptr, sizeof(ptr),
+ NULL, NULL);
+
+ /* No need to detect errors here: if ptr is set, then we have a good
+ function pointer. Otherwise, we should behave as if we had no
+ function pointer.
+ */
+ return ptr;
+}
+
+/* Mingw doesn't have these in its mswsock.h. The values are copied from
+ wine.h. Perhaps if we copy them exactly, the cargo will come again.
+*/
+#ifndef WSAID_ACCEPTEX
+#define WSAID_ACCEPTEX \
+ {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+#endif
+#ifndef WSAID_CONNECTEX
+#define WSAID_CONNECTEX \
+ {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
+#endif
+#ifndef WSAID_GETACCEPTEXSOCKADDRS
+#define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+#endif
+
+static void
+init_extension_functions(struct win32_extension_fns *ext)
+{
+ const GUID acceptex = WSAID_ACCEPTEX;
+ const GUID connectex = WSAID_CONNECTEX
+ SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return;
+ ext->AcceptEx = get_extension_function(s, &acceptex);
+ ext->ConnectEx = get_extension_function(s, &connectex);
+ ext->GetAcceptExSockAddrs = get_extension_function(s,
+ &getacceptexsockaddrs);
+ closesocket(s);
+}
+
+static struct win32_extension_fns the_extension_fns;
+static int extension_fns_initialized = 0;
+
+const struct win32_extension_fns *
+event_get_win32_extension_fns(void)
+{
+ return &the_extension_fns;
+}
+
struct event_iocp_port *
event_iocp_port_launch(void)
{
struct event_iocp_port *port;
int i;
+ if (!extension_fns_initialized)
+ init_extension_functions(&the_extension_fns)
+
if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
return NULL;
port->n_threads = 2;
diff --git a/libevent/iocp-internal.h b/libevent/iocp-internal.h
index d743bd5..4b18fea 100644
--- a/libevent/iocp-internal.h
+++ b/libevent/iocp-internal.h
@@ -53,6 +53,21 @@ struct event_overlapped {
iocp_callback cb;
};
+/* Mingw's headers don't define LPFN_ACCEPTEX. */
+
+typedef BOOL (WINAPI *AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED);
+typedef BOOL (WINAPI *ConnectExPtr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
+typedef void (WINAPI *GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR *, LPINT, LPSOCKADDR *, LPINT);
+
+/** Internal use only. Holds pointers to functions that only some versions of
+ Windows provide.
+ */
+struct win32_extention_fns {
+ AcceptExPtr AcceptEx;
+ ConnectExPtr ConnectEx;
+ GetAcceptSockAddrsPtr GetAcceptExSockaddrs;
+};
+
/**
Internal use only. Stores a Windows IO Completion port, along with
related data.
@@ -73,9 +88,11 @@ struct event_iocp_port {
HANDLE *threads;
/** Number of threads currently open on this port. */
short n_live_threads;
- /* A semaphore to signal when we are done shutting down. */
+ /** A semaphore to signal when we are done shutting down. */
HANDLE *shutdownSemaphore;
};
+
+const struct win32_extension_fns *event_get_win32_extension_fns(void);
#else
/* Dummy definition so we can test-compile more things on unix. */
struct event_overlapped {
diff --git a/libevent/listener.c b/libevent/listener.c
index 3051c80..76392eb 100644
--- a/libevent/listener.c
+++ b/libevent/listener.c
@@ -57,6 +57,10 @@ struct evconnlistener {
evconnlistener_cb cb;
void *user_data;
unsigned flags;
+#ifdef WIN32
+ evutil_socket_t fd;
+ struct iocp_port *port;
+#endif
};
static void listener_read_cb(evutil_socket_t, short, void *);
@@ -183,3 +187,106 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
return;
event_sock_warn(fd, "Error from accept() call");
}
+
+#ifdef WIN32
+struct accepting_socket {
+ struct event_overlapped overlapped;
+ SOCKET s;
+ struct evconnlistener *lev;
+ int buflen;
+ char addrbuf[1]; /*XXX */
+};
+
+static struct accepting_socket *
+new_accepting_socket(struct evconnlistener *lev, int family)
+{
+ struct accepting_socket *res;
+ int addrlen;
+ int buflen;
+ if (family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return NULL;
+ buflen = (addrlen+16)*2;
+
+ mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
+
+ if (!res)
+ return NULL;
+
+ event_overlapped_init(&res->overlapped, accepted_socket_cb);
+ res->socket = INVALID_SOCKET;
+ res->lev = lev;
+ res->buflen = buflen;
+ return res;
+}
+
+static int
+start_accepting(struct accepting_socket *as)
+{
+ const struct win32_extension_fns *ext = get_win32_extension_fns();
+ int family = AF_INET; /* XXXX */
+ SOCKET s = socket(family, SOCK_STREAM, 0);
+ DWORD pending = 0;
+ if (s == INVALID_SOCKET)
+ return -1;
+
+ setsockopt(s,
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&as->lev->fd,
+ sizeof(&as->lev->fd));
+
+ if (!(as->lev->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
+ evutil_make_socket_nonblocking(s);
+
+ if (event_iocp_port_associate(as->lev->iocp_port, s, 1) < 0)
+ return -1;
+
+ as->s = s;
+
+ if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
+ as->buflen/2, as->buflen/2,
+ &pending, &as->o)) {
+ /* Immediate success! */
+ accepted_socket_cb(&as->o, 1, 0);
+ return 0;
+ } else {
+ int err = WSAGetLastError();
+ if (err == ERROR_IO_PENDING)
+ return 0;
+ /* XXXX log the error */
+ return -1;
+ }
+}
+
+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 */
+
+ struct sockaddr *sa_local=NULL, *sa_remote=NULL;
+ int socklen_local=0, socklen_remote=0;
+ struct accepting_socket *as =
+ EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
+ const struct win32_extension_fns *ext = get_win32_extension_fns();
+
+ EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
+
+ ext->GetAcceptExSockaddrs(as->addrbuf, 0,
+ as->buflen/2, as->buflen/2,
+ &sa_local, &socklen_local,
+ &sa_remote, &socklen_remote);
+
+ as->s = INVALID_SOCKET;
+
+ as->lev->cb(lev, as->s, sa_remote, socklen_remote,
+ as->lev->user_data);
+
+ /* Avoid stack overflow XXXX */
+ start_accepting(as);
+}
+
+#endif