use std::io;
use std::mem::MaybeUninit;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::os::windows::io::{BorrowedHandle, FromRawSocket, OwnedHandle, OwnedSocket};
use crate::io::raw::Raw;
use crate::io::source::Kind;
use crate::syscore::windows::{
AF_INET, AF_INET6, DWORD, ERROR_BROKEN_PIPE, ERROR_HANDLE_EOF, FILE_ACCESS_INFORMATION,
FILE_APPEND_DATA, FILE_BEGIN, FILE_CURRENT, FILE_MODE_INFORMATION, FILE_SYNCHRONOUS_IO_ALERT,
FILE_SYNCHRONOUS_IO_NONALERT, FILE_TYPE_DISK, FILE_WRITE_DATA, GetFileSizeEx, GetFileType,
HANDLE, IN_ADDR, INVALID_SOCKET, IO_STATUS_BLOCK, IPPROTO_TCP, NtQueryInformationFile,
OVERLAPPED, ReadFile, SD_SEND, SIO_UDP_CONNRESET, SO_ACCEPTCONN, SO_TYPE,
SO_UPDATE_ACCEPT_CONTEXT, SO_UPDATE_CONNECT_CONTEXT, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,
SOCK_STREAM, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, SOCKADDR_STORAGE, SOCKET, SOCKET_ERROR,
SOL_SOCKET, STATUS_SUCCESS, SetFilePointerEx, ULONG, WSA_FLAG_NO_HANDLE_INHERIT,
WSA_FLAG_OVERLAPPED, WSAIoctl, WSASocketW, WriteFile, bind, getsockname, getsockopt,
last_error, setsockopt, shutdown, wsa_error,
};
fn socket_of(raw: Raw) -> SOCKET {
raw as SOCKET
}
fn handle_of(raw: Raw) -> HANDLE {
raw as usize as HANDLE
}
fn check(ret: i32) -> io::Result<()> {
if ret == SOCKET_ERROR {
Err(wsa_error())
} else {
Ok(())
}
}
fn int_option(raw: Raw, name: i32) -> io::Result<i32> {
let mut value: i32 = 0;
let mut len = size_of::<i32>() as i32;
check(unsafe {
getsockopt(
socket_of(raw),
SOL_SOCKET,
name,
core::ptr::from_mut(&mut value).cast(),
&mut len,
)
})?;
Ok(value)
}
pub(crate) fn kind_of_socket(raw: Raw) -> io::Result<Kind> {
Ok(match int_option(raw, SO_TYPE)? {
SOCK_DGRAM | SOCK_RAW | SOCK_RDM => Kind::Udp,
_ if int_option(raw, SO_ACCEPTCONN)? != 0 => Kind::TcpListener,
_ => Kind::Tcp,
})
}
pub(crate) fn kind_of(raw: Raw) -> io::Result<Kind> {
match kind_of_socket(raw) {
Err(err) if err.raw_os_error() == Some(crate::syscore::windows::WSAENOTSOCK) => {
Ok(match unsafe { GetFileType(handle_of(raw)) } {
FILE_TYPE_DISK => Kind::File,
_ => Kind::Bytes,
})
}
other => other,
}
}
pub(crate) fn synchronous(raw: Raw) -> io::Result<bool> {
let mode = file_information(raw, FILE_MODE_INFORMATION)?;
Ok(mode & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) != 0)
}
pub(crate) fn appends(raw: Raw) -> io::Result<bool> {
let access = file_information(raw, FILE_ACCESS_INFORMATION)?;
Ok(access & FILE_APPEND_DATA != 0 && access & FILE_WRITE_DATA == 0)
}
fn file_information(raw: Raw, class: u32) -> io::Result<ULONG> {
let mut status = IO_STATUS_BLOCK {
Status: 0,
Information: 0,
};
let mut value: ULONG = 0;
let got = unsafe {
NtQueryInformationFile(
handle_of(raw),
&mut status,
core::ptr::from_mut(&mut value).cast(),
size_of::<ULONG>() as ULONG,
class,
)
};
if got != STATUS_SUCCESS {
return Err(io::Error::from_raw_os_error(
crate::syscore::windows::status_error(got).unwrap_or(0),
));
}
Ok(value)
}
pub(crate) fn shutdown_write(raw: Raw) -> io::Result<()> {
check(unsafe { shutdown(socket_of(raw), SD_SEND) })
}
pub(crate) fn adopt_accepted(listener: Raw, conn: &OwnedSocket) -> io::Result<()> {
use std::os::windows::io::AsRawSocket;
let listener = socket_of(listener);
check(unsafe {
setsockopt(
conn.as_raw_socket() as SOCKET,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
core::ptr::from_ref(&listener).cast(),
size_of::<SOCKET>() as i32,
)
})
}
pub(crate) fn adopt_connected(raw: Raw) -> io::Result<()> {
check(unsafe {
setsockopt(
socket_of(raw),
SOL_SOCKET,
SO_UPDATE_CONNECT_CONTEXT,
core::ptr::null(),
0,
)
})
}
pub(crate) fn tcp_socket(family: u16) -> io::Result<OwnedSocket> {
crate::syscore::windows::winsock::start()?;
let socket = unsafe {
WSASocketW(
i32::from(family),
SOCK_STREAM,
IPPROTO_TCP,
core::ptr::null_mut(),
0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
)
};
if socket == INVALID_SOCKET {
return Err(wsa_error());
}
Ok(unsafe { OwnedSocket::from_raw_socket(socket as u64) })
}
pub(crate) fn family(raw: Raw) -> io::Result<u16> {
let mut storage = SOCKADDR_STORAGE::zeroed();
let mut len = size_of::<SOCKADDR_STORAGE>() as i32;
check(unsafe {
getsockname(
socket_of(raw),
core::ptr::from_mut(&mut storage).cast(),
&mut len,
)
})?;
Ok(storage.ss_family)
}
pub(crate) fn bind_any(raw: Raw, family: u16) -> io::Result<()> {
let any = if family == AF_INET6 {
SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0)
} else {
SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0)
};
let (storage, len) = raw_addr(&any);
match check(unsafe { bind(socket_of(raw), core::ptr::from_ref(&storage).cast(), len) }) {
Err(err) if err.raw_os_error() == Some(crate::syscore::windows::WSAEINVAL) => Ok(()),
other => other,
}
}
pub(crate) fn udp_connreset_off(raw: Raw) -> io::Result<()> {
let off: u32 = 0;
let mut bytes: DWORD = 0;
check(unsafe {
WSAIoctl(
socket_of(raw),
SIO_UDP_CONNRESET,
core::ptr::from_ref(&off).cast(),
size_of::<u32>() as DWORD,
core::ptr::null_mut(),
0,
&mut bytes,
core::ptr::null_mut(),
core::ptr::null(),
)
})
}
pub(crate) fn bind_inet(raw: Raw, addr: &SocketAddr) -> io::Result<()> {
let (storage, len) = raw_addr(addr);
check(unsafe { bind(socket_of(raw), core::ptr::from_ref(&storage).cast(), len) })
}
pub(crate) fn listen(raw: Raw, backlog: u32) -> io::Result<()> {
let backlog = i32::try_from(backlog).unwrap_or(i32::MAX);
check(unsafe { crate::syscore::windows::listen(socket_of(raw), backlog) })
}
pub(crate) fn raw_addr(addr: &SocketAddr) -> (SOCKADDR_STORAGE, i32) {
let mut storage = SOCKADDR_STORAGE::zeroed();
let len = match addr {
SocketAddr::V4(v4) => {
let raw = SOCKADDR_IN {
sin_family: AF_INET,
sin_port: v4.port().to_be(),
sin_addr: IN_ADDR {
s_addr: v4.ip().octets(),
},
sin_zero: [0; 8],
};
unsafe { core::ptr::write(core::ptr::from_mut(&mut storage).cast(), raw) };
size_of::<SOCKADDR_IN>()
}
SocketAddr::V6(v6) => {
let raw = SOCKADDR_IN6 {
sin6_family: AF_INET6,
sin6_port: v6.port().to_be(),
sin6_flowinfo: v6.flowinfo(),
sin6_addr: v6.ip().octets(),
sin6_scope_id: v6.scope_id(),
};
unsafe { core::ptr::write(core::ptr::from_mut(&mut storage).cast(), raw) };
size_of::<SOCKADDR_IN6>()
}
};
(storage, len as i32)
}
pub(crate) unsafe fn socket_addr(addr: *const SOCKADDR, len: i32) -> io::Result<SocketAddr> {
let len = usize::try_from(len).unwrap_or(0);
let family = if len >= 2 {
unsafe { (*addr).sa_family }
} else {
0
};
match family {
AF_INET if len >= size_of::<SOCKADDR_IN>() => {
let raw = unsafe { core::ptr::read_unaligned(addr.cast::<SOCKADDR_IN>()) };
Ok(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::from(raw.sin_addr.s_addr),
u16::from_be(raw.sin_port),
)))
}
AF_INET6 if len >= size_of::<SOCKADDR_IN6>() => {
let raw = unsafe { core::ptr::read_unaligned(addr.cast::<SOCKADDR_IN6>()) };
Ok(SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::from(raw.sin6_addr),
u16::from_be(raw.sin6_port),
raw.sin6_flowinfo,
raw.sin6_scope_id,
)))
}
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"the kernel gave an address of a family nuclei does not read",
)),
}
}
fn at(offset: u64) -> OVERLAPPED {
let mut ov = OVERLAPPED::zeroed();
ov.Offset = offset as u32;
ov.OffsetHigh = (offset >> 32) as u32;
ov
}
fn read_at(raw: Raw, buf: *mut u8, len: usize, offset: u64) -> io::Result<usize> {
let mut ov = at(offset);
let mut read: DWORD = 0;
let len = u32::try_from(len).unwrap_or(u32::MAX);
if unsafe { ReadFile(handle_of(raw), buf.cast(), len, &mut read, &mut ov) } == 0 {
let err = last_error();
return match err.raw_os_error() {
Some(ERROR_HANDLE_EOF | ERROR_BROKEN_PIPE) => Ok(0),
_ => Err(err),
};
}
Ok(read as usize)
}
pub(crate) fn pread(raw: Raw, buf: &mut [u8], offset: u64) -> io::Result<usize> {
read_at(raw, buf.as_mut_ptr(), buf.len(), offset)
}
pub(crate) fn pread_uninit(
raw: Raw,
buf: &mut [MaybeUninit<u8>],
offset: u64,
) -> io::Result<usize> {
read_at(raw, buf.as_mut_ptr().cast(), buf.len(), offset)
}
pub(crate) fn pwrite_all(raw: Raw, buf: &[u8], offset: u64) -> io::Result<()> {
write_all_at(raw, buf, Some(offset))
}
pub(crate) fn append_all(raw: Raw, buf: &[u8]) -> io::Result<u64> {
write_all_at(raw, buf, None)?;
file_size(raw)
}
fn write_all_at(raw: Raw, mut buf: &[u8], mut offset: Option<u64>) -> io::Result<()> {
while !buf.is_empty() {
let mut ov = at(offset.unwrap_or(u64::MAX));
let mut written: DWORD = 0;
let len = u32::try_from(buf.len()).unwrap_or(u32::MAX);
if unsafe {
WriteFile(
handle_of(raw),
buf.as_ptr().cast(),
len,
&mut written,
&mut ov,
)
} == 0
{
return Err(last_error());
}
if written == 0 {
return Err(io::ErrorKind::WriteZero.into());
}
buf = &buf[written as usize..];
offset = offset.map(|at| at + u64::from(written));
}
Ok(())
}
pub(crate) fn seek(raw: Raw, offset: Option<u64>) -> io::Result<u64> {
let (distance, method) = match offset {
Some(offset) => (
i64::try_from(offset).map_err(|_| io::ErrorKind::InvalidInput)?,
FILE_BEGIN,
),
None => (0, FILE_CURRENT),
};
let mut now: i64 = 0;
if unsafe { SetFilePointerEx(handle_of(raw), distance, &mut now, method) } == 0 {
return Err(last_error());
}
Ok(now as u64)
}
pub(crate) fn file_size(raw: Raw) -> io::Result<u64> {
let mut size: i64 = 0;
if unsafe { GetFileSizeEx(handle_of(raw), &mut size) } == 0 {
return Err(last_error());
}
Ok(size as u64)
}
pub(crate) fn duplicate_file(raw: Raw) -> io::Result<OwnedHandle> {
unsafe { BorrowedHandle::borrow_raw(handle_of(raw).cast()) }.try_clone_to_owned()
}