diff --git a/src/afd.c b/src/afd.c new file mode 100644 index 0000000..3a0cb41 --- /dev/null +++ b/src/afd.c @@ -0,0 +1,89 @@ +#include "afd.h" +#include "error.h" +#include "win.h" + +int 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 = CreateEventW(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = NtDeviceIoControlFile((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_ptr->Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = we_map_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/src/afd.h b/src/afd.h index 0b7e27e..67b325b 100644 --- a/src/afd.h +++ b/src/afd.h @@ -4,10 +4,6 @@ #include "nt.h" #include "win.h" -#ifndef SIO_BASE_HANDLE -#define SIO_BASE_HANDLE 0x48000022 -#endif - #ifndef FILE_DEVICE_NETWORK #define FILE_DEVICE_NETWORK 0x00000012 #endif @@ -86,4 +82,6 @@ static const GUID AFD_PROVIDER_IDS[] = { 0x43e4, {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}}; +int afd_poll(SOCKET socket, AFD_POLL_INFO* info, OVERLAPPED* overlapped); + #endif /* EPOLL_AFD_H_ */ diff --git a/src/epoll.c b/src/epoll.c index 80496ac..0cb3618 100644 --- a/src/epoll.c +++ b/src/epoll.c @@ -10,6 +10,10 @@ #include "tree.h" #include "win.h" +#ifndef SIO_BASE_HANDLE +#define SIO_BASE_HANDLE 0x48000022 +#endif + #ifndef _SSIZE_T_DEFINED #define SSIZE_T_DEFINED typedef intptr_t ssize_t; @@ -46,9 +50,6 @@ static int epoll__compare_sock_data(epoll_sock_data_t* a, epoll_sock_data_t* b); static int epoll__submit_poll_req(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__initialized = 0; @@ -686,8 +687,8 @@ int epoll__submit_poll_req(epoll_port_data_t* port_data, io_req->poll_info.Handles[0].Status = 0; io_req->poll_info.Handles[0].Events = afd_events; - result = epoll__afd_poll( - sock_data->peer_sock, &io_req->poll_info, &io_req->overlapped); + result = + afd_poll(sock_data->peer_sock, &io_req->poll_info, &io_req->overlapped); if (result != 0) { DWORD error = WSAGetLastError(); if (error != WSA_IO_PENDING) { @@ -705,91 +706,3 @@ int epoll__submit_poll_req(epoll_port_data_t* port_data, 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 = CreateEventW(NULL, FALSE, FALSE, NULL); - if (event == NULL) { - return SOCKET_ERROR; - } - apc_context = NULL; - } - - iosb_ptr->Status = STATUS_PENDING; - status = NtDeviceIoControlFile((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_ptr->Status; - } - - CloseHandle(event); - } - - switch (status) { - case STATUS_SUCCESS: - error = ERROR_SUCCESS; - break; - - case STATUS_PENDING: - error = WSA_IO_PENDING; - break; - - default: - error = we_map_ntstatus_to_winsock_error(status); - break; - } - - WSASetLastError(error); - - if (error == ERROR_SUCCESS) { - return 0; - } else { - return SOCKET_ERROR; - } -}