diff --git a/epoll.gyp b/epoll.gyp
index 22d308f..e4e6c60 100644
--- a/epoll.gyp
+++ b/epoll.gyp
@@ -18,9 +18,7 @@
'sources': [
'common.gypi',
'include/epoll.h',
- 'src/msafd.c',
'src/msafd.h',
- 'src/ntapi.c',
'src/ntapi.h',
'src/tree.h',
'src/epoll.c',
diff --git a/epoll.vcxproj b/epoll.vcxproj
index 88f82fe..b9d623e 100644
--- a/epoll.vcxproj
+++ b/epoll.vcxproj
@@ -1 +1 @@
-DebugWin32ReleaseWin32{2CF47921-4CCE-ADEA-4A82-BC6521983261}Win32ProjepollStaticLibrary$(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\$(Configuration)\obj\$(ProjectName)\falsetrue$(SolutionDir)$(Configuration)\$(ProjectName)$(OutDir)\lib\$(ProjectName).libinclude;src;%(AdditionalIncludeDirectories)/MP %(AdditionalOptions)EnableFastCheckstrueProgramDatabaseSyncfalsefalseDisabledWIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DEBUG;_DEBUG;%(PreprocessorDefinitions)MultiThreadedDebugtruetruefalseLevel3$(OutDir)lib\$(ProjectName).libws2_32.lib;%(AdditionalDependencies)truetruetruetruetrueinclude;src;%(AdditionalIncludeDirectories)WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)include;src;%(AdditionalIncludeDirectories)/MP %(AdditionalOptions)trueProgramDatabaseSyncSpeedtrueAnySuitabletruetrueFullWIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions)MultiThreadedtruetruefalseLevel3true/LTCG %(AdditionalOptions)$(OutDir)lib\$(ProjectName).libws2_32.lib;%(AdditionalDependencies)truetruetruetrueUseLinkTimeCodeGenerationtruetruetrueinclude;src;%(AdditionalIncludeDirectories)WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)
\ No newline at end of file
+DebugWin32ReleaseWin32{2CF47921-4CCE-ADEA-4A82-BC6521983261}Win32ProjepollStaticLibrary$(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\$(Configuration)\obj\$(ProjectName)\falsetrue$(SolutionDir)$(Configuration)\$(ProjectName)$(OutDir)\lib\$(ProjectName).libinclude;src;%(AdditionalIncludeDirectories)/MP %(AdditionalOptions)EnableFastCheckstrueProgramDatabaseSyncfalsefalseDisabledWIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DEBUG;_DEBUG;%(PreprocessorDefinitions)MultiThreadedDebugtruetruefalseLevel3$(OutDir)lib\$(ProjectName).libws2_32.lib;%(AdditionalDependencies)truetruetruetruetrueinclude;src;%(AdditionalIncludeDirectories)WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)include;src;%(AdditionalIncludeDirectories)/MP %(AdditionalOptions)trueProgramDatabaseSyncSpeedtrueAnySuitabletruetrueFullWIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions)MultiThreadedtruetruefalseLevel3true/LTCG %(AdditionalOptions)$(OutDir)lib\$(ProjectName).libws2_32.lib;%(AdditionalDependencies)truetruetruetrueUseLinkTimeCodeGenerationtruetruetrueinclude;src;%(AdditionalIncludeDirectories)WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)
\ No newline at end of file
diff --git a/include/epoll.h b/include/epoll.h
index 45b495e..843bd91 100644
--- a/include/epoll.h
+++ b/include/epoll.h
@@ -20,8 +20,6 @@
#define EPOLLWRBAND 0x200
#define EPOLLRDHUP 0x2000
-#define EPOLL_EVENT_MASK 0xffff
-
/* #define EPOLLET (1 << 30) Not supported */
#define EPOLLONESHOT (1 << 31)
@@ -47,6 +45,7 @@ struct epoll_event {
epoll_data_t data; /* User data variable */
};
+
epoll_t epoll_create();
int epoll_close(epoll_t epoll_hnd);
@@ -55,7 +54,5 @@ int epoll_ctl(epoll_t epoll_hnd, int op, SOCKET sock, struct epoll_event* event)
int epoll_wait(epoll_t epoll_hnd, struct epoll_event* events, int maxevents, int timeout);
-int afd_init();
-
#endif /* EPOLL_H_ */
\ No newline at end of file
diff --git a/src/epoll.c b/src/epoll.c
index 9df9f40..c24f395 100644
--- a/src/epoll.c
+++ b/src/epoll.c
@@ -1,13 +1,19 @@
-#include
#include
-
#include
+#include
+#include
+
#include "msafd.h"
#include "tree.h"
+
#define ARRAY_COUNT(a) (sizeof(a) / (sizeof((a)[0])))
-#define EPOLL_KEY 0xE9011
+
+#define EPOLL__EVENT_MASK 0xffff
+
+#define EPOLL__SOCK_LISTED 0x1
+#define EPOLL__SOCK_DELETED 0x2
typedef struct epoll_port_data_s epoll_port_data_t;
@@ -15,6 +21,24 @@ typedef struct epoll_op_s epoll_op_t;
typedef struct epoll_sock_data_s epoll_sock_data_t;
+static int epoll__initialize();
+static SOCKET epoll__get_peer_socket(epoll_port_data_t* port_data,
+ WSAPROTOCOL_INFOW* protocol_info);
+static SOCKET epoll__create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info);
+static int epoll__compare_sock_data(epoll_sock_data_t* a,
+ epoll_sock_data_t* b);
+static int epoll__submit_poll_op(epoll_port_data_t* port_data,
+ epoll_sock_data_t* sock_data);
+static int epoll__afd_poll(SOCKET socket, AFD_POLL_INFO* info,
+ OVERLAPPED* overlapped);
+static int epoll__ntstatus_to_winsock_error(NTSTATUS status);
+
+
+static int epoll__initialized = 0;
+static PNTDEVICEIOCONTROLFILE pNtDeviceIoControlFile;
+
+
/* State associated with a epoll handle. */
struct epoll_port_data_s {
HANDLE iocp;
@@ -24,15 +48,16 @@ struct epoll_port_data_s {
size_t pending_ops_count;
};
+
/* State associated with a socket that is registered to the epoll port. */
typedef struct epoll_sock_data_s {
SOCKET sock;
SOCKET base_sock;
SOCKET peer_sock;
- int op_generation;
- int submitted_events;
- int events;
- int attn;
+ uint32_t registered_events;
+ uint32_t submitted_events;
+ uint32_t flags;
+ uint32_t op_generation;
uint64_t user_data;
epoll_op_t* free_op;
epoll_sock_data_t* attn_prev;
@@ -44,23 +69,29 @@ typedef struct epoll_sock_data_s {
struct epoll_op_s {
OVERLAPPED overlapped;
AFD_POLL_INFO poll_info;
- int generation;
+ uint32_t generation;
epoll_sock_data_t* sock_data;
};
-int epoll_socket_compare(epoll_sock_data_t* a, epoll_sock_data_t* b) {
- return a->sock - b->sock;
-}
-
-
-RB_GENERATE_STATIC(epoll_sock_data_tree, epoll_sock_data_s, tree_entry, epoll_socket_compare)
+RB_GENERATE_STATIC(epoll_sock_data_tree,
+ epoll_sock_data_s,
+ tree_entry, epoll__compare_sock_data)
epoll_t epoll_create() {
+ epoll_port_data_t* port_data;
HANDLE iocp;
- epoll_port_data_t* port_data = malloc(sizeof *port_data);
+ /* If necessary, do global initialization first. This is totally not */
+ /* thread-safe at the moment. */
+ if (!epoll__initialized) {
+ if (epoll__initialize() < 0)
+ return -1;
+ epoll__initialized = 1;
+ }
+
+ port_data = malloc(sizeof *port_data);
if (port_data == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
@@ -85,128 +116,9 @@ epoll_t epoll_create() {
return (epoll_t) port_data;
}
-static SOCKET epoll__create_peer_socket(HANDLE iocp,
- WSAPROTOCOL_INFOW* protocol_info) {
- SOCKET sock = 0;
-
- sock = WSASocketW(protocol_info->iAddressFamily,
- protocol_info->iSocketType,
- protocol_info->iProtocol,
- protocol_info,
- 0,
- WSA_FLAG_OVERLAPPED);
- if (sock == INVALID_SOCKET) {
- return INVALID_SOCKET;
- }
-
- if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
- goto error;
- };
-
- if (CreateIoCompletionPort((HANDLE) sock,
- iocp,
- EPOLL_KEY,
- 0) == NULL) {
- goto error;
- }
-
- return sock;
-
- error:
- closesocket(sock);
- return INVALID_SOCKET;
-}
-
-
-static SOCKET epoll__get_peer_socket(epoll_port_data_t* port_data,
- WSAPROTOCOL_INFOW* protocol_info) {
- int index, i;
- SOCKET peer_socket;
-
- index = -1;
- for (i = 0; i < ARRAY_COUNT(AFD_PROVIDER_IDS); i++) {
- if (memcmp((void*) &protocol_info->ProviderId,
- (void*) &AFD_PROVIDER_IDS[i],
- sizeof protocol_info->ProviderId) == 0) {
- index = i;
- }
- }
-
- /* Check if the protocol uses an msafd socket. */
- if (index < 0) {
- SetLastError(ERROR_NOT_SUPPORTED);
- return INVALID_SOCKET;
- }
-
- /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
- /* try again if the peer socket creation failed earlier for the same */
- /* protocol. */
- peer_socket = port_data->peer_sockets[index];
- if (peer_socket == 0) {
- peer_socket = epoll__create_peer_socket(port_data->iocp, protocol_info);
- port_data->peer_sockets[index] = peer_socket;
- }
-
- return peer_socket;
-}
-
-
-int epoll__submit_poll_op(epoll_port_data_t* port_data, epoll_sock_data_t* sock_data) {
- epoll_op_t* op;
- int events;
- DWORD result, afd_events;
-
- op = sock_data->free_op;
- events = sock_data->events;
-
- /* epoll_ctl should ensure that there is a free op struct. */
- assert(op != NULL);
-
- /* These events should always be registered. */
- assert(events & EPOLLERR);
- assert(events & EPOLLHUP);
- afd_events = AFD_POLL_ABORT | AFD_POLL_CONNECT_FAIL | AFD_POLL_LOCAL_CLOSE;
-
- if (events & (EPOLLIN | EPOLLRDNORM))
- afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT;
- if (events & (EPOLLIN | EPOLLRDBAND))
- afd_events |= AFD_POLL_RECEIVE_EXPEDITED;
- if (events & (EPOLLOUT | EPOLLWRNORM | EPOLLRDBAND))
- afd_events |= AFD_POLL_SEND | AFD_POLL_CONNECT;
-
- op->generation = ++sock_data->op_generation;
- op->sock_data = sock_data;
-
- memset(&op->overlapped, 0, sizeof op->overlapped);
-
- op->poll_info.Exclusive = TRUE;
- op->poll_info.NumberOfHandles = 1;
- op->poll_info.Timeout.QuadPart = INT64_MAX;
- op->poll_info.Handles[0].Handle = (HANDLE) sock_data->base_sock;
- op->poll_info.Handles[0].Status = 0;
- op->poll_info.Handles[0].Events = afd_events;
-
- result = afd_poll(sock_data->peer_sock,
- &op->poll_info,
- &op->overlapped);
- if (result != 0) {
- DWORD error = WSAGetLastError();
- if (error != WSA_IO_PENDING) {
- /* If this happens an error happened and no overlapped operation was */
- /* started. */
- return -1;
- }
- }
-
- sock_data->free_op = NULL;
- port_data->pending_ops_count++;
-
- return 0;
-}
-
int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
- struct epoll_event* event) {
+ struct epoll_event* ev) {
epoll_port_data_t* port_data;
port_data = (epoll_port_data_t*) port_handle;
@@ -252,12 +164,15 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
sock_data->base_sock = sock;
sock_data->op_generation = 0;
sock_data->submitted_events = 0;
- sock_data->events = event->events | EPOLLERR | EPOLLHUP;
- sock_data->user_data = event->data.u64;
+ sock_data->registered_events = ev->events | EPOLLERR | EPOLLHUP;
+ sock_data->user_data = ev->data.u64;
sock_data->peer_sock = peer_sock;
sock_data->free_op = op;
+ sock_data->flags = 0;
- if (RB_INSERT(epoll_sock_data_tree, &port_data->sock_data_tree, sock_data) != NULL) {
+ if (RB_INSERT(epoll_sock_data_tree,
+ &port_data->sock_data_tree,
+ sock_data) != NULL) {
/* Socket was already added. */
free(sock_data);
free(op);
@@ -265,13 +180,13 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
return -1;
}
- // Add to attention list
- sock_data->attn = 1;
+ /* Add to attention list */
sock_data->attn_prev = NULL;
sock_data->attn_next = port_data->attn;
if (port_data->attn)
port_data->attn->attn_prev = sock_data;
port_data->attn = sock_data;
+ sock_data->flags |= EPOLL__SOCK_LISTED;
return 0;
}
@@ -281,14 +196,16 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
epoll_sock_data_t* sock_data;
lookup.sock = sock;
- sock_data = RB_FIND(epoll_sock_data_tree, &port_data->sock_data_tree, &lookup);
+ sock_data = RB_FIND(epoll_sock_data_tree,
+ &port_data->sock_data_tree,
+ &lookup);
if (sock_data == NULL) {
/* Socket has not been registered with epoll instance. */
SetLastError(ERROR_NOT_FOUND);
return -1;
}
- if (event->events & ~sock_data->submitted_events) {
+ if (ev->events & EPOLL__EVENT_MASK & ~sock_data->submitted_events) {
if (sock_data->free_op == NULL) {
epoll_op_t* op = malloc(sizeof *op);
if (op == NULL) {
@@ -299,19 +216,19 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
sock_data->free_op = NULL;
}
- // Add to attention list, if not already added.
- if (!sock_data->attn) {
+ /* Add to attention list, if not already added. */
+ if (!(sock_data->flags & EPOLL__SOCK_LISTED)) {
sock_data->attn_prev = NULL;
sock_data->attn_next = port_data->attn;
if (port_data->attn)
port_data->attn->attn_prev = sock_data;
port_data->attn = sock_data;
- sock_data->attn = 1;
+ sock_data->flags |= EPOLL__SOCK_LISTED;
}
}
- sock_data->events = event->events | EPOLLERR | EPOLLHUP;
- sock_data->user_data = event->data.u64;
+ sock_data->registered_events = ev->events | EPOLLERR | EPOLLHUP;
+ sock_data->user_data = ev->data.u64;
return 0;
}
@@ -320,7 +237,9 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
epoll_sock_data_t* sock_data;
lookup.sock = sock;
- sock_data = RB_FIND(epoll_sock_data_tree, &port_data->sock_data_tree, &lookup);
+ sock_data = RB_FIND(epoll_sock_data_tree,
+ &port_data->sock_data_tree,
+ &lookup);
if (sock_data == NULL) {
/* Socket has not been registered with epoll instance. */
SetLastError(ERROR_NOT_FOUND);
@@ -330,18 +249,19 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
RB_REMOVE(epoll_sock_data_tree, &port_data->sock_data_tree, sock_data);
free(sock_data->free_op);
- sock_data->events = -1;
+ sock_data->flags |= EPOLL__SOCK_DELETED;
/* Remove from attention list. */
- if (sock_data->attn) {
+ if (sock_data->flags & EPOLL__SOCK_LISTED) {
if (sock_data->attn_prev != NULL)
sock_data->attn_prev->attn_next = sock_data->attn_next;
if (sock_data->attn_next != NULL)
sock_data->attn_next->attn_prev = sock_data->attn_prev;
if (port_data->attn == sock_data)
port_data->attn = sock_data->attn_next;
- sock_data->attn = 0;
- sock_data->attn_prev = sock_data->attn_next = NULL;
+ sock_data->attn_prev = NULL;
+ sock_data->attn_next = NULL;
+ sock_data->flags &= ~EPOLL__SOCK_LISTED;
}
if (sock_data->submitted_events == 0) {
@@ -363,7 +283,8 @@ int epoll_ctl(epoll_t port_handle, int op, SOCKET sock,
}
-int epoll_wait(epoll_t port_handle, struct epoll_event* events, int maxevents, int timeout) {
+int epoll_wait(epoll_t port_handle, struct epoll_event* events, int maxevents,
+ int timeout) {
epoll_port_data_t* port_data;
DWORD due;
DWORD gqcs_timeout;
@@ -373,20 +294,39 @@ int epoll_wait(epoll_t port_handle, struct epoll_event* events, int maxevents, i
/* Create overlapped poll operations for all sockets on the attention list. */
while (port_data->attn != NULL) {
epoll_sock_data_t* sock_data = port_data->attn;
- assert(sock_data->attn);
+ assert(sock_data->flags & EPOLL__SOCK_LISTED);
- /* Check if we need to submit another req. */
- if (sock_data->events & EPOLL_EVENT_MASK & ~sock_data->submitted_events) {
+ /* Check if there are events registered that are not yet submitted. In */
+ /* that case we need to submit another req. */
+ if (sock_data->registered_events & EPOLL__EVENT_MASK &
+ ~sock_data->submitted_events) {
int r = epoll__submit_poll_op(port_data, sock_data);
- /* TODO: handle error. */
+
+ if (r) {
+ /* If submitting the poll op fails then most likely the socket is */
+ /* invalid. In this case we silently remove the socket from the */
+ /* epoll port. Ohter errors make epoll_wait() fail. */
+ if (WSAGetLastError() != WSAENOTSOCK)
+ return -1;
+
+ /* Skip to the next attention list item already, because we're about */
+ /* to delete the currently selected socket. */
+ port_data->attn = sock_data->attn_next;
+ sock_data->flags &= ~EPOLL__SOCK_LISTED;
+
+ /* Delete it. */
+ r = epoll_ctl(port_handle, EPOLL_CTL_DEL, sock_data->sock, NULL);
+ assert(r == 0);
+
+ continue;
+ }
}
/* Remove from attention list */
port_data->attn = sock_data->attn_next;
sock_data->attn_prev = sock_data->attn_next = NULL;
- sock_data->attn = 0;
+ sock_data->flags &= ~EPOLL__SOCK_LISTED;
}
- port_data->attn = NULL;
/* Compute the timeout for GetQueuedCompletionStatus, and the wait end */
/* time, if the user specified a timeout other than zero or infinite. */
@@ -453,12 +393,12 @@ int epoll_wait(epoll_t port_handle, struct epoll_event* events, int maxevents, i
sock_data->submitted_events = 0;
sock_data->free_op = op;
- registered_events = sock_data->events;
+ registered_events = sock_data->registered_events;
reported_events = 0;
/* Check if this op was associated with a socket that was removed */
/* with EPOLL_CTL_DEL. */
- if (registered_events == -1) {
+ if (sock_data->flags & EPOLL__SOCK_DELETED) {
free(op);
free(sock_data);
continue;
@@ -509,7 +449,7 @@ int epoll_wait(epoll_t port_handle, struct epoll_event* events, int maxevents, i
/* Unless EPOLLONESHOT is used or no events were reported that the */
/* user is interested in, add the socket back to the attention list. */
if (!registered_events & EPOLLONESHOT || reported_events == 0) {
- assert(!sock_data->attn);
+ assert(!(sock_data->flags & EPOLL__SOCK_LISTED));
if (port_data->attn == NULL) {
sock_data->attn_next = sock_data->attn_prev = NULL;
port_data->attn = sock_data;
@@ -606,4 +546,359 @@ int epoll_close(epoll_t port_handle) {
free(port_data);
return 0;
+}
+
+
+int epoll__initialize() {
+ HMODULE ntdll;
+ int r;
+ WSADATA wsa_data;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (r != 0)
+ return -1;
+
+ ntdll = LoadLibraryW(L"ntdll.dll");
+ if (ntdll == NULL)
+ return -1;
+
+ pNtDeviceIoControlFile = (PNTDEVICEIOCONTROLFILE) GetProcAddress(ntdll,
+ "NtDeviceIoControlFile");
+ if (pNtDeviceIoControlFile == NULL)
+ return -1;
+
+ return 0;
+}
+
+
+SOCKET epoll__get_peer_socket(epoll_port_data_t* port_data,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ int index, i;
+ SOCKET peer_socket;
+
+ index = -1;
+ for (i = 0; i < ARRAY_COUNT(AFD_PROVIDER_IDS); i++) {
+ if (memcmp((void*) &protocol_info->ProviderId,
+ (void*) &AFD_PROVIDER_IDS[i],
+ sizeof protocol_info->ProviderId) == 0) {
+ index = i;
+ }
+ }
+
+ /* Check if the protocol uses an msafd socket. */
+ if (index < 0) {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return INVALID_SOCKET;
+ }
+
+ /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+ /* try again if the peer socket creation failed earlier for the same */
+ /* protocol. */
+ peer_socket = port_data->peer_sockets[index];
+ if (peer_socket == 0) {
+ peer_socket = epoll__create_peer_socket(port_data->iocp, protocol_info);
+ port_data->peer_sockets[index] = peer_socket;
+ }
+
+ return peer_socket;
+}
+
+
+SOCKET epoll__create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ SOCKET sock = 0;
+
+ sock = WSASocketW(protocol_info->iAddressFamily,
+ protocol_info->iSocketType,
+ protocol_info->iProtocol,
+ protocol_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ if (sock == INVALID_SOCKET) {
+ return INVALID_SOCKET;
+ }
+
+ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+ goto error;
+ };
+
+ if (CreateIoCompletionPort((HANDLE) sock,
+ iocp,
+ 0,
+ 0) == NULL) {
+ goto error;
+ }
+
+ return sock;
+
+ error:
+ closesocket(sock);
+ return INVALID_SOCKET;
+}
+
+
+int epoll__compare_sock_data(epoll_sock_data_t* a,
+ epoll_sock_data_t* b) {
+ return a->sock - b->sock;
+}
+
+
+int epoll__submit_poll_op(epoll_port_data_t* port_data,
+ epoll_sock_data_t* sock_data) {
+ epoll_op_t* op;
+ int registered_events;
+ DWORD result, afd_events;
+
+ op = sock_data->free_op;
+ registered_events = sock_data->registered_events;
+
+ /* epoll_ctl should ensure that there is a free op struct. */
+ assert(op != NULL);
+
+ /* These events should always be registered. */
+ assert(registered_events & EPOLLERR);
+ assert(registered_events & EPOLLHUP);
+ afd_events = AFD_POLL_ABORT | AFD_POLL_CONNECT_FAIL | AFD_POLL_LOCAL_CLOSE;
+
+ if (registered_events & (EPOLLIN | EPOLLRDNORM))
+ afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT;
+ if (registered_events & (EPOLLIN | EPOLLRDBAND))
+ afd_events |= AFD_POLL_RECEIVE_EXPEDITED;
+ if (registered_events & (EPOLLOUT | EPOLLWRNORM | EPOLLRDBAND))
+ afd_events |= AFD_POLL_SEND | AFD_POLL_CONNECT;
+
+ op->generation = sock_data->op_generation + 1;
+ op->sock_data = sock_data;
+
+ memset(&op->overlapped, 0, sizeof op->overlapped);
+
+ op->poll_info.Exclusive = TRUE;
+ op->poll_info.NumberOfHandles = 1;
+ op->poll_info.Timeout.QuadPart = INT64_MAX;
+ op->poll_info.Handles[0].Handle = (HANDLE) sock_data->base_sock;
+ op->poll_info.Handles[0].Status = 0;
+ op->poll_info.Handles[0].Events = afd_events;
+
+ result = epoll__afd_poll(sock_data->peer_sock,
+ &op->poll_info,
+ &op->overlapped);
+ if (result != 0) {
+ DWORD error = WSAGetLastError();
+ if (error != WSA_IO_PENDING) {
+ /* If this happens an error happened and no overlapped operation was */
+ /* started. */
+ return -1;
+ }
+ }
+
+ sock_data->submitted_events = registered_events;
+ sock_data->op_generation = op->generation;
+ sock_data->free_op = NULL;
+ port_data->pending_ops_count++;
+
+ return 0;
+}
+
+
+int epoll__afd_poll(SOCKET socket, AFD_POLL_INFO* info,
+ OVERLAPPED* overlapped) {
+ IO_STATUS_BLOCK iosb;
+ IO_STATUS_BLOCK* iosb_ptr;
+ HANDLE event = NULL;
+ void* apc_context;
+ NTSTATUS status;
+ DWORD error;
+
+ if (overlapped != NULL) {
+ /* Overlapped operation. */
+ iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ event = overlapped->hEvent;
+
+ /* Do not report iocp completion if hEvent is tagged. */
+ if ((uintptr_t) event & 1) {
+ event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+ apc_context = NULL;
+ } else {
+ apc_context = overlapped;
+ }
+
+ } else {
+ /* Blocking operation. */
+ iosb_ptr = &iosb;
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return SOCKET_ERROR;
+ }
+ apc_context = NULL;
+ }
+
+ iosb_ptr->Status = STATUS_PENDING;
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ event,
+ NULL,
+ apc_context,
+ iosb_ptr,
+ IOCTL_AFD_POLL,
+ info,
+ sizeof *info,
+ info,
+ sizeof *info);
+
+ if (overlapped == NULL) {
+ /* If this is a blocking operation, wait for the event to become */
+ /* signaled, and then grab the real status from the io status block. */
+ if (status == STATUS_PENDING) {
+ DWORD r = WaitForSingleObject(event, INFINITE);
+
+ if (r == WAIT_FAILED) {
+ DWORD saved_error = GetLastError();
+ CloseHandle(event);
+ WSASetLastError(saved_error);
+ return SOCKET_ERROR;
+ }
+
+ status = iosb.Status;
+ }
+
+ CloseHandle(event);
+ }
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ default:
+ error = epoll__ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+int epoll__ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ case STATUS_TOO_MANY_ADDRESSES:
+ return WSAENOBUFS;
+
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ case STATUS_HOPLIMIT_EXCEEDED:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
+ (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/msafd.c b/src/msafd.c
deleted file mode 100644
index 2987877..0000000
--- a/src/msafd.c
+++ /dev/null
@@ -1,229 +0,0 @@
-
-#include
-#include
-
-#include "msafd.h"
-#include "ntapi.h"
-
-
-static int afd_ntstatus_to_winsock_error(NTSTATUS status);
-static sNtDeviceIoControlFile pNtDeviceIoControlFile;
-
-int afd_init() {
- HMODULE ntdll;
-
- ntdll = LoadLibraryW(L"ntdll.dll");
- if (ntdll == NULL)
- return -1;
-
- pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(ntdll,
- "NtDeviceIoControlFile");
- if (pNtDeviceIoControlFile == NULL)
- return -1;
-
- return 0;
-}
-
-
-int WSAAPI afd_poll(SOCKET socket, AFD_POLL_INFO* info,
- OVERLAPPED* overlapped) {
- IO_STATUS_BLOCK iosb;
- IO_STATUS_BLOCK* iosb_ptr;
- HANDLE event = NULL;
- void* apc_context;
- NTSTATUS status;
- DWORD error;
-
- if (overlapped != NULL) {
- /* Overlapped operation. */
- iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
- event = overlapped->hEvent;
-
- /* Do not report iocp completion if hEvent is tagged. */
- if ((uintptr_t) event & 1) {
- event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
- apc_context = NULL;
- } else {
- apc_context = overlapped;
- }
-
- } else {
- /* Blocking operation. */
- iosb_ptr = &iosb;
- event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (event == NULL) {
- return SOCKET_ERROR;
- }
- apc_context = NULL;
- }
-
- iosb_ptr->Status = STATUS_PENDING;
- status = pNtDeviceIoControlFile((HANDLE) socket,
- event,
- NULL,
- apc_context,
- iosb_ptr,
- IOCTL_AFD_POLL,
- info,
- sizeof *info,
- info,
- sizeof *info);
-
- if (overlapped == NULL) {
- /* If this is a blocking operation, wait for the event to become */
- /* signaled, and then grab the real status from the io status block. */
- if (status == STATUS_PENDING) {
- DWORD r = WaitForSingleObject(event, INFINITE);
-
- if (r == WAIT_FAILED) {
- DWORD saved_error = GetLastError();
- CloseHandle(event);
- WSASetLastError(saved_error);
- return SOCKET_ERROR;
- }
-
- status = iosb.Status;
- }
-
- CloseHandle(event);
- }
-
- switch (status) {
- case STATUS_SUCCESS:
- error = ERROR_SUCCESS;
- break;
-
- case STATUS_PENDING:
- error = WSA_IO_PENDING;
- break;
-
- default:
- error = afd_ntstatus_to_winsock_error(status);
- break;
- }
-
- WSASetLastError(error);
-
- if (error == ERROR_SUCCESS) {
- return 0;
- } else {
- return SOCKET_ERROR;
- }
-}
-
-
-static int afd_ntstatus_to_winsock_error(NTSTATUS status) {
- switch (status) {
- case STATUS_SUCCESS:
- return ERROR_SUCCESS;
-
- case STATUS_PENDING:
- return ERROR_IO_PENDING;
-
- case STATUS_INVALID_HANDLE:
- case STATUS_OBJECT_TYPE_MISMATCH:
- return WSAENOTSOCK;
-
- case STATUS_INSUFFICIENT_RESOURCES:
- case STATUS_PAGEFILE_QUOTA:
- case STATUS_COMMITMENT_LIMIT:
- case STATUS_WORKING_SET_QUOTA:
- case STATUS_NO_MEMORY:
- case STATUS_CONFLICTING_ADDRESSES:
- case STATUS_QUOTA_EXCEEDED:
- case STATUS_TOO_MANY_PAGING_FILES:
- case STATUS_REMOTE_RESOURCES:
- case STATUS_TOO_MANY_ADDRESSES:
- return WSAENOBUFS;
-
- case STATUS_SHARING_VIOLATION:
- case STATUS_ADDRESS_ALREADY_EXISTS:
- return WSAEADDRINUSE;
-
- case STATUS_LINK_TIMEOUT:
- case STATUS_IO_TIMEOUT:
- case STATUS_TIMEOUT:
- return WSAETIMEDOUT;
-
- case STATUS_GRACEFUL_DISCONNECT:
- return WSAEDISCON;
-
- case STATUS_REMOTE_DISCONNECT:
- case STATUS_CONNECTION_RESET:
- case STATUS_LINK_FAILED:
- case STATUS_CONNECTION_DISCONNECTED:
- case STATUS_PORT_UNREACHABLE:
- case STATUS_HOPLIMIT_EXCEEDED:
- return WSAECONNRESET;
-
- case STATUS_LOCAL_DISCONNECT:
- case STATUS_TRANSACTION_ABORTED:
- case STATUS_CONNECTION_ABORTED:
- return WSAECONNABORTED;
-
- case STATUS_BAD_NETWORK_PATH:
- case STATUS_NETWORK_UNREACHABLE:
- case STATUS_PROTOCOL_UNREACHABLE:
- return WSAENETUNREACH;
-
- case STATUS_HOST_UNREACHABLE:
- return WSAEHOSTUNREACH;
-
- case STATUS_CANCELLED:
- case STATUS_REQUEST_ABORTED:
- return WSAEINTR;
-
- case STATUS_BUFFER_OVERFLOW:
- case STATUS_INVALID_BUFFER_SIZE:
- return WSAEMSGSIZE;
-
- case STATUS_BUFFER_TOO_SMALL:
- case STATUS_ACCESS_VIOLATION:
- return WSAEFAULT;
-
- case STATUS_DEVICE_NOT_READY:
- case STATUS_REQUEST_NOT_ACCEPTED:
- return WSAEWOULDBLOCK;
-
- case STATUS_INVALID_NETWORK_RESPONSE:
- case STATUS_NETWORK_BUSY:
- case STATUS_NO_SUCH_DEVICE:
- case STATUS_NO_SUCH_FILE:
- case STATUS_OBJECT_PATH_NOT_FOUND:
- case STATUS_OBJECT_NAME_NOT_FOUND:
- case STATUS_UNEXPECTED_NETWORK_ERROR:
- return WSAENETDOWN;
-
- case STATUS_INVALID_CONNECTION:
- return WSAENOTCONN;
-
- case STATUS_REMOTE_NOT_LISTENING:
- case STATUS_CONNECTION_REFUSED:
- return WSAECONNREFUSED;
-
- case STATUS_PIPE_DISCONNECTED:
- return WSAESHUTDOWN;
-
- case STATUS_INVALID_ADDRESS:
- case STATUS_INVALID_ADDRESS_COMPONENT:
- return WSAEADDRNOTAVAIL;
-
- case STATUS_NOT_SUPPORTED:
- case STATUS_NOT_IMPLEMENTED:
- return WSAEOPNOTSUPP;
-
- case STATUS_ACCESS_DENIED:
- return WSAEACCES;
-
- default:
- if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
- (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
- /* It's a windows error that has been previously mapped to an */
- /* ntstatus code. */
- return (DWORD) (status & 0xffff);
- } else {
- /* The default fallback for unmappable ntstatus codes. */
- return WSAEINVAL;
- }
- }
-}
\ No newline at end of file
diff --git a/src/msafd.h b/src/msafd.h
index e15e16a..90177b5 100644
--- a/src/msafd.h
+++ b/src/msafd.h
@@ -68,10 +68,4 @@ static const GUID AFD_PROVIDER_IDS[] = {
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
};
-
-int afd_init();
-
-int WSAAPI afd_poll(SOCKET socket, AFD_POLL_INFO* info,
- OVERLAPPED* overlapped);
-
#endif /* EPOLL_MSAFD_H_ */
\ No newline at end of file
diff --git a/src/ntapi.c b/src/ntapi.c
deleted file mode 100644
index e69de29..0000000
diff --git a/src/ntapi.h b/src/ntapi.h
index 45a6251..7ac6f3d 100644
--- a/src/ntapi.h
+++ b/src/ntapi.h
@@ -4073,7 +4073,7 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
ULONG Reserved);
-typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
+typedef NTSTATUS (NTAPI *PNTDEVICEIOCONTROLFILE)
(HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
diff --git a/src/test.c b/src/test.c
index 64f2960..189a9f2 100644
--- a/src/test.c
+++ b/src/test.c
@@ -11,6 +11,8 @@ static const char PING[] = "PING";
static const int NUM_PINGERS = 10000;
static const int RUN_TIME = 10000;
+int x = 0;
+
int main(int argc, char* argv[]) {
epoll_t epoll_hnd;
WSADATA wsa_data;
@@ -23,13 +25,8 @@ int main(int argc, char* argv[]) {
long long pings = 0, pings_sent = 0;
int i;
- r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
- assert(r == 0);
-
- afd_init();
-
epoll_hnd = epoll_create();
- assert(epoll_hnd);
+ assert(epoll_hnd && epoll_hnd != INVALID_HANDLE_VALUE);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
@@ -54,7 +51,6 @@ int main(int argc, char* argv[]) {
memset(bind_addr.sin_zero, 0, sizeof bind_addr.sin_zero);
*/
-
for (i = 0; i < NUM_PINGERS; i++) {
SOCKET sock;
struct epoll_event ev;
@@ -104,11 +100,11 @@ int main(int argc, char* argv[]) {
printf("%lld pings (%f per sec), %lld sent\n", pings, (double) pings / (ticks - ticks_start) * 1000, pings_sent);
ticks_last = ticks;
- if (ticks - ticks_start > RUN_TIME)
- break;
+ // if (ticks - ticks_start > RUN_TIME)
+ // break;
}
- count = epoll_wait(epoll_hnd, events, 16, 1000);
+ count = epoll_wait(epoll_hnd, events, 15, 1000);
assert(count >= 0);
for (i = 0; i < count; i++) {