From 503e0bca694f30c09cad3c3b7955e93220d11b12 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 6 Sep 2012 04:20:37 +0200 Subject: [PATCH] More WIP --- epoll.gyp | 2 - epoll.vcxproj | 2 +- include/epoll.h | 5 +- src/epoll.c | 619 +++++++++++++++++++++++++++++++++++------------- src/msafd.c | 229 ------------------ src/msafd.h | 6 - src/ntapi.c | 0 src/ntapi.h | 2 +- src/test.c | 16 +- 9 files changed, 466 insertions(+), 415 deletions(-) delete mode 100644 src/msafd.c delete mode 100644 src/ntapi.c 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++) {