Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace miow, winapi, and ntapi with windows-sys #1556

Merged
merged 12 commits into from
Mar 31, 2022
20 changes: 15 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ default = []
# Enables the `Poll` and `Registry` types.
os-poll = []
# Enables additional OS specific extensions, e.g. Unix `pipe(2)`.
os-ext = ["os-poll"]
os-ext = [
"os-poll",
"windows-sys/Win32_System_Pipes",
"windows-sys/Win32_Security",
]
# Enables `mio::net` module containing networking primitives.
net = []

Expand All @@ -44,10 +48,16 @@ log = "0.4.8"
[target.'cfg(unix)'.dependencies]
libc = "0.2.86"

[target.'cfg(windows)'.dependencies]
miow = "0.3.6"
winapi = { version = "0.3", features = ["winsock2", "mswsock"] }
ntapi = "0.3"
[target.'cfg(windows)'.dependencies.windows-sys]
version = ">=0.32, <=0.34"
features = [
"Win32_Storage_FileSystem", # Enables NtCreateFile
"Win32_Foundation", # Basic types eg HANDLE
"Win32_Networking_WinSock", # winsock2 types/functions
"Win32_NetworkManagement_IpHelper", # AF_INET and AF_INET6 constants
"Win32_System_IO", # IO types like OVERLAPPED etc
"Win32_System_WindowsProgramming", # General future used for various types/funcs
]

[target.'cfg(target_os = "wasi")'.dependencies]
wasi = "0.11.0"
Expand Down
84 changes: 51 additions & 33 deletions src/sys/windows/afd.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
use ntapi::ntioapi::{IO_STATUS_BLOCK_u, IO_STATUS_BLOCK};
use ntapi::ntioapi::{NtCancelIoFileEx, NtDeviceIoControlFile};
use ntapi::ntrtl::RtlNtStatusToDosError;
use std::ffi::c_void;
use std::fmt;
use std::fs::File;
use std::io;
use std::mem::size_of;
use std::os::windows::io::AsRawHandle;
use std::ptr::null_mut;
use winapi::shared::ntdef::{HANDLE, LARGE_INTEGER, NTSTATUS, PVOID, ULONG};
use winapi::shared::ntstatus::{STATUS_NOT_FOUND, STATUS_PENDING, STATUS_SUCCESS};

const IOCTL_AFD_POLL: ULONG = 0x00012024;
use windows_sys::Win32::Foundation::{
RtlNtStatusToDosError, HANDLE, NTSTATUS, STATUS_NOT_FOUND, STATUS_PENDING, STATUS_SUCCESS,
};
use windows_sys::Win32::System::WindowsProgramming::{
NtDeviceIoControlFile, IO_STATUS_BLOCK, IO_STATUS_BLOCK_0,
};

const IOCTL_AFD_POLL: u32 = 0x00012024;

#[link(name = "ntdll")]
extern "system" {
Jake-Shadle marked this conversation as resolved.
Show resolved Hide resolved
/// See <https://processhacker.sourceforge.io/doc/ntioapi_8h.html#a0d4d550cad4d62d75b76961e25f6550c>
///
/// This is an undocumented API and as such not part of <https://github.com/microsoft/win32metadata>
/// from which `windows-sys` is generated, and also unlikely to be added, so
/// we manually declare it here
fn NtCancelIoFileEx(
FileHandle: HANDLE,
IoRequestToCancel: *mut IO_STATUS_BLOCK,
IoStatusBlock: *mut IO_STATUS_BLOCK,
) -> NTSTATUS;
}
/// Winsock2 AFD driver instance.
///
/// All operations are unsafe due to IO_STATUS_BLOCK parameter are being used by Afd driver during STATUS_PENDING before I/O Completion Port returns its result.
Expand All @@ -24,18 +39,18 @@ pub struct Afd {
#[derive(Debug)]
pub struct AfdPollHandleInfo {
pub handle: HANDLE,
pub events: ULONG,
pub events: u32,
pub status: NTSTATUS,
}

unsafe impl Send for AfdPollHandleInfo {}

#[repr(C)]
pub struct AfdPollInfo {
pub timeout: LARGE_INTEGER,
pub timeout: i64,
// Can have only value 1.
pub number_of_handles: ULONG,
pub exclusive: ULONG,
pub number_of_handles: u32,
pub exclusive: u32,
pub handles: [AfdPollHandleInfo; 1],
}

Expand All @@ -58,13 +73,13 @@ impl Afd {
&self,
info: &mut AfdPollInfo,
iosb: *mut IO_STATUS_BLOCK,
overlapped: PVOID,
overlapped: *mut c_void,
) -> io::Result<bool> {
let info_ptr: PVOID = info as *mut _ as PVOID;
(*iosb).u.Status = STATUS_PENDING;
let info_ptr = info as *mut _ as *mut c_void;
(*iosb).Anonymous.Status = STATUS_PENDING;
let status = NtDeviceIoControlFile(
self.fd.as_raw_handle(),
null_mut(),
self.fd.as_raw_handle() as HANDLE,
0,
None,
overlapped,
iosb,
Expand Down Expand Up @@ -93,15 +108,15 @@ impl Afd {
/// Use it only with request is still being polled so that you have valid `IO_STATUS_BLOCK` to use.
/// User should NOT deallocate there overlapped value after the `cancel` to prevent double free.
pub unsafe fn cancel(&self, iosb: *mut IO_STATUS_BLOCK) -> io::Result<()> {
if (*iosb).u.Status != STATUS_PENDING {
if (*iosb).Anonymous.Status != STATUS_PENDING {
return Ok(());
}

let mut cancel_iosb = IO_STATUS_BLOCK {
u: IO_STATUS_BLOCK_u { Status: 0 },
Anonymous: IO_STATUS_BLOCK_0 { Status: 0 },
Information: 0,
};
let status = NtCancelIoFileEx(self.fd.as_raw_handle(), iosb, &mut cancel_iosb);
let status = NtCancelIoFileEx(self.fd.as_raw_handle() as HANDLE, iosb, &mut cancel_iosb);
if status == STATUS_SUCCESS || status == STATUS_NOT_FOUND {
return Ok(());
}
Expand All @@ -114,31 +129,34 @@ impl Afd {
cfg_io_source! {
use std::mem::zeroed;
use std::os::windows::io::{FromRawHandle, RawHandle};
use std::ptr::null_mut;
use std::sync::atomic::{AtomicUsize, Ordering};

use miow::iocp::CompletionPort;
use ntapi::ntioapi::{NtCreateFile, FILE_OPEN};
use winapi::shared::ntdef::{OBJECT_ATTRIBUTES, UNICODE_STRING, USHORT, WCHAR};
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winbase::{SetFileCompletionNotificationModes, FILE_SKIP_SET_EVENT_ON_HANDLE};
use winapi::um::winnt::{SYNCHRONIZE, FILE_SHARE_READ, FILE_SHARE_WRITE};
use super::iocp::CompletionPort;
use windows_sys::Win32::{
Foundation::{UNICODE_STRING, INVALID_HANDLE_VALUE},
System::WindowsProgramming::{
OBJECT_ATTRIBUTES, FILE_SKIP_SET_EVENT_ON_HANDLE,
},
Storage::FileSystem::{FILE_OPEN, NtCreateFile, SetFileCompletionNotificationModes, SYNCHRONIZE, FILE_SHARE_READ, FILE_SHARE_WRITE},
};

const AFD_HELPER_ATTRIBUTES: OBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES {
Length: size_of::<OBJECT_ATTRIBUTES>() as ULONG,
RootDirectory: null_mut(),
Length: size_of::<OBJECT_ATTRIBUTES>() as u32,
RootDirectory: 0,
ObjectName: &AFD_OBJ_NAME as *const _ as *mut _,
Attributes: 0,
SecurityDescriptor: null_mut(),
SecurityQualityOfService: null_mut(),
};

const AFD_OBJ_NAME: UNICODE_STRING = UNICODE_STRING {
Length: (AFD_HELPER_NAME.len() * size_of::<WCHAR>()) as USHORT,
MaximumLength: (AFD_HELPER_NAME.len() * size_of::<WCHAR>()) as USHORT,
Length: (AFD_HELPER_NAME.len() * size_of::<u16>()) as u16,
MaximumLength: (AFD_HELPER_NAME.len() * size_of::<u16>()) as u16,
Buffer: AFD_HELPER_NAME.as_ptr() as *mut _,
};

const AFD_HELPER_NAME: &[WCHAR] = &[
const AFD_HELPER_NAME: &[u16] = &[
'\\' as _,
'D' as _,
'e' as _,
Expand Down Expand Up @@ -166,10 +184,10 @@ cfg_io_source! {

impl Afd {
/// Create new Afd instance.
pub fn new(cp: &CompletionPort) -> io::Result<Afd> {
pub(crate) fn new(cp: &CompletionPort) -> io::Result<Afd> {
let mut afd_helper_handle: HANDLE = INVALID_HANDLE_VALUE;
let mut iosb = IO_STATUS_BLOCK {
u: IO_STATUS_BLOCK_u { Status: 0 },
Anonymous: IO_STATUS_BLOCK_0 { Status: 0 },
Information: 0,
};

Expand Down Expand Up @@ -204,7 +222,7 @@ cfg_io_source! {
cp.add_handle(token, &afd.fd)?;
match SetFileCompletionNotificationModes(
afd_helper_handle,
FILE_SKIP_SET_EVENT_ON_HANDLE,
FILE_SKIP_SET_EVENT_ON_HANDLE as u8 // This is just 2, so fits in u8
) {
0 => Err(io::Error::last_os_error()),
_ => Ok(afd),
Expand Down
3 changes: 1 addition & 2 deletions src/sys/windows/event.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::fmt;

use miow::iocp::CompletionStatus;

use super::afd;
use super::iocp::CompletionStatus;
use crate::Token;

#[derive(Clone)]
Expand Down
30 changes: 30 additions & 0 deletions src/sys/windows/handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::os::windows::io::RawHandle;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};

/// Wrapper around a Windows HANDLE so that we close it upon drop in all scenarios
#[derive(Debug)]
pub struct Handle(HANDLE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a review comment, but future work: we can replace this with std::os::windows::io::OwnedHandle (currently unstable).


impl Handle {
#[inline]
pub fn new(handle: HANDLE) -> Self {
Self(handle)
}

pub fn raw(&self) -> HANDLE {
self.0
}

pub fn into_raw(self) -> RawHandle {
let ret = self.0;
// This is super important so that drop is not called!
std::mem::forget(self);
ret as RawHandle
}
}

impl Drop for Handle {
fn drop(&mut self) {
unsafe { CloseHandle(self.0) };
}
}
6 changes: 3 additions & 3 deletions src/sys/windows/io_status_block.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::fmt;
use std::ops::{Deref, DerefMut};

use ntapi::ntioapi::IO_STATUS_BLOCK;
use windows_sys::Win32::System::WindowsProgramming::IO_STATUS_BLOCK;

pub struct IoStatusBlock(IO_STATUS_BLOCK);

cfg_io_source! {
use ntapi::ntioapi::IO_STATUS_BLOCK_u;
use windows_sys::Win32::System::WindowsProgramming::{IO_STATUS_BLOCK_0};

impl IoStatusBlock {
pub fn zeroed() -> Self {
Self(IO_STATUS_BLOCK {
u: IO_STATUS_BLOCK_u { Status: 0 },
Anonymous: IO_STATUS_BLOCK_0 { Status: 0 },
Information: 0,
})
}
Expand Down
Loading