Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
255
third-party/vendor/mio/src/sys/windows/afd.rs
vendored
Normal file
255
third-party/vendor/mio/src/sys/windows/afd.rs
vendored
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
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 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" {
|
||||
/// 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.
|
||||
#[derive(Debug)]
|
||||
pub struct Afd {
|
||||
fd: File,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct AfdPollHandleInfo {
|
||||
pub handle: HANDLE,
|
||||
pub events: u32,
|
||||
pub status: NTSTATUS,
|
||||
}
|
||||
|
||||
unsafe impl Send for AfdPollHandleInfo {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct AfdPollInfo {
|
||||
pub timeout: i64,
|
||||
// Can have only value 1.
|
||||
pub number_of_handles: u32,
|
||||
pub exclusive: u32,
|
||||
pub handles: [AfdPollHandleInfo; 1],
|
||||
}
|
||||
|
||||
impl fmt::Debug for AfdPollInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AfdPollInfo").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Afd {
|
||||
/// Poll `Afd` instance with `AfdPollInfo`.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe due to memory of `IO_STATUS_BLOCK` still being used by `Afd` instance while `Ok(false)` (`STATUS_PENDING`).
|
||||
/// `iosb` needs to be untouched after the call while operation is in effective at ALL TIME except for `cancel` method.
|
||||
/// So be careful not to `poll` twice while polling.
|
||||
/// User should deallocate there overlapped value when error to prevent memory leak.
|
||||
pub unsafe fn poll(
|
||||
&self,
|
||||
info: &mut AfdPollInfo,
|
||||
iosb: *mut IO_STATUS_BLOCK,
|
||||
overlapped: *mut c_void,
|
||||
) -> io::Result<bool> {
|
||||
let info_ptr = info as *mut _ as *mut c_void;
|
||||
(*iosb).Anonymous.Status = STATUS_PENDING;
|
||||
let status = NtDeviceIoControlFile(
|
||||
self.fd.as_raw_handle() as HANDLE,
|
||||
0,
|
||||
None,
|
||||
overlapped,
|
||||
iosb,
|
||||
IOCTL_AFD_POLL,
|
||||
info_ptr,
|
||||
size_of::<AfdPollInfo>() as u32,
|
||||
info_ptr,
|
||||
size_of::<AfdPollInfo>() as u32,
|
||||
);
|
||||
match status {
|
||||
STATUS_SUCCESS => Ok(true),
|
||||
STATUS_PENDING => Ok(false),
|
||||
_ => Err(io::Error::from_raw_os_error(
|
||||
RtlNtStatusToDosError(status) as i32
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel previous polled request of `Afd`.
|
||||
///
|
||||
/// iosb needs to be used by `poll` first for valid `cancel`.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This function is unsafe due to memory of `IO_STATUS_BLOCK` still being used by `Afd` instance while `Ok(false)` (`STATUS_PENDING`).
|
||||
/// 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).Anonymous.Status != STATUS_PENDING {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut cancel_iosb = IO_STATUS_BLOCK {
|
||||
Anonymous: IO_STATUS_BLOCK_0 { Status: 0 },
|
||||
Information: 0,
|
||||
};
|
||||
let status = NtCancelIoFileEx(self.fd.as_raw_handle() as HANDLE, iosb, &mut cancel_iosb);
|
||||
if status == STATUS_SUCCESS || status == STATUS_NOT_FOUND {
|
||||
return Ok(());
|
||||
}
|
||||
Err(io::Error::from_raw_os_error(
|
||||
RtlNtStatusToDosError(status) as i32
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
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 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 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::<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: &[u16] = &[
|
||||
'\\' as _,
|
||||
'D' as _,
|
||||
'e' as _,
|
||||
'v' as _,
|
||||
'i' as _,
|
||||
'c' as _,
|
||||
'e' as _,
|
||||
'\\' as _,
|
||||
'A' as _,
|
||||
'f' as _,
|
||||
'd' as _,
|
||||
'\\' as _,
|
||||
'M' as _,
|
||||
'i' as _,
|
||||
'o' as _
|
||||
];
|
||||
|
||||
static NEXT_TOKEN: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
impl AfdPollInfo {
|
||||
pub fn zeroed() -> AfdPollInfo {
|
||||
unsafe { zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Afd {
|
||||
/// Create new Afd instance.
|
||||
pub(crate) fn new(cp: &CompletionPort) -> io::Result<Afd> {
|
||||
let mut afd_helper_handle: HANDLE = INVALID_HANDLE_VALUE;
|
||||
let mut iosb = IO_STATUS_BLOCK {
|
||||
Anonymous: IO_STATUS_BLOCK_0 { Status: 0 },
|
||||
Information: 0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let status = NtCreateFile(
|
||||
&mut afd_helper_handle as *mut _,
|
||||
SYNCHRONIZE,
|
||||
&AFD_HELPER_ATTRIBUTES as *const _ as *mut _,
|
||||
&mut iosb,
|
||||
null_mut(),
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
0,
|
||||
null_mut(),
|
||||
0,
|
||||
);
|
||||
if status != STATUS_SUCCESS {
|
||||
let raw_err = io::Error::from_raw_os_error(
|
||||
RtlNtStatusToDosError(status) as i32
|
||||
);
|
||||
let msg = format!("Failed to open \\Device\\Afd\\Mio: {}", raw_err);
|
||||
return Err(io::Error::new(raw_err.kind(), msg));
|
||||
}
|
||||
let fd = File::from_raw_handle(afd_helper_handle as RawHandle);
|
||||
// Increment by 2 to reserve space for other types of handles.
|
||||
// Non-AFD types (currently only NamedPipe), use odd numbered
|
||||
// tokens. This allows the selector to differentiate between them
|
||||
// and dispatch events accordingly.
|
||||
let token = NEXT_TOKEN.fetch_add(2, Ordering::Relaxed) + 2;
|
||||
let afd = Afd { fd };
|
||||
cp.add_handle(token, &afd.fd)?;
|
||||
match SetFileCompletionNotificationModes(
|
||||
afd_helper_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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const POLL_RECEIVE: u32 = 0b0_0000_0001;
|
||||
pub const POLL_RECEIVE_EXPEDITED: u32 = 0b0_0000_0010;
|
||||
pub const POLL_SEND: u32 = 0b0_0000_0100;
|
||||
pub const POLL_DISCONNECT: u32 = 0b0_0000_1000;
|
||||
pub const POLL_ABORT: u32 = 0b0_0001_0000;
|
||||
pub const POLL_LOCAL_CLOSE: u32 = 0b0_0010_0000;
|
||||
// Not used as it indicated in each event where a connection is connected, not
|
||||
// just the first time a connection is established.
|
||||
// Also see https://github.com/piscisaureus/wepoll/commit/8b7b340610f88af3d83f40fb728e7b850b090ece.
|
||||
pub const POLL_CONNECT: u32 = 0b0_0100_0000;
|
||||
pub const POLL_ACCEPT: u32 = 0b0_1000_0000;
|
||||
pub const POLL_CONNECT_FAIL: u32 = 0b1_0000_0000;
|
||||
|
||||
pub const KNOWN_EVENTS: u32 = POLL_RECEIVE
|
||||
| POLL_RECEIVE_EXPEDITED
|
||||
| POLL_SEND
|
||||
| POLL_DISCONNECT
|
||||
| POLL_ABORT
|
||||
| POLL_LOCAL_CLOSE
|
||||
| POLL_ACCEPT
|
||||
| POLL_CONNECT_FAIL;
|
||||
Loading…
Add table
Add a link
Reference in a new issue