WIP
This commit is contained in:
parent
b45fca6328
commit
c3f7e36acb
@ -1 +1,36 @@
|
|||||||
|
|
||||||
|
#ifndef WPOLL_H_
|
||||||
|
#define WPOLL_H_
|
||||||
|
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define WPOLL_CTL_ADD 0
|
||||||
|
#define WPOLL_CTL_MOD 1
|
||||||
|
#define WPOLL_CTL_DEL 2
|
||||||
|
|
||||||
|
typedef void* wpoll_t;
|
||||||
|
|
||||||
|
typedef union wpoll_data {
|
||||||
|
void *ptr;
|
||||||
|
int fd;
|
||||||
|
uint32_t u32;
|
||||||
|
uint64_t u64;
|
||||||
|
} wpoll_data_t;
|
||||||
|
|
||||||
|
struct wpoll_event {
|
||||||
|
uint32_t events; /* Epoll events */
|
||||||
|
wpoll_data_t data; /* User data variable */
|
||||||
|
};
|
||||||
|
|
||||||
|
wpoll_t wpoll_create();
|
||||||
|
|
||||||
|
int wpoll_close();
|
||||||
|
|
||||||
|
int wpoll_ctl(wpoll_t wpoll_hnd, int op, SOCKET sock, struct wpoll_event* event);
|
||||||
|
|
||||||
|
int epoll_wait(wpoll_t wpoll_hnd, struct wpoll_event* events, int maxevents, int timeout);
|
||||||
|
|
||||||
|
#endif /* WPOLL_H_ */
|
||||||
228
src/msafd.c
228
src/msafd.c
@ -1 +1,229 @@
|
|||||||
|
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/msafd.h
70
src/msafd.h
@ -1 +1,71 @@
|
|||||||
|
|
||||||
|
#ifndef WPOLL_MSAFD_H_
|
||||||
|
#define WPOLL_MSAFD_H_
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "ntapi.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define AFD_NO_FAST_IO 0x00000001
|
||||||
|
#define AFD_OVERLAPPED 0x00000002
|
||||||
|
#define AFD_IMMEDIATE 0x00000004
|
||||||
|
|
||||||
|
#define AFD_POLL_RECEIVE_BIT 0
|
||||||
|
#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
|
||||||
|
#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
|
||||||
|
#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
|
||||||
|
#define AFD_POLL_SEND_BIT 2
|
||||||
|
#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
|
||||||
|
#define AFD_POLL_DISCONNECT_BIT 3
|
||||||
|
#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
|
||||||
|
#define AFD_POLL_ABORT_BIT 4
|
||||||
|
#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
|
||||||
|
#define AFD_POLL_LOCAL_CLOSE_BIT 5
|
||||||
|
#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
|
||||||
|
#define AFD_POLL_CONNECT_BIT 6
|
||||||
|
#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
|
||||||
|
#define AFD_POLL_ACCEPT_BIT 7
|
||||||
|
#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
|
||||||
|
#define AFD_POLL_CONNECT_FAIL_BIT 8
|
||||||
|
#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
|
||||||
|
#define AFD_POLL_QOS_BIT 9
|
||||||
|
#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
|
||||||
|
#define AFD_POLL_GROUP_QOS_BIT 10
|
||||||
|
#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
|
||||||
|
|
||||||
|
#define AFD_NUM_POLL_EVENTS 11
|
||||||
|
#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
|
||||||
|
|
||||||
|
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
|
||||||
|
|
||||||
|
#define _AFD_CONTROL_CODE(operation, method) \
|
||||||
|
((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
|
||||||
|
|
||||||
|
#define AFD_POLL 9
|
||||||
|
|
||||||
|
#define IOCTL_AFD_POLL \
|
||||||
|
_AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
|
||||||
|
|
||||||
|
typedef struct _AFD_POLL_HANDLE_INFO {
|
||||||
|
HANDLE Handle;
|
||||||
|
ULONG Events;
|
||||||
|
NTSTATUS Status;
|
||||||
|
} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
|
||||||
|
|
||||||
|
typedef struct _AFD_POLL_INFO {
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
ULONG NumberOfHandles;
|
||||||
|
ULONG Exclusive;
|
||||||
|
AFD_POLL_HANDLE_INFO Handles[1];
|
||||||
|
} AFD_POLL_INFO, *PAFD_POLL_INFO;
|
||||||
|
|
||||||
|
static const GUID AFD_PROVIDER_IDS[] = {
|
||||||
|
{0xe70f1aa0, 0xab8b, 0x11cf,
|
||||||
|
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
|
||||||
|
{0xf9eab0c0, 0x26d4, 0x11d0,
|
||||||
|
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
|
||||||
|
{0x9fc48064, 0x7298, 0x43e4,
|
||||||
|
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* WPOLL_MSAFD_H_ */
|
||||||
0
src/ntapi.c
Normal file
0
src/ntapi.c
Normal file
4088
src/ntapi.h
Normal file
4088
src/ntapi.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +1,10 @@
|
|||||||
|
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <WS2tcpip.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <wpoll.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -394,7 +394,7 @@ attr struct type *name##_RB_MINMAX(struct name *, int); \
|
|||||||
#define RB_GENERATE(name, type, field, cmp) \
|
#define RB_GENERATE(name, type, field, cmp) \
|
||||||
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
||||||
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
||||||
RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
|
RB_GENERATE_INTERNAL(name, type, field, cmp, static)
|
||||||
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
||||||
attr void \
|
attr void \
|
||||||
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
||||||
|
|||||||
271
src/wpoll.c
271
src/wpoll.c
@ -1 +1,272 @@
|
|||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <wpoll.h>
|
||||||
|
#include "msafd.h"
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
#define ARRAY_COUNT(a) (sizeof(a) / (sizeof((a)[0])))
|
||||||
|
#define WPOLL_KEY 0xE9011
|
||||||
|
|
||||||
|
typedef struct wpoll_op_s wpoll_op_t;
|
||||||
|
|
||||||
|
/* State associated with a wpoll handle. */
|
||||||
|
typedef struct wpoll_handle_state_s {
|
||||||
|
HANDLE iocp;
|
||||||
|
SOCKET peer_sockets[ARRAY_COUNT(AFD_PROVIDER_IDS)];
|
||||||
|
size_t pending_ops_count;
|
||||||
|
RB_HEAD(wpoll_socket_state_tree, wpoll_socket_state_s) socket_state_tree;
|
||||||
|
} wpoll_handle_state_t;
|
||||||
|
|
||||||
|
/* State associated with a socket that is registered to the wpoll port. */
|
||||||
|
typedef struct wpoll_socket_state_s {
|
||||||
|
SOCKET sock;
|
||||||
|
SOCKET base_sock;
|
||||||
|
SOCKET peer_sock;
|
||||||
|
int op_generation;
|
||||||
|
int submitted_events;
|
||||||
|
int events;
|
||||||
|
uint64_t user_data;
|
||||||
|
wpoll_op_t* free_op;
|
||||||
|
RB_ENTRY(wpoll_socket_state_s) tree_entry;
|
||||||
|
} wpoll_socket_state_t;
|
||||||
|
|
||||||
|
/* State associated with a AFD_POLL request. */
|
||||||
|
struct wpoll_op_s {
|
||||||
|
IO_STATUS_BLOCK status;
|
||||||
|
AFD_POLL_INFO poll_info;
|
||||||
|
int generation;
|
||||||
|
struct wpoll_socket_state* socket_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int wpoll_socket_compare(wpoll_socket_state_t* a, wpoll_socket_state_t* b) {
|
||||||
|
return a->sock - b->sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RB_GENERATE_STATIC(wpoll_socket_state_tree, wpoll_socket_state_s, tree_entry, wpoll_socket_compare)
|
||||||
|
|
||||||
|
|
||||||
|
wpoll_t wpoll_create() {
|
||||||
|
HANDLE iocp;
|
||||||
|
|
||||||
|
wpoll_handle_state_t* state = malloc(sizeof *state);
|
||||||
|
if (state == NULL) {
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
if (iocp == INVALID_HANDLE_VALUE) {
|
||||||
|
free(state);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->iocp = iocp;
|
||||||
|
memset(&state->peer_sockets, 0, sizeof state->peer_sockets);
|
||||||
|
state->pending_ops_count = 0;
|
||||||
|
RB_INIT(&state->socket_state_tree);
|
||||||
|
|
||||||
|
return (wpoll_t*) state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SOCKET wpoll__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,
|
||||||
|
WPOLL_KEY,
|
||||||
|
0) == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
|
||||||
|
error:
|
||||||
|
closesocket(sock);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SOCKET wpoll__get_peer_socket(wpoll_handle_state_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 = wpoll__create_peer_socket(port_data->iocp, protocol_info);
|
||||||
|
port_data->peer_sockets[index] = peer_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
return peer_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpoll__submit_poll_op(wpoll_handle_state_t* port_data, wpoll_socket_state_t* sock_data) {
|
||||||
|
wpoll_op_t* op = sock_data->free_op;
|
||||||
|
|
||||||
|
assert(op != NULL);
|
||||||
|
|
||||||
|
op->generation = ++sock_data->op_generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpoll_ctl(wpoll_t wpoll_hnd, int op, SOCKET sock,
|
||||||
|
struct wpoll_event* event) {
|
||||||
|
wpoll_handle_state_t* port_data;
|
||||||
|
|
||||||
|
port_data = (wpoll_handle_state_t*) wpoll_hnd;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case WPOLL_CTL_ADD: {
|
||||||
|
wpoll_socket_state_t* sock_data;
|
||||||
|
wpoll_op_t* op;
|
||||||
|
SOCKET peer_sock;
|
||||||
|
WSAPROTOCOL_INFOW protocol_info;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* Obtain protocol information about the socket. */
|
||||||
|
len = sizeof protocol_info;
|
||||||
|
if (getsockopt(sock,
|
||||||
|
SOL_SOCKET,
|
||||||
|
SO_PROTOCOL_INFOW,
|
||||||
|
(char*) &protocol_info,
|
||||||
|
&len) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
peer_sock = wpoll__get_peer_socket(port_data, &protocol_info);
|
||||||
|
if (peer_sock == INVALID_SOCKET) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_data = malloc(sizeof *sock_data);
|
||||||
|
if (sock_data == NULL) {
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
op = malloc(sizeof *op);
|
||||||
|
if (op == NULL) {
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
free(sock_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_data->sock = sock;
|
||||||
|
sock_data->op_generation = 0;
|
||||||
|
sock_data->submitted_events = 0;
|
||||||
|
sock_data->events = event->events;
|
||||||
|
sock_data->user_data = event->data.u64;
|
||||||
|
sock_data->peer_sock = peer_sock;
|
||||||
|
sock_data->free_op = op;
|
||||||
|
|
||||||
|
if (RB_INSERT(wpoll_socket_state_tree, &port_data->socket_state_tree, sock_data) != NULL) {
|
||||||
|
/* Poll entry was already there. */
|
||||||
|
free(sock_data);
|
||||||
|
free(op);
|
||||||
|
SetLastError(ERROR_ALREADY_EXISTS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add to attention list
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WPOLL_CTL_MOD: {
|
||||||
|
wpoll_socket_state_t lookup;
|
||||||
|
wpoll_socket_state_t* sock_data;
|
||||||
|
|
||||||
|
lookup.sock = sock;
|
||||||
|
sock_data = RB_FIND(wpoll_socket_state_tree, &port_data->socket_state_tree, &lookup);
|
||||||
|
if (sock_data == NULL) {
|
||||||
|
/* Socket has not been registered with wpoll instance. */
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->events & ~sock_data->events) {
|
||||||
|
if (sock_data->free_op == NULL) {
|
||||||
|
wpoll_op_t* op = malloc(sizeof *op);
|
||||||
|
if (op == NULL) {
|
||||||
|
SetLastError(ERROR_OUTOFMEMORY);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_data->free_op = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add to attention list
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_data->user_data = event->data.u64;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WPOLL_CTL_DEL: {
|
||||||
|
wpoll_socket_state_t lookup;
|
||||||
|
wpoll_socket_state_t* sock_data;
|
||||||
|
|
||||||
|
lookup.sock = sock;
|
||||||
|
sock_data = RB_FIND(wpoll_socket_state_tree, &port_data->socket_state_tree, &lookup);
|
||||||
|
if (sock_data == NULL) {
|
||||||
|
/* Socket has not been registered with wpoll instance. */
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SetLastError(ERROR_NOT_FOUND);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
WSASetLastError(WSAEINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int epoll_wait(wpoll_t wpoll_hnd, struct wpoll_event* events, int maxevents, int timeout);
|
||||||
|
|
||||||
|
|||||||
@ -18,10 +18,12 @@
|
|||||||
'sources': [
|
'sources': [
|
||||||
'common.gypi',
|
'common.gypi',
|
||||||
'include/wpoll.h',
|
'include/wpoll.h',
|
||||||
|
'src/msafd.c',
|
||||||
'src/msafd.h',
|
'src/msafd.h',
|
||||||
|
'src/ntapi.c',
|
||||||
|
'src/ntapi.h',
|
||||||
'src/tree.h',
|
'src/tree.h',
|
||||||
'src/wpoll.c',
|
'src/wpoll.c',
|
||||||
'src/msafd.c'
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user