All pastes #1648120 Raw Edit

Untitled

public text v1 · immutable
#1648120 ·published 2009-10-29 17:57 UTC
rendered paste body
diff --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