version 1.5.2

This commit is contained in:
Bert Belder 2018-07-26 03:46:57 +02:00
commit 006dc04624
No known key found for this signature in database
GPG Key ID: 7A77887B2E2ED461

230
wepoll.c
View File

@ -126,7 +126,7 @@ WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
#pragma clang diagnostic ignored "-Wreserved-id-macro" #pragma clang diagnostic ignored "-Wreserved-id-macro"
#endif #endif
#if defined(_WIN32_WINNT) #ifdef _WIN32_WINNT
#undef _WIN32_WINNT #undef _WIN32_WINNT
#endif #endif
@ -170,10 +170,7 @@ typedef NTSTATUS* PNTSTATUS;
#endif #endif
typedef struct _IO_STATUS_BLOCK { typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status; NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information; ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
@ -187,6 +184,9 @@ typedef struct _LSA_UNICODE_STRING {
PWSTR Buffer; PWSTR Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING; } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
#define RTL_CONSTANT_STRING(s) \
{ sizeof(s) - sizeof((s)[0]), sizeof(s), s }
typedef struct _OBJECT_ATTRIBUTES { typedef struct _OBJECT_ATTRIBUTES {
ULONG Length; ULONG Length;
HANDLE RootDirectory; HANDLE RootDirectory;
@ -196,7 +196,29 @@ typedef struct _OBJECT_ATTRIBUTES {
PVOID SecurityQualityOfService; PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
#define NTDLL_IMPORT_LIST(X) \ #define RTL_CONSTANT_OBJECT_ATTRIBUTES(ObjectName, Attributes) \
{ sizeof(OBJECT_ATTRIBUTES), NULL, ObjectName, Attributes, NULL, NULL }
#ifndef FILE_OPEN
#define FILE_OPEN 0x00000001UL
#endif
#define NT_NTDLL_IMPORT_LIST(X) \
X(NTSTATUS, \
NTAPI, \
NtCreateFile, \
(PHANDLE FileHandle, \
ACCESS_MASK DesiredAccess, \
POBJECT_ATTRIBUTES ObjectAttributes, \
PIO_STATUS_BLOCK IoStatusBlock, \
PLARGE_INTEGER AllocationSize, \
ULONG FileAttributes, \
ULONG ShareAccess, \
ULONG CreateDisposition, \
ULONG CreateOptions, \
PVOID EaBuffer, \
ULONG EaLength)) \
\
X(NTSTATUS, \ X(NTSTATUS, \
NTAPI, \ NTAPI, \
NtDeviceIoControlFile, \ NtDeviceIoControlFile, \
@ -233,7 +255,7 @@ typedef struct _OBJECT_ATTRIBUTES {
#define X(return_type, attributes, name, parameters) \ #define X(return_type, attributes, name, parameters) \
WEPOLL_INTERNAL_VAR return_type(attributes* name) parameters; WEPOLL_INTERNAL_VAR return_type(attributes* name) parameters;
NTDLL_IMPORT_LIST(X) NT_NTDLL_IMPORT_LIST(X)
#undef X #undef X
#include <assert.h> #include <assert.h>
@ -282,12 +304,10 @@ 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_global_init(void); WEPOLL_INTERNAL int afd_create_helper_handle(HANDLE iocp,
HANDLE* afd_helper_handle_out);
WEPOLL_INTERNAL int afd_create_driver_socket(HANDLE iocp, WEPOLL_INTERNAL int afd_poll(HANDLE afd_helper_handle,
SOCKET* driver_socket_out);
WEPOLL_INTERNAL int afd_poll(SOCKET driver_socket,
AFD_POLL_INFO* poll_info, AFD_POLL_INFO* poll_info,
OVERLAPPED* overlapped); OVERLAPPED* overlapped);
@ -308,127 +328,54 @@ WEPOLL_INTERNAL void err_set_win_error(DWORD error);
WEPOLL_INTERNAL int err_check_handle(HANDLE handle); WEPOLL_INTERNAL int err_check_handle(HANDLE handle);
WEPOLL_INTERNAL int ws_global_init(void); WEPOLL_INTERNAL int ws_global_init(void);
WEPOLL_INTERNAL SOCKET ws_get_base_socket(SOCKET socket); WEPOLL_INTERNAL SOCKET ws_get_base_socket(SOCKET socket);
WEPOLL_INTERNAL int ws_get_protocol_catalog(WSAPROTOCOL_INFOW** infos_out,
size_t* infos_count_out);
#define IOCTL_AFD_POLL 0x00012024 #define IOCTL_AFD_POLL 0x00012024
/* clang-format off */ static UNICODE_STRING afd__helper_name =
static const GUID AFD__PROVIDER_GUID_LIST[] = { RTL_CONSTANT_STRING(L"\\Device\\Afd\\Wepoll");
/* MSAFD Tcpip [TCP+UDP+RAW / IP] */
{0xe70f1aa0, 0xab8b, 0x11cf,
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
/* MSAFD Tcpip [TCP+UDP+RAW / IPv6] */
{0xf9eab0c0, 0x26d4, 0x11d0,
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
/* MSAFD RfComm [Bluetooth] */
{0x9fc48064, 0x7298, 0x43e4,
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
/* MSAFD Irda [IrDA] */
{0x3972523d, 0x2af1, 0x11d1,
{0xb6, 0x55, 0x00, 0x80, 0x5f, 0x36, 0x42, 0xcc}}};
/* clang-format on */
static const int AFD__ANY_PROTOCOL = -1; static OBJECT_ATTRIBUTES afd__helper_attributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&afd__helper_name, 0);
/* This protocol info record is used by afd_create_driver_socket() to create int afd_create_helper_handle(HANDLE iocp, HANDLE* afd_helper_handle_out) {
* sockets that can be used as the first argument to afd_poll(). It is HANDLE afd_helper_handle;
* populated on startup by afd_global_init(). */ IO_STATUS_BLOCK iosb;
static WSAPROTOCOL_INFOW afd__driver_socket_protocol_info; NTSTATUS status;
static const WSAPROTOCOL_INFOW* afd__find_protocol_info( /* By opening \Device\Afd without specifying any extended attributes, we'll
const WSAPROTOCOL_INFOW* infos, size_t infos_count, int protocol_id) { * get a handle that lets us talk to the AFD driver, but that doesn't have an
size_t i, j; * associated endpoint (so it's not a socket). */
status = NtCreateFile(&afd_helper_handle,
for (i = 0; i < infos_count; i++) { SYNCHRONIZE,
const WSAPROTOCOL_INFOW* info = &infos[i]; &afd__helper_attributes,
&iosb,
/* Apply protocol id filter. */ NULL,
if (protocol_id != AFD__ANY_PROTOCOL && protocol_id != info->iProtocol)
continue;
/* Filter out non-MSAFD protocols. */
for (j = 0; j < array_count(AFD__PROVIDER_GUID_LIST); j++) {
if (memcmp(&info->ProviderId,
&AFD__PROVIDER_GUID_LIST[j],
sizeof info->ProviderId) == 0)
return info;
}
}
return NULL; /* Not found. */
}
int afd_global_init(void) {
WSAPROTOCOL_INFOW* infos;
size_t infos_count;
const WSAPROTOCOL_INFOW* afd_info;
/* Load the winsock catalog. */
if (ws_get_protocol_catalog(&infos, &infos_count) < 0)
return -1;
/* Find a WSAPROTOCOL_INFOW structure that we can use to create an MSAFD
* socket. Preferentially we pick a UDP socket, otherwise try TCP or any
* other type. */
for (;;) {
afd_info = afd__find_protocol_info(infos, infos_count, IPPROTO_UDP);
if (afd_info != NULL)
break;
afd_info = afd__find_protocol_info(infos, infos_count, IPPROTO_TCP);
if (afd_info != NULL)
break;
afd_info = afd__find_protocol_info(infos, infos_count, AFD__ANY_PROTOCOL);
if (afd_info != NULL)
break;
free(infos);
return_set_error(-1, WSAENETDOWN); /* No suitable protocol found. */
}
/* Copy found protocol information from the catalog to a static buffer. */
afd__driver_socket_protocol_info = *afd_info;
free(infos);
return 0;
}
int afd_create_driver_socket(HANDLE iocp, SOCKET* driver_socket_out) {
SOCKET socket;
socket = WSASocketW(afd__driver_socket_protocol_info.iAddressFamily,
afd__driver_socket_protocol_info.iSocketType,
afd__driver_socket_protocol_info.iProtocol,
&afd__driver_socket_protocol_info,
0, 0,
WSA_FLAG_OVERLAPPED); FILE_SHARE_READ | FILE_SHARE_WRITE,
if (socket == INVALID_SOCKET) FILE_OPEN,
return_map_error(-1); 0,
NULL,
0);
if (status != STATUS_SUCCESS)
return_set_error(-1, RtlNtStatusToDosError(status));
/* TODO: use WSA_FLAG_NOINHERIT on Windows versions that support it. */ if (CreateIoCompletionPort(afd_helper_handle, iocp, 0, 0) == NULL)
if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
goto error; goto error;
if (CreateIoCompletionPort((HANDLE) socket, iocp, 0, 0) == NULL) if (!SetFileCompletionNotificationModes(afd_helper_handle,
goto error;
if (!SetFileCompletionNotificationModes((HANDLE) socket,
FILE_SKIP_SET_EVENT_ON_HANDLE)) FILE_SKIP_SET_EVENT_ON_HANDLE))
goto error; goto error;
*driver_socket_out = socket; *afd_helper_handle_out = afd_helper_handle;
return 0; return 0;
error: error:
closesocket(socket); CloseHandle(afd_helper_handle);
return_map_error(-1); return_map_error(-1);
} }
int afd_poll(SOCKET driver_socket, int afd_poll(HANDLE afd_helper_handle,
AFD_POLL_INFO* poll_info, AFD_POLL_INFO* poll_info,
OVERLAPPED* overlapped) { OVERLAPPED* overlapped) {
IO_STATUS_BLOCK* iosb; IO_STATUS_BLOCK* iosb;
@ -452,7 +399,7 @@ int afd_poll(SOCKET driver_socket,
} }
iosb->Status = STATUS_PENDING; iosb->Status = STATUS_PENDING;
status = NtDeviceIoControlFile((HANDLE) driver_socket, status = NtDeviceIoControlFile(afd_helper_handle,
event, event,
NULL, NULL,
apc_context, apc_context,
@ -513,7 +460,8 @@ 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 SOCKET poll_group_get_socket(poll_group_t* poll_group); WEPOLL_INTERNAL HANDLE
poll_group_get_afd_helper_handle(poll_group_t* poll_group);
/* N.b.: the tree functions do not set errno or LastError when they fail. Each /* N.b.: the tree functions do not set errno or LastError when they fail. Each
* of the API functions has at most one failure mode. It is up to the caller to * of the API functions has at most one failure mode. It is up to the caller to
@ -961,7 +909,7 @@ static BOOL CALLBACK init__once_callback(INIT_ONCE* once,
unused_var(context); unused_var(context);
/* N.b. that initialization order matters here. */ /* N.b. that initialization order matters here. */
if (ws_global_init() < 0 || nt_global_init() < 0 || afd_global_init() < 0 || if (ws_global_init() < 0 || nt_global_init() < 0 ||
reflock_global_init() < 0 || epoll_global_init() < 0) reflock_global_init() < 0 || epoll_global_init() < 0)
return FALSE; return FALSE;
@ -979,7 +927,7 @@ int init(void) {
#define X(return_type, attributes, name, parameters) \ #define X(return_type, attributes, name, parameters) \
WEPOLL_INTERNAL return_type(attributes* name) parameters = NULL; WEPOLL_INTERNAL return_type(attributes* name) parameters = NULL;
NTDLL_IMPORT_LIST(X) NT_NTDLL_IMPORT_LIST(X)
#undef X #undef X
int nt_global_init(void) { int nt_global_init(void) {
@ -993,7 +941,7 @@ int nt_global_init(void) {
name = (return_type(attributes*) parameters) GetProcAddress(ntdll, #name); \ name = (return_type(attributes*) parameters) GetProcAddress(ntdll, #name); \
if (name == NULL) \ if (name == NULL) \
return -1; return -1;
NTDLL_IMPORT_LIST(X) NT_NTDLL_IMPORT_LIST(X)
#undef X #undef X
return 0; return 0;
@ -1006,7 +954,7 @@ static const size_t 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;
SOCKET socket; HANDLE afd_helper_handle;
size_t group_size; size_t group_size;
} poll_group_t; } poll_group_t;
@ -1020,7 +968,8 @@ 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_driver_socket(port_state->iocp, &poll_group->socket) < 0) { if (afd_create_helper_handle(port_state->iocp,
&poll_group->afd_helper_handle) < 0) {
free(poll_group); free(poll_group);
return NULL; return NULL;
} }
@ -1032,7 +981,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);
closesocket(poll_group->socket); CloseHandle(poll_group->afd_helper_handle);
queue_remove(&poll_group->queue_node); queue_remove(&poll_group->queue_node);
free(poll_group); free(poll_group);
} }
@ -1041,8 +990,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);
} }
SOCKET poll_group_get_socket(poll_group_t* poll_group) { HANDLE poll_group_get_afd_helper_handle(poll_group_t* poll_group) {
return poll_group->socket; return poll_group->afd_helper_handle;
} }
poll_group_t* poll_group_acquire(port_state_t* port_state) { poll_group_t* poll_group_acquire(port_state_t* port_state) {
@ -1621,13 +1570,13 @@ static inline void sock__free(sock_state_t* sock_state) {
} }
static int sock__cancel_poll(sock_state_t* sock_state) { static int sock__cancel_poll(sock_state_t* sock_state) {
HANDLE driver_handle = HANDLE afd_helper_handle =
(HANDLE)(uintptr_t) poll_group_get_socket(sock_state->poll_group); poll_group_get_afd_helper_handle(sock_state->poll_group);
assert(sock_state->poll_status == SOCK__POLL_PENDING); assert(sock_state->poll_status == SOCK__POLL_PENDING);
/* CancelIoEx() may fail with ERROR_NOT_FOUND if the overlapped operation has /* CancelIoEx() may fail with ERROR_NOT_FOUND if the overlapped operation has
* already completed. This is not a problem and we proceed normally. */ * already completed. This is not a problem and we proceed normally. */
if (!CancelIoEx(driver_handle, &sock_state->overlapped) && if (!CancelIoEx(afd_helper_handle, &sock_state->overlapped) &&
GetLastError() != ERROR_NOT_FOUND) GetLastError() != ERROR_NOT_FOUND)
return_map_error(-1); return_map_error(-1);
@ -1806,7 +1755,7 @@ int sock_update(port_state_t* port_state, sock_state_t* sock_state) {
memset(&sock_state->overlapped, 0, sizeof sock_state->overlapped); memset(&sock_state->overlapped, 0, sizeof sock_state->overlapped);
if (afd_poll(poll_group_get_socket(sock_state->poll_group), if (afd_poll(poll_group_get_afd_helper_handle(sock_state->poll_group),
&sock_state->poll_info, &sock_state->poll_info,
&sock_state->overlapped) < 0) { &sock_state->overlapped) < 0) {
switch (GetLastError()) { switch (GetLastError()) {
@ -2191,8 +2140,6 @@ tree_node_t* tree_root(const tree_t* tree) {
#define SIO_BASE_HANDLE 0x48000022 #define SIO_BASE_HANDLE 0x48000022
#endif #endif
#define WS__INITIAL_CATALOG_BUFFER_SIZE 0x4000 /* 16kb. */
int ws_global_init(void) { int ws_global_init(void) {
int r; int r;
WSADATA wsa_data; WSADATA wsa_data;
@ -2221,30 +2168,3 @@ SOCKET ws_get_base_socket(SOCKET socket) {
return base_socket; return base_socket;
} }
/* Retrieves a copy of the winsock catalog.
* The infos pointer must be released by the caller with free(). */
int ws_get_protocol_catalog(WSAPROTOCOL_INFOW** infos_out,
size_t* infos_count_out) {
DWORD buffer_size = WS__INITIAL_CATALOG_BUFFER_SIZE;
int count;
WSAPROTOCOL_INFOW* infos;
retry:
infos = malloc(buffer_size);
if (infos == NULL)
return_set_error(-1, ERROR_NOT_ENOUGH_MEMORY);
count = WSAEnumProtocolsW(NULL, infos, &buffer_size);
if (count == SOCKET_ERROR) {
free(infos);
if (WSAGetLastError() == WSAENOBUFS)
goto retry; /* Try again with bigger buffer size. */
else
return_map_error(-1);
}
*infos_out = infos;
*infos_count_out = (size_t) count;
return 0;
}