190 lines
5.9 KiB
Rust
190 lines
5.9 KiB
Rust
use crate::address::WindowsAddressKnown;
|
|
use crate::errors::throw_from_windows_err_code;
|
|
use crate::eventloop::allocator::Allocator;
|
|
use crate::eventloop::task::IoTask;
|
|
use bgtu_networks_2_network_abstract::ServersContext;
|
|
use std::mem::uninitialized;
|
|
use std::pin::Pin;
|
|
use std::ptr::NonNull;
|
|
use std::slice;
|
|
use windows::Win32::Networking::WinSock::{
|
|
WSAGetLastError, WSARecvFrom, WSASendTo, WSASocketW, AF_UNSPEC,
|
|
IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKADDR, SOCKADDR_STORAGE, SOCKET,
|
|
SOCKET_ERROR, SOCK_RAW, WSAEACCES, WSAEADDRNOTAVAIL, WSAEAFNOSUPPORT,
|
|
WSAECONNRESET, WSAEDESTADDRREQ, WSAEFAULT, WSAEHOSTUNREACH, WSAEINPROGRESS, WSAEINTR,
|
|
WSAEINVAL, WSAEMSGSIZE, WSAENETDOWN, WSAENETRESET, WSAENETUNREACH, WSAENOBUFS, WSAENOTCONN,
|
|
WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSANOTINITIALISED, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED,
|
|
WSA_IO_PENDING, WSA_OPERATION_ABORTED,
|
|
};
|
|
use windows::Win32::System::IO::OVERLAPPED;
|
|
|
|
pub(super) struct WindowsOverlappingIcmpSocket<'a> {
|
|
socket: SOCKET,
|
|
heap: &'a Allocator,
|
|
}
|
|
|
|
impl<'a> WindowsOverlappingIcmpSocket<'a> {
|
|
pub fn new(heap: &'a Allocator) -> Self {
|
|
let result = unsafe {
|
|
WSASocketW(
|
|
AF_UNSPEC.0 as i32,
|
|
SOCK_RAW.0,
|
|
IPPROTO_ICMP.0,
|
|
None,
|
|
0,
|
|
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
|
|
)
|
|
};
|
|
|
|
match result {
|
|
Ok(s) => return Self { socket: s, heap },
|
|
Err(e) => throw_from_windows_err_code(e.code()),
|
|
}
|
|
}
|
|
unsafe extern "system" fn _native_callback<
|
|
F: for<'xx> FnOnce(u32, &'xx [u8], WindowsAddressKnown) + 'static,
|
|
>(
|
|
dwerror: u32,
|
|
cbtransferred: u32,
|
|
lpoverlapped: *mut OVERLAPPED,
|
|
dwflags: u32,
|
|
) {
|
|
let task =
|
|
NonNull::from_mut(IoTask::<F>::from_overlapped(lpoverlapped).get_unchecked_mut())
|
|
.as_ptr();
|
|
|
|
(task.read().callback)(
|
|
dwerror,
|
|
slice::from_raw_parts(
|
|
NonNull::from_ref(&(*task).buff).as_ptr().cast(),
|
|
cbtransferred as usize,
|
|
),
|
|
task.read().addr,
|
|
);
|
|
|
|
NonNull::new_unchecked(task)
|
|
.as_mut()
|
|
.heap
|
|
.as_mut()
|
|
.free(Pin::new_unchecked(NonNull::new_unchecked(task).as_mut()));
|
|
}
|
|
|
|
fn _gen_native_callback<F: for<'xx> FnOnce(u32, &'xx [u8], WindowsAddressKnown) + 'static>(
|
|
_: &IoTask<F>,
|
|
) -> LPWSAOVERLAPPED_COMPLETION_ROUTINE {
|
|
return Some(Self::_native_callback::<F>);
|
|
}
|
|
|
|
pub unsafe fn send(
|
|
&mut self,
|
|
addr: WindowsAddressKnown,
|
|
init_data: impl FnOnce(&mut [u8]),
|
|
on_sent: impl FnOnce(u32, WindowsAddressKnown) + 'static,
|
|
) {
|
|
let task = self.heap.alloc(|p| {
|
|
IoTask::init(
|
|
p,
|
|
NonNull::from_ref(self.heap),
|
|
addr,
|
|
|errcode, _: &[u8], addr| on_sent(errcode, addr),
|
|
)
|
|
});
|
|
let task_p = task.get_unchecked_mut();
|
|
|
|
init_data(&mut task_p.buff);
|
|
|
|
let result = WSASendTo(
|
|
self.socket,
|
|
&task_p.buff_d,
|
|
None,
|
|
0,
|
|
Some(NonNull::from_ref(&task_p.addr).cast().as_ptr()),
|
|
size_of::<SOCKADDR_STORAGE>() as i32,
|
|
Some(NonNull::from_mut(&mut task_p.sys).as_ptr()),
|
|
Self::_gen_native_callback(task_p),
|
|
);
|
|
|
|
if result != SOCKET_ERROR {
|
|
return;
|
|
}
|
|
|
|
let result = WSAGetLastError();
|
|
match result {
|
|
WSA_IO_PENDING => {}
|
|
WSAENETUNREACH | WSAENETRESET | WSAECONNRESET => todo!("report"),
|
|
WSAEWOULDBLOCK => throw_from_windows_err_code(result),
|
|
WSAEACCES
|
|
| WSAEADDRNOTAVAIL
|
|
| WSAEAFNOSUPPORT
|
|
| WSAEDESTADDRREQ
|
|
| WSAEFAULT
|
|
| WSAEHOSTUNREACH
|
|
| WSAEINPROGRESS
|
|
| WSAEINTR
|
|
| WSAEINVAL
|
|
| WSAEMSGSIZE
|
|
| WSAENETDOWN
|
|
| WSAENOBUFS
|
|
| WSAENOTCONN
|
|
| WSAENOTSOCK
|
|
| WSAESHUTDOWN
|
|
| WSANOTINITIALISED
|
|
| WSA_OPERATION_ABORTED => throw_from_windows_err_code(result),
|
|
_ => throw_from_windows_err_code(result),
|
|
}
|
|
}
|
|
|
|
pub unsafe fn receive(
|
|
&self,
|
|
on_received: impl for<'xx> FnOnce(u32, WindowsAddressKnown, &'xx [u8]) + 'static,
|
|
) {
|
|
|
|
let task = self.heap.alloc(|p| {
|
|
IoTask::init(
|
|
p,
|
|
NonNull::from_ref(self.heap),
|
|
uninitialized(),
|
|
|errcode, buffer: &[u8], addr| on_received(errcode, addr, buffer),
|
|
)
|
|
});
|
|
let task_p = task.get_unchecked_mut();
|
|
|
|
|
|
task_p._addr_size = size_of::<SOCKADDR_STORAGE>() as i32;
|
|
task_p._flags = 0;
|
|
let result = WSARecvFrom(
|
|
self.socket,
|
|
&task_p.buff_d,
|
|
None,
|
|
&mut task_p._flags,
|
|
Some(
|
|
NonNull::from_mut(&mut task_p.addr.any.native)
|
|
.cast::<SOCKADDR>()
|
|
.as_ptr(),
|
|
),
|
|
Some(&mut task_p._addr_size),
|
|
Some(&mut task_p.sys),
|
|
Self::_gen_native_callback(task_p),
|
|
);
|
|
|
|
if result != SOCKET_ERROR {
|
|
return;
|
|
}
|
|
|
|
let result = WSAGetLastError();
|
|
match result {
|
|
WSAECONNRESET | WSAEMSGSIZE | WSAENETRESET | WSA_IO_PENDING => return,
|
|
WSAEINVAL => throw_from_windows_err_code(result),
|
|
WSAEWOULDBLOCK => throw_from_windows_err_code(result),
|
|
WSAEFAULT
|
|
| WSAEINPROGRESS
|
|
| WSAEINTR
|
|
| WSAENETDOWN
|
|
| WSAENOTCONN
|
|
| WSANOTINITIALISED
|
|
| WSA_OPERATION_ABORTED => throw_from_windows_err_code(result),
|
|
_ => throw_from_windows_err_code(result),
|
|
}
|
|
}
|
|
}
|