version 1.5.8

This commit is contained in:
Bert Belder 2020-06-29 04:38:00 +02:00
commit 0598a791bf
No known key found for this signature in database
GPG Key ID: 7A77887B2E2ED461
2 changed files with 90 additions and 93 deletions

181
wepoll.c
View File

@ -29,7 +29,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef WEPOLL_EXPORT
#define WEPOLL_EXPORT #define WEPOLL_EXPORT
#endif
#include <stdint.h> #include <stdint.h>
@ -110,36 +112,29 @@ WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
#include <stdlib.h> #include <stdlib.h>
#define WEPOLL_INTERNAL static #define WEPOLL_INTERNAL static
#define WEPOLL_INTERNAL_VAR static #define WEPOLL_INTERNAL_EXTERN static
#ifndef WIN32_LEAN_AND_MEAN #if defined(__clang__)
#define WIN32_LEAN_AND_MEAN
#endif
#ifdef __clang__
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
#pragma clang diagnostic ignored "-Wreserved-id-macro" #pragma clang diagnostic ignored "-Wreserved-id-macro"
#endif #elif defined(_MSC_VER)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifndef __GNUC__
#pragma warning(push, 1) #pragma warning(push, 1)
#endif #endif
#include <WS2tcpip.h> #undef WIN32_LEAN_AND_MEAN
#include <WinSock2.h> #define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#ifndef __GNUC__ #undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
#endif #endif
@ -271,7 +266,7 @@ typedef struct _OBJECT_ATTRIBUTES {
X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status)) X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status))
#define X(return_type, attributes, name, parameters) \ #define X(return_type, attributes, name, parameters) \
WEPOLL_INTERNAL_VAR return_type(attributes* name) parameters; WEPOLL_INTERNAL_EXTERN return_type(attributes* name) parameters;
NT_NTDLL_IMPORT_LIST(X) NT_NTDLL_IMPORT_LIST(X)
#undef X #undef X
@ -297,13 +292,13 @@ typedef struct _AFD_POLL_INFO {
AFD_POLL_HANDLE_INFO Handles[1]; AFD_POLL_HANDLE_INFO Handles[1];
} AFD_POLL_INFO, *PAFD_POLL_INFO; } AFD_POLL_INFO, *PAFD_POLL_INFO;
WEPOLL_INTERNAL int afd_create_helper_handle(HANDLE iocp_handle, WEPOLL_INTERNAL int afd_create_device_handle(HANDLE iocp_handle,
HANDLE* afd_helper_handle_out); HANDLE* afd_device_handle_out);
WEPOLL_INTERNAL int afd_poll(HANDLE afd_helper_handle, WEPOLL_INTERNAL int afd_poll(HANDLE afd_device_handle,
AFD_POLL_INFO* poll_info, AFD_POLL_INFO* poll_info,
IO_STATUS_BLOCK* io_status_block); IO_STATUS_BLOCK* io_status_block);
WEPOLL_INTERNAL int afd_cancel_poll(HANDLE afd_helper_handle, WEPOLL_INTERNAL int afd_cancel_poll(HANDLE afd_device_handle,
IO_STATUS_BLOCK* io_status_block); IO_STATUS_BLOCK* io_status_block);
#define return_map_error(value) \ #define return_map_error(value) \
@ -324,24 +319,24 @@ WEPOLL_INTERNAL int err_check_handle(HANDLE handle);
#define IOCTL_AFD_POLL 0x00012024 #define IOCTL_AFD_POLL 0x00012024
static UNICODE_STRING afd__helper_name = static UNICODE_STRING afd__device_name =
RTL_CONSTANT_STRING(L"\\Device\\Afd\\Wepoll"); RTL_CONSTANT_STRING(L"\\Device\\Afd\\Wepoll");
static OBJECT_ATTRIBUTES afd__helper_attributes = static OBJECT_ATTRIBUTES afd__device_attributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&afd__helper_name, 0); RTL_CONSTANT_OBJECT_ATTRIBUTES(&afd__device_name, 0);
int afd_create_helper_handle(HANDLE iocp_handle, int afd_create_device_handle(HANDLE iocp_handle,
HANDLE* afd_helper_handle_out) { HANDLE* afd_device_handle_out) {
HANDLE afd_helper_handle; HANDLE afd_device_handle;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
NTSTATUS status; NTSTATUS status;
/* By opening \Device\Afd without specifying any extended attributes, we'll /* By opening \Device\Afd without specifying any extended attributes, we'll
* get a handle that lets us talk to the AFD driver, but that doesn't have an * get a handle that lets us talk to the AFD driver, but that doesn't have an
* associated endpoint (so it's not a socket). */ * associated endpoint (so it's not a socket). */
status = NtCreateFile(&afd_helper_handle, status = NtCreateFile(&afd_device_handle,
SYNCHRONIZE, SYNCHRONIZE,
&afd__helper_attributes, &afd__device_attributes,
&iosb, &iosb,
NULL, NULL,
0, 0,
@ -353,22 +348,22 @@ int afd_create_helper_handle(HANDLE iocp_handle,
if (status != STATUS_SUCCESS) if (status != STATUS_SUCCESS)
return_set_error(-1, RtlNtStatusToDosError(status)); return_set_error(-1, RtlNtStatusToDosError(status));
if (CreateIoCompletionPort(afd_helper_handle, iocp_handle, 0, 0) == NULL) if (CreateIoCompletionPort(afd_device_handle, iocp_handle, 0, 0) == NULL)
goto error; goto error;
if (!SetFileCompletionNotificationModes(afd_helper_handle, if (!SetFileCompletionNotificationModes(afd_device_handle,
FILE_SKIP_SET_EVENT_ON_HANDLE)) FILE_SKIP_SET_EVENT_ON_HANDLE))
goto error; goto error;
*afd_helper_handle_out = afd_helper_handle; *afd_device_handle_out = afd_device_handle;
return 0; return 0;
error: error:
CloseHandle(afd_helper_handle); CloseHandle(afd_device_handle);
return_map_error(-1); return_map_error(-1);
} }
int afd_poll(HANDLE afd_helper_handle, int afd_poll(HANDLE afd_device_handle,
AFD_POLL_INFO* poll_info, AFD_POLL_INFO* poll_info,
IO_STATUS_BLOCK* io_status_block) { IO_STATUS_BLOCK* io_status_block) {
NTSTATUS status; NTSTATUS status;
@ -377,7 +372,7 @@ int afd_poll(HANDLE afd_helper_handle,
assert(io_status_block != NULL); assert(io_status_block != NULL);
io_status_block->Status = STATUS_PENDING; io_status_block->Status = STATUS_PENDING;
status = NtDeviceIoControlFile(afd_helper_handle, status = NtDeviceIoControlFile(afd_device_handle,
NULL, NULL,
NULL, NULL,
io_status_block, io_status_block,
@ -396,7 +391,7 @@ int afd_poll(HANDLE afd_helper_handle,
return_set_error(-1, RtlNtStatusToDosError(status)); return_set_error(-1, RtlNtStatusToDosError(status));
} }
int afd_cancel_poll(HANDLE afd_helper_handle, int afd_cancel_poll(HANDLE afd_device_handle,
IO_STATUS_BLOCK* io_status_block) { IO_STATUS_BLOCK* io_status_block) {
NTSTATUS cancel_status; NTSTATUS cancel_status;
IO_STATUS_BLOCK cancel_iosb; IO_STATUS_BLOCK cancel_iosb;
@ -407,7 +402,7 @@ int afd_cancel_poll(HANDLE afd_helper_handle,
return 0; return 0;
cancel_status = cancel_status =
NtCancelIoFileEx(afd_helper_handle, io_status_block, &cancel_iosb); NtCancelIoFileEx(afd_device_handle, io_status_block, &cancel_iosb);
/* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed /* NtCancelIoFileEx() may return STATUS_NOT_FOUND if the operation completed
* just before calling NtCancelIoFileEx(). This is not an error. */ * just before calling NtCancelIoFileEx(). This is not an error. */
@ -922,7 +917,7 @@ WEPOLL_INTERNAL void poll_group_delete(poll_group_t* poll_group);
WEPOLL_INTERNAL poll_group_t* poll_group_from_queue_node( WEPOLL_INTERNAL poll_group_t* poll_group_from_queue_node(
queue_node_t* queue_node); queue_node_t* queue_node);
WEPOLL_INTERNAL HANDLE WEPOLL_INTERNAL HANDLE
poll_group_get_afd_helper_handle(poll_group_t* poll_group); poll_group_get_afd_device_handle(poll_group_t* poll_group);
typedef struct queue_node { typedef struct queue_node {
queue_node_t* prev; queue_node_t* prev;
@ -948,12 +943,12 @@ WEPOLL_INTERNAL void queue_remove(queue_node_t* node);
WEPOLL_INTERNAL bool queue_is_empty(const queue_t* queue); WEPOLL_INTERNAL bool queue_is_empty(const queue_t* queue);
WEPOLL_INTERNAL bool queue_is_enqueued(const queue_node_t* node); WEPOLL_INTERNAL bool queue_is_enqueued(const queue_node_t* node);
static const size_t POLL_GROUP__MAX_GROUP_SIZE = 32; #define POLL_GROUP__MAX_GROUP_SIZE 32
typedef struct poll_group { typedef struct poll_group {
port_state_t* port_state; port_state_t* port_state;
queue_node_t queue_node; queue_node_t queue_node;
HANDLE afd_helper_handle; HANDLE afd_device_handle;
size_t group_size; size_t group_size;
} poll_group_t; } poll_group_t;
@ -970,7 +965,7 @@ static poll_group_t* poll_group__new(port_state_t* port_state) {
queue_node_init(&poll_group->queue_node); queue_node_init(&poll_group->queue_node);
poll_group->port_state = port_state; poll_group->port_state = port_state;
if (afd_create_helper_handle(iocp_handle, &poll_group->afd_helper_handle) < if (afd_create_device_handle(iocp_handle, &poll_group->afd_device_handle) <
0) { 0) {
free(poll_group); free(poll_group);
return NULL; return NULL;
@ -983,7 +978,7 @@ static poll_group_t* poll_group__new(port_state_t* port_state) {
void poll_group_delete(poll_group_t* poll_group) { void poll_group_delete(poll_group_t* poll_group) {
assert(poll_group->group_size == 0); assert(poll_group->group_size == 0);
CloseHandle(poll_group->afd_helper_handle); CloseHandle(poll_group->afd_device_handle);
queue_remove(&poll_group->queue_node); queue_remove(&poll_group->queue_node);
free(poll_group); free(poll_group);
} }
@ -992,8 +987,8 @@ poll_group_t* poll_group_from_queue_node(queue_node_t* queue_node) {
return container_of(queue_node, poll_group_t, queue_node); return container_of(queue_node, poll_group_t, queue_node);
} }
HANDLE poll_group_get_afd_helper_handle(poll_group_t* poll_group) { HANDLE poll_group_get_afd_device_handle(poll_group_t* poll_group) {
return poll_group->afd_helper_handle; return poll_group->afd_device_handle;
} }
poll_group_t* poll_group_acquire(port_state_t* port_state) { poll_group_t* poll_group_acquire(port_state_t* port_state) {
@ -1066,7 +1061,7 @@ typedef struct port_state {
size_t active_poll_count; size_t active_poll_count;
} port_state_t; } port_state_t;
static port_state_t* port__alloc(void) { static inline port_state_t* port__alloc(void) {
port_state_t* port_state = malloc(sizeof *port_state); port_state_t* port_state = malloc(sizeof *port_state);
if (port_state == NULL) if (port_state == NULL)
return_set_error(NULL, ERROR_NOT_ENOUGH_MEMORY); return_set_error(NULL, ERROR_NOT_ENOUGH_MEMORY);
@ -1074,12 +1069,12 @@ static port_state_t* port__alloc(void) {
return port_state; return port_state;
} }
static void port__free(port_state_t* port) { static inline void port__free(port_state_t* port) {
assert(port != NULL); assert(port != NULL);
free(port); free(port);
} }
static HANDLE port__create_iocp(void) { static inline HANDLE port__create_iocp(void) {
HANDLE iocp_handle = HANDLE iocp_handle =
CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (iocp_handle == NULL) if (iocp_handle == NULL)
@ -1119,7 +1114,7 @@ err1:
return NULL; return NULL;
} }
static int port__close_iocp(port_state_t* port_state) { static inline int port__close_iocp(port_state_t* port_state) {
HANDLE iocp_handle = port_state->iocp_handle; HANDLE iocp_handle = port_state->iocp_handle;
port_state->iocp_handle = NULL; port_state->iocp_handle = NULL;
@ -1188,15 +1183,15 @@ static int port__update_events(port_state_t* port_state) {
return 0; return 0;
} }
static void port__update_events_if_polling(port_state_t* port_state) { static inline void port__update_events_if_polling(port_state_t* port_state) {
if (port_state->active_poll_count > 0) if (port_state->active_poll_count > 0)
port__update_events(port_state); port__update_events(port_state);
} }
static int port__feed_events(port_state_t* port_state, static inline int port__feed_events(port_state_t* port_state,
struct epoll_event* epoll_events, struct epoll_event* epoll_events,
OVERLAPPED_ENTRY* iocp_events, OVERLAPPED_ENTRY* iocp_events,
DWORD iocp_event_count) { DWORD iocp_event_count) {
int epoll_event_count = 0; int epoll_event_count = 0;
DWORD i; DWORD i;
@ -1211,11 +1206,11 @@ static int port__feed_events(port_state_t* port_state,
return epoll_event_count; return epoll_event_count;
} }
static int port__poll(port_state_t* port_state, static inline int port__poll(port_state_t* port_state,
struct epoll_event* epoll_events, struct epoll_event* epoll_events,
OVERLAPPED_ENTRY* iocp_events, OVERLAPPED_ENTRY* iocp_events,
DWORD maxevents, DWORD maxevents,
DWORD timeout) { DWORD timeout) {
DWORD completion_count; DWORD completion_count;
if (port__update_events(port_state) < 0) if (port__update_events(port_state) < 0)
@ -1321,9 +1316,9 @@ int port_wait(port_state_t* port_state,
return -1; return -1;
} }
static int port__ctl_add(port_state_t* port_state, static inline int port__ctl_add(port_state_t* port_state,
SOCKET sock, SOCKET sock,
struct epoll_event* ev) { struct epoll_event* ev) {
sock_state_t* sock_state = sock_new(port_state, sock); sock_state_t* sock_state = sock_new(port_state, sock);
if (sock_state == NULL) if (sock_state == NULL)
return -1; return -1;
@ -1338,9 +1333,9 @@ static int port__ctl_add(port_state_t* port_state,
return 0; return 0;
} }
static int port__ctl_mod(port_state_t* port_state, static inline int port__ctl_mod(port_state_t* port_state,
SOCKET sock, SOCKET sock,
struct epoll_event* ev) { struct epoll_event* ev) {
sock_state_t* sock_state = port_find_socket(port_state, sock); sock_state_t* sock_state = port_find_socket(port_state, sock);
if (sock_state == NULL) if (sock_state == NULL)
return -1; return -1;
@ -1353,7 +1348,7 @@ static int port__ctl_mod(port_state_t* port_state,
return 0; return 0;
} }
static int port__ctl_del(port_state_t* port_state, SOCKET sock) { static inline int port__ctl_del(port_state_t* port_state, SOCKET sock) {
sock_state_t* sock_state = port_find_socket(port_state, sock); sock_state_t* sock_state = port_find_socket(port_state, sock);
if (sock_state == NULL) if (sock_state == NULL)
return -1; return -1;
@ -1363,10 +1358,10 @@ static int port__ctl_del(port_state_t* port_state, SOCKET sock) {
return 0; return 0;
} }
static int port__ctl_op(port_state_t* port_state, static inline int port__ctl_op(port_state_t* port_state,
int op, int op,
SOCKET sock, SOCKET sock,
struct epoll_event* ev) { struct epoll_event* ev) {
switch (op) { switch (op) {
case EPOLL_CTL_ADD: case EPOLL_CTL_ADD:
return port__ctl_add(port_state, sock, ev); return port__ctl_add(port_state, sock, ev);
@ -1522,11 +1517,11 @@ bool queue_is_enqueued(const queue_node_t* node) {
return node->prev != node; return node->prev != node;
} }
static const long REFLOCK__REF = (long) 0x00000001; #define REFLOCK__REF ((long) 0x00000001UL)
static const long REFLOCK__REF_MASK = (long) 0x0fffffff; #define REFLOCK__REF_MASK ((long) 0x0fffffffUL)
static const long REFLOCK__DESTROY = (long) 0x10000000; #define REFLOCK__DESTROY ((long) 0x10000000UL)
static const long REFLOCK__DESTROY_MASK = (long) 0xf0000000; #define REFLOCK__DESTROY_MASK ((long) 0xf0000000UL)
static const long REFLOCK__POISON = (long) 0x300dead0; #define REFLOCK__POISON ((long) 0x300dead0UL)
static HANDLE reflock__keyed_event = NULL; static HANDLE reflock__keyed_event = NULL;
@ -1589,9 +1584,9 @@ void reflock_unref_and_destroy(reflock_t* reflock) {
assert(state == REFLOCK__DESTROY); assert(state == REFLOCK__DESTROY);
} }
static const uint32_t SOCK__KNOWN_EPOLL_EVENTS = #define SOCK__KNOWN_EPOLL_EVENTS \
EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDNORM | (EPOLLIN | EPOLLPRI | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLRDNORM | \
EPOLLRDBAND | EPOLLWRNORM | EPOLLWRBAND | EPOLLMSG | EPOLLRDHUP; EPOLLRDBAND | EPOLLWRNORM | EPOLLWRBAND | EPOLLMSG | EPOLLRDHUP)
typedef enum sock__poll_status { typedef enum sock__poll_status {
SOCK__POLL_IDLE = 0, SOCK__POLL_IDLE = 0,
@ -1621,13 +1616,14 @@ static inline sock_state_t* sock__alloc(void) {
} }
static inline void sock__free(sock_state_t* sock_state) { static inline void sock__free(sock_state_t* sock_state) {
assert(sock_state != NULL);
free(sock_state); free(sock_state);
} }
static int sock__cancel_poll(sock_state_t* sock_state) { static inline int sock__cancel_poll(sock_state_t* sock_state) {
assert(sock_state->poll_status == SOCK__POLL_PENDING); assert(sock_state->poll_status == SOCK__POLL_PENDING);
if (afd_cancel_poll(poll_group_get_afd_helper_handle(sock_state->poll_group), if (afd_cancel_poll(poll_group_get_afd_device_handle(sock_state->poll_group),
&sock_state->io_status_block) < 0) &sock_state->io_status_block) < 0)
return -1; return -1;
@ -1719,7 +1715,7 @@ int sock_set_event(port_state_t* port_state,
const struct epoll_event* ev) { const struct epoll_event* ev) {
/* EPOLLERR and EPOLLHUP are always reported, even when not requested by the /* EPOLLERR and EPOLLHUP are always reported, even when not requested by the
* caller. However they are disabled after a event has been reported for a * caller. However they are disabled after a event has been reported for a
* socket for which the EPOLLONESHOT flag as set. */ * socket for which the EPOLLONESHOT flag was set. */
uint32_t events = ev->events | EPOLLERR | EPOLLHUP; uint32_t events = ev->events | EPOLLERR | EPOLLHUP;
sock_state->user_events = events; sock_state->user_events = events;
@ -1806,7 +1802,7 @@ int sock_update(port_state_t* port_state, sock_state_t* sock_state) {
sock_state->poll_info.Handles[0].Events = sock_state->poll_info.Handles[0].Events =
sock__epoll_events_to_afd_events(sock_state->user_events); sock__epoll_events_to_afd_events(sock_state->user_events);
if (afd_poll(poll_group_get_afd_helper_handle(sock_state->poll_group), if (afd_poll(poll_group_get_afd_device_handle(sock_state->poll_group),
&sock_state->poll_info, &sock_state->poll_info,
&sock_state->io_status_block) < 0) { &sock_state->io_status_block) < 0) {
switch (GetLastError()) { switch (GetLastError()) {
@ -2241,14 +2237,13 @@ SOCKET ws_get_base_socket(SOCKET socket) {
* never intercept the `SIO_BASE_HANDLE` ioctl [1], Komodia based LSPs do * never intercept the `SIO_BASE_HANDLE` ioctl [1], Komodia based LSPs do
* so anyway, breaking it, with the apparent intention of preventing LSP * so anyway, breaking it, with the apparent intention of preventing LSP
* bypass [2]. Fortunately they don't handle `SIO_BSP_HANDLE_POLL`, which * bypass [2]. Fortunately they don't handle `SIO_BSP_HANDLE_POLL`, which
* we can use to obtain the socket associated with the next protocol chain * will at least let us obtain the socket associated with the next winsock
* entry. If this succeeds, loop around and call `SIO_BASE_HANDLE` again * protocol chain entry. If this succeeds, loop around and call
* with the retrieved BSP socket to be sure that we actually got all the * `SIO_BASE_HANDLE` again with the returned BSP socket, to make sure that
* way to the base. * we unwrap all layers and retrieve the actual base socket.
* [1] https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls * [1] https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls
* [2] https://www.komodia.com/newwiki/index.php?title=Komodia%27s_Redirector_bug_fixes#Version_2.2.2.6 * [2] https://www.komodia.com/newwiki/index.php?title=Komodia%27s_Redirector_bug_fixes#Version_2.2.2.6
*/ */
base_socket = ws__ioctl_get_bsp_socket(socket, SIO_BSP_HANDLE_POLL); base_socket = ws__ioctl_get_bsp_socket(socket, SIO_BSP_HANDLE_POLL);
if (base_socket != INVALID_SOCKET && base_socket != socket) if (base_socket != INVALID_SOCKET && base_socket != socket)
socket = base_socket; socket = base_socket;

View File

@ -32,7 +32,9 @@
#ifndef WEPOLL_H_ #ifndef WEPOLL_H_
#define WEPOLL_H_ #define WEPOLL_H_
#ifndef WEPOLL_EXPORT
#define WEPOLL_EXPORT #define WEPOLL_EXPORT
#endif
#include <stdint.h> #include <stdint.h>