Cleaner eventloop implementation
This commit is contained in:
parent
b2dcd7819a
commit
049b2b1a49
@ -1,7 +1,9 @@
|
|||||||
use super::Address;
|
use super::Address;
|
||||||
|
|
||||||
pub trait ServersContext {
|
pub trait ServersContext {
|
||||||
fn iter_servers(&self) -> impl Iterator<Item=Address>;
|
fn start_measuring(&mut self) -> (u64, impl Iterator<Item = Address>);
|
||||||
|
|
||||||
fn report_ping(&mut self, addr: Address, ping_ms: u64);
|
fn report_ping(&mut self, addr: Address, id: u64, ping_ms: u64);
|
||||||
}
|
|
||||||
|
fn report_error(&mut self, addr: Address, id: u64);
|
||||||
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use windows::Win32::System::Diagnostics::Debug::{
|
|||||||
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
FormatMessageA,
|
FormatMessageA,
|
||||||
};
|
};
|
||||||
use windows::core::PSTR;
|
use windows::core::{HRESULT, PSTR};
|
||||||
|
|
||||||
trait ErrCode {
|
trait ErrCode {
|
||||||
fn to_dword(&self) -> u32;
|
fn to_dword(&self) -> u32;
|
||||||
@ -16,9 +16,7 @@ trait ErrCode {
|
|||||||
|
|
||||||
impl ErrCode for WSA_ERROR {
|
impl ErrCode for WSA_ERROR {
|
||||||
fn to_dword(&self) -> u32 {
|
fn to_dword(&self) -> u32 {
|
||||||
return 0u32
|
return i32::to_dword(&self.0)
|
||||||
.checked_add_signed(self.0)
|
|
||||||
.unwrap_or_else(|| panic!("Cast i32 -> u32 overflow"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +25,19 @@ impl ErrCode for u32 {
|
|||||||
return *self;
|
return *self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ErrCode for i32 {
|
||||||
|
fn to_dword(&self) -> u32 {
|
||||||
|
return 0u32
|
||||||
|
.checked_add_signed(*self)
|
||||||
|
.unwrap_or_else(|| panic!("Cast i32 -> u32 overflow"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrCode for HRESULT {
|
||||||
|
fn to_dword(&self) -> u32 {
|
||||||
|
return i32::to_dword(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn throw_from_windows_err_code(code: impl ErrCode) -> ! {
|
pub(super) fn throw_from_windows_err_code(code: impl ErrCode) -> ! {
|
||||||
panic!(
|
panic!(
|
||||||
|
|||||||
@ -1,68 +1,48 @@
|
|||||||
use crate::io::allocator::Allocator;
|
use crate::io::allocator::Allocator;
|
||||||
use crate::io::servers_context::ServersContext;
|
use crate::io::servers_context::ServersContext;
|
||||||
use crate::io::windows::task::IoTask;
|
|
||||||
use crate::io::windows::WindowsAddressKnown;
|
use crate::io::windows::WindowsAddressKnown;
|
||||||
|
use crate::io::windows::errors::throw_from_windows_err_code;
|
||||||
|
use crate::io::windows::task::IoTask;
|
||||||
|
use std::mem::uninitialized;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use windows::Win32::Networking::WinSock::{
|
use windows::Win32::Networking::WinSock::{
|
||||||
WSARecvFrom, WSASendTo, WSASocketW, AF_UNSPEC, IPPROTO_ICMP, SOCKADDR,
|
AF_UNSPEC, IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCK_RAW, SOCKADDR,
|
||||||
SOCKADDR_STORAGE, SOCK_RAW, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED,
|
SOCKADDR_STORAGE, SOCKET, SOCKET_ERROR, WSA_FLAG_NO_HANDLE_INHERIT,
|
||||||
|
WSA_FLAG_OVERLAPPED, WSA_IO_PENDING, WSA_OPERATION_ABORTED, WSAEACCES, WSAEADDRNOTAVAIL,
|
||||||
|
WSAEAFNOSUPPORT, WSAECONNRESET, WSAEDESTADDRREQ, WSAEFAULT, WSAEHOSTUNREACH, WSAEINPROGRESS,
|
||||||
|
WSAEINTR, WSAEINVAL, WSAEMSGSIZE, WSAENETDOWN, WSAENETRESET, WSAENETUNREACH, WSAENOBUFS,
|
||||||
|
WSAENOTCONN, WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSAGetLastError, WSANOTINITIALISED,
|
||||||
|
WSARecvFrom, WSASendTo, WSASocketW,
|
||||||
};
|
};
|
||||||
use windows::Win32::System::IO::OVERLAPPED;
|
use windows::Win32::System::IO::OVERLAPPED;
|
||||||
|
|
||||||
pub unsafe fn run_eventloop<Ctx: ServersContext>(ctx: *mut Ctx) {
|
pub unsafe fn run_eventloop<Ctx: ServersContext>(ctx: *mut Ctx) {
|
||||||
let mut heap = Allocator::<IoTask<CallbackData<_>>>::new();
|
let mut heap = Allocator::<IoTask<CallbackData<_>>>::new();
|
||||||
|
|
||||||
let socket = WSASocketW(
|
let mut socket = WindowsOverlappingIcmpSocket::new();
|
||||||
AF_UNSPEC.0 as i32,
|
|
||||||
SOCK_RAW.0,
|
|
||||||
IPPROTO_ICMP.0,
|
|
||||||
None,
|
|
||||||
0,
|
|
||||||
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut recv_task = NonNull::from_mut(&mut heap).as_mut().alloc();
|
let mut recv_task = NonNull::from_mut(&mut heap).as_mut().alloc();
|
||||||
let mut in_addr_size = 0i32;
|
CallbackData::init_recv(
|
||||||
let mut in_flags = 0u32;
|
&mut recv_task,
|
||||||
|
NonNull::new_unchecked(ctx),
|
||||||
|
NonNull::from_mut(&mut heap),
|
||||||
|
);
|
||||||
|
socket.receive(&mut recv_task, Some(receiving_done::<Ctx>));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for mut address in (*ctx).iter_servers() {
|
let (id, it) = (*ctx).start_measuring();
|
||||||
let mut data = NonNull::from_mut(&mut heap).as_mut().alloc();
|
|
||||||
data.init(CallbackData {
|
for address in it {
|
||||||
ctx: NonNull::new_unchecked(ctx),
|
let mut task = NonNull::from_mut(&mut heap).as_mut().alloc();
|
||||||
allocator: NonNull::from_mut(&mut heap),
|
CallbackData::init_send(
|
||||||
|
&mut task,
|
||||||
|
NonNull::new_unchecked(ctx),
|
||||||
|
NonNull::from_mut(&mut heap),
|
||||||
address,
|
address,
|
||||||
});
|
|
||||||
|
|
||||||
let overlapped = data.get_overlapped();
|
|
||||||
let address =
|
|
||||||
NonNull::from_ref(&data.get_extra().address.any.native).cast::<SOCKADDR>();
|
|
||||||
WSASendTo(
|
|
||||||
socket,
|
|
||||||
data.as_ref().get_buffer_descriptors(),
|
|
||||||
None,
|
|
||||||
0,
|
|
||||||
Some(address.as_ptr()),
|
|
||||||
size_of::<SOCKADDR_STORAGE>() as i32,
|
|
||||||
Some(overlapped),
|
|
||||||
Some(sending_done::<Ctx>),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let overlapped = recv_task.get_overlapped();
|
socket.send(&mut task, Some(sending_done::<Ctx>));
|
||||||
let address =
|
|
||||||
NonNull::from_mut(&mut recv_task.get_extra().address.any.native).cast::<SOCKADDR>();
|
|
||||||
WSARecvFrom(
|
|
||||||
socket,
|
|
||||||
data.as_ref().get_buffer_descriptors(),
|
|
||||||
None,
|
|
||||||
&mut in_flags,
|
|
||||||
Some(address.as_ptr()),
|
|
||||||
Some(&mut in_addr_size),
|
|
||||||
Some(overlapped),
|
|
||||||
Some(receiving_done::<Ctx>),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,6 +51,38 @@ struct CallbackData<Ctx: ServersContext> {
|
|||||||
ctx: NonNull<Ctx>,
|
ctx: NonNull<Ctx>,
|
||||||
allocator: NonNull<Allocator<IoTask<Self>>>,
|
allocator: NonNull<Allocator<IoTask<Self>>>,
|
||||||
address: WindowsAddressKnown,
|
address: WindowsAddressKnown,
|
||||||
|
__flags: u32,
|
||||||
|
__addrs_size: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Ctx: ServersContext> CallbackData<Ctx> {
|
||||||
|
fn init_send(
|
||||||
|
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
|
||||||
|
ctx: NonNull<Ctx>,
|
||||||
|
allocator: NonNull<Allocator<IoTask<Self>>>,
|
||||||
|
address: WindowsAddressKnown,
|
||||||
|
) {
|
||||||
|
task.init(Self {
|
||||||
|
ctx,
|
||||||
|
allocator,
|
||||||
|
address,
|
||||||
|
__flags: unsafe { uninitialized() },
|
||||||
|
__addrs_size: unsafe { uninitialized() },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn init_recv(
|
||||||
|
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
|
||||||
|
ctx: NonNull<Ctx>,
|
||||||
|
allocator: NonNull<Allocator<IoTask<Self>>>,
|
||||||
|
) {
|
||||||
|
task.init(Self {
|
||||||
|
ctx,
|
||||||
|
allocator,
|
||||||
|
address: unsafe { uninitialized() },
|
||||||
|
__flags: unsafe { uninitialized() },
|
||||||
|
__addrs_size: unsafe { uninitialized() },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn sending_done<Ctx: ServersContext>(
|
unsafe extern "system" fn sending_done<Ctx: ServersContext>(
|
||||||
@ -102,3 +114,122 @@ unsafe extern "system" fn receiving_done<Ctx: ServersContext>(
|
|||||||
);
|
);
|
||||||
task.get_extra().allocator.as_mut().free(task);
|
task.get_extra().allocator.as_mut().free(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WindowsOverlappingIcmpSocket {
|
||||||
|
s: SOCKET,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowsOverlappingIcmpSocket {
|
||||||
|
fn new() -> 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 { s },
|
||||||
|
Err(e) => throw_from_windows_err_code(e.code()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn send<Ctx: ServersContext>(
|
||||||
|
&mut self,
|
||||||
|
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
|
||||||
|
cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
|
||||||
|
) {
|
||||||
|
let overlapped = task.get_overlapped();
|
||||||
|
let address = NonNull::from_ref(&task.get_extra().address.any.native)
|
||||||
|
.cast::<SOCKADDR>()
|
||||||
|
.as_ptr();
|
||||||
|
|
||||||
|
let result = WSASendTo(
|
||||||
|
self.s,
|
||||||
|
task.as_ref().get_buffer_descriptors(),
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
Some(address),
|
||||||
|
size_of::<SOCKADDR_STORAGE>() as i32,
|
||||||
|
Some(overlapped),
|
||||||
|
cb,
|
||||||
|
);
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn receive<Ctx: ServersContext>(
|
||||||
|
&mut self,
|
||||||
|
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
|
||||||
|
cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
|
||||||
|
) {
|
||||||
|
let overlapped = task.get_overlapped();
|
||||||
|
let extra = NonNull::from_ref(task.get_extra()).as_mut();
|
||||||
|
extra.__addrs_size = size_of::<SOCKADDR_STORAGE>() as i32;
|
||||||
|
extra.__flags = 0;
|
||||||
|
let result = WSARecvFrom(
|
||||||
|
self.s,
|
||||||
|
task.as_ref().get_buffer_descriptors(),
|
||||||
|
None,
|
||||||
|
&mut extra.__flags,
|
||||||
|
Some(
|
||||||
|
NonNull::from_mut(&mut extra.address.any.native)
|
||||||
|
.cast::<SOCKADDR>()
|
||||||
|
.as_ptr(),
|
||||||
|
),
|
||||||
|
Some(&mut extra.__addrs_size),
|
||||||
|
Some(overlapped),
|
||||||
|
cb,
|
||||||
|
);
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -18,12 +18,14 @@ pub struct IoTask<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E> IoTask<E> {
|
impl<E> IoTask<E> {
|
||||||
pub unsafe fn init(self: &mut Pin<&mut Self>, extra: E) {
|
pub fn init(self: &mut Pin<&mut Self>, extra: E) {
|
||||||
let self_unwrapped = Pin::into_inner_unchecked(NonNull::from_mut(self).read());
|
unsafe {
|
||||||
self_unwrapped.sys = zeroed();
|
let self_unwrapped = Pin::into_inner_unchecked(NonNull::from_mut(self).read());
|
||||||
self_unwrapped.buff_d[0].len = self_unwrapped.buff.len() as u32;
|
self_unwrapped.sys = zeroed();
|
||||||
self_unwrapped.buff_d[0].buf = PSTR(self_unwrapped.buff.as_mut_ptr());
|
self_unwrapped.buff_d[0].len = self_unwrapped.buff.len() as u32;
|
||||||
self_unwrapped.extra = extra
|
self_unwrapped.buff_d[0].buf = PSTR(self_unwrapped.buff.as_mut_ptr());
|
||||||
|
self_unwrapped.extra = extra
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const BUFFER_LEN: usize = _BUFF_LEN;
|
pub const BUFFER_LEN: usize = _BUFF_LEN;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user