use std::mem::{align_of, offset_of, size_of};
use windows::Win32::Foundation::{HANDLE, NTSTATUS};
use crate::{Event, Interest};
pub(super) const IOCTL_AFD_POLL: u32 = 0x0001_2024;
const POLL_RECEIVE: u32 = 0x01;
const POLL_SEND: u32 = 0x04;
const POLL_DISCONNECT: u32 = 0x08;
const POLL_ABORT: u32 = 0x10;
const POLL_LOCAL_CLOSE: u32 = 0x20;
const POLL_ACCEPT: u32 = 0x80;
const POLL_CONNECT_FAIL: u32 = 0x100;
const READABLE: u32 = POLL_RECEIVE | POLL_DISCONNECT | POLL_ACCEPT | POLL_ABORT | POLL_CONNECT_FAIL;
const WRITABLE: u32 = POLL_SEND | POLL_ABORT | POLL_CONNECT_FAIL;
#[derive(Clone, Copy)]
#[repr(C)]
pub(super) struct AfdPollHandle {
pub(super) handle: HANDLE,
pub(super) events: u32,
pub(super) status: NTSTATUS,
}
#[derive(Clone, Copy)]
#[repr(C)]
pub(super) struct AfdPollInfo {
pub(super) timeout: i64,
pub(super) number_of_handles: u32,
pub(super) exclusive: u32,
pub(super) handles: [AfdPollHandle; 1],
}
const _: () = {
assert!(size_of::<AfdPollHandle>() == 2 * size_of::<usize>());
assert!(size_of::<AfdPollInfo>() == 16 + size_of::<AfdPollHandle>());
assert!(align_of::<AfdPollInfo>() == align_of::<usize>());
assert!(offset_of!(AfdPollInfo, number_of_handles) == 8);
assert!(offset_of!(AfdPollInfo, handles) == 16);
};
impl AfdPollInfo {
pub(super) fn idle() -> Self {
Self {
timeout: 0,
number_of_handles: 0,
exclusive: 0,
handles: [AfdPollHandle {
handle: HANDLE::default(),
events: 0,
status: NTSTATUS(0),
}],
}
}
pub(super) fn new(base_socket: HANDLE, interest: Interest) -> Self {
let mut events = POLL_LOCAL_CLOSE;
if interest.readable {
events |= READABLE;
}
if interest.writable {
events |= WRITABLE;
}
Self {
timeout: i64::MAX,
number_of_handles: 1,
exclusive: 0,
handles: [AfdPollHandle {
handle: base_socket,
events,
status: NTSTATUS(0),
}],
}
}
pub(super) fn readiness(&self, socket: usize) -> Event {
let reported = if self.number_of_handles == 0 {
0
} else {
self.handles[0].events
};
let closed = reported & POLL_LOCAL_CLOSE != 0;
Event {
fd: std::ptr::without_provenance_mut(socket),
readable: !closed && reported & READABLE != 0,
writable: !closed && reported & WRITABLE != 0,
error: closed || reported & (POLL_ABORT | POLL_CONNECT_FAIL) != 0,
hangup: closed || reported & POLL_DISCONNECT != 0,
}
}
}
#[cfg(test)]
pub(super) fn poll_info(interest: Interest) -> AfdPollInfo {
AfdPollInfo::new(HANDLE::default(), interest)
}