diff --git a/src/io/servers_context.rs b/src/io/servers_context.rs index b48f73d..b533023 100644 --- a/src/io/servers_context.rs +++ b/src/io/servers_context.rs @@ -1,7 +1,9 @@ use super::Address; pub trait ServersContext { - fn iter_servers(&self) -> impl Iterator; + fn start_measuring(&mut self) -> (u64, impl Iterator); - fn report_ping(&mut self, addr: Address, ping_ms: u64); -} \ No newline at end of file + fn report_ping(&mut self, addr: Address, id: u64, ping_ms: u64); + + fn report_error(&mut self, addr: Address, id: u64); +} diff --git a/src/io/windows/errors.rs b/src/io/windows/errors.rs index f39cb31..7abba52 100644 --- a/src/io/windows/errors.rs +++ b/src/io/windows/errors.rs @@ -8,7 +8,7 @@ use windows::Win32::System::Diagnostics::Debug::{ FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageA, }; -use windows::core::PSTR; +use windows::core::{HRESULT, PSTR}; trait ErrCode { fn to_dword(&self) -> u32; @@ -16,9 +16,7 @@ trait ErrCode { impl ErrCode for WSA_ERROR { fn to_dword(&self) -> u32 { - return 0u32 - .checked_add_signed(self.0) - .unwrap_or_else(|| panic!("Cast i32 -> u32 overflow")); + return i32::to_dword(&self.0) } } @@ -27,6 +25,19 @@ impl ErrCode for u32 { 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) -> ! { panic!( diff --git a/src/io/windows/eventloop.rs b/src/io/windows/eventloop.rs index 96235b3..61054db 100644 --- a/src/io/windows/eventloop.rs +++ b/src/io/windows/eventloop.rs @@ -1,68 +1,48 @@ use crate::io::allocator::Allocator; use crate::io::servers_context::ServersContext; -use crate::io::windows::task::IoTask; 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::ptr::NonNull; use windows::Win32::Networking::WinSock::{ - WSARecvFrom, WSASendTo, WSASocketW, AF_UNSPEC, IPPROTO_ICMP, SOCKADDR, - SOCKADDR_STORAGE, SOCK_RAW, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, + AF_UNSPEC, IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCK_RAW, SOCKADDR, + 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; pub unsafe fn run_eventloop(ctx: *mut Ctx) { let mut heap = Allocator::>>::new(); - let socket = WSASocketW( - AF_UNSPEC.0 as i32, - SOCK_RAW.0, - IPPROTO_ICMP.0, - None, - 0, - WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT, - ) - .unwrap(); + let mut socket = WindowsOverlappingIcmpSocket::new(); let mut recv_task = NonNull::from_mut(&mut heap).as_mut().alloc(); - let mut in_addr_size = 0i32; - let mut in_flags = 0u32; + CallbackData::init_recv( + &mut recv_task, + NonNull::new_unchecked(ctx), + NonNull::from_mut(&mut heap), + ); + socket.receive(&mut recv_task, Some(receiving_done::)); loop { - for mut address in (*ctx).iter_servers() { - let mut data = NonNull::from_mut(&mut heap).as_mut().alloc(); - data.init(CallbackData { - ctx: NonNull::new_unchecked(ctx), - allocator: NonNull::from_mut(&mut heap), + let (id, it) = (*ctx).start_measuring(); + + for address in it { + let mut task = NonNull::from_mut(&mut heap).as_mut().alloc(); + CallbackData::init_send( + &mut task, + NonNull::new_unchecked(ctx), + NonNull::from_mut(&mut heap), address, - }); - - let overlapped = data.get_overlapped(); - let address = - NonNull::from_ref(&data.get_extra().address.any.native).cast::(); - WSASendTo( - socket, - data.as_ref().get_buffer_descriptors(), - None, - 0, - Some(address.as_ptr()), - size_of::() as i32, - Some(overlapped), - Some(sending_done::), ); - let overlapped = recv_task.get_overlapped(); - let address = - NonNull::from_mut(&mut recv_task.get_extra().address.any.native).cast::(); - 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::), - ); + socket.send(&mut task, Some(sending_done::)); } } } @@ -71,6 +51,38 @@ struct CallbackData { ctx: NonNull, allocator: NonNull>>, address: WindowsAddressKnown, + __flags: u32, + __addrs_size: i32, +} + +impl CallbackData { + fn init_send( + task: &mut Pin<&mut IoTask>>, + ctx: NonNull, + allocator: NonNull>>, + address: WindowsAddressKnown, + ) { + task.init(Self { + ctx, + allocator, + address, + __flags: unsafe { uninitialized() }, + __addrs_size: unsafe { uninitialized() }, + }); + } + fn init_recv( + task: &mut Pin<&mut IoTask>>, + ctx: NonNull, + allocator: NonNull>>, + ) { + task.init(Self { + ctx, + allocator, + address: unsafe { uninitialized() }, + __flags: unsafe { uninitialized() }, + __addrs_size: unsafe { uninitialized() }, + }); + } } unsafe extern "system" fn sending_done( @@ -102,3 +114,122 @@ unsafe extern "system" fn receiving_done( ); 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( + &mut self, + task: &mut Pin<&mut IoTask>>, + cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) { + let overlapped = task.get_overlapped(); + let address = NonNull::from_ref(&task.get_extra().address.any.native) + .cast::() + .as_ptr(); + + let result = WSASendTo( + self.s, + task.as_ref().get_buffer_descriptors(), + None, + 0, + Some(address), + size_of::() 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( + &mut self, + task: &mut Pin<&mut IoTask>>, + cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) { + let overlapped = task.get_overlapped(); + let extra = NonNull::from_ref(task.get_extra()).as_mut(); + extra.__addrs_size = size_of::() 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::() + .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), + } + } +} diff --git a/src/io/windows/task.rs b/src/io/windows/task.rs index 1d8d40e..42bc9c2 100644 --- a/src/io/windows/task.rs +++ b/src/io/windows/task.rs @@ -18,12 +18,14 @@ pub struct IoTask { } impl IoTask { - pub unsafe fn init(self: &mut Pin<&mut Self>, extra: E) { - let self_unwrapped = Pin::into_inner_unchecked(NonNull::from_mut(self).read()); - self_unwrapped.sys = zeroed(); - self_unwrapped.buff_d[0].len = self_unwrapped.buff.len() as u32; - self_unwrapped.buff_d[0].buf = PSTR(self_unwrapped.buff.as_mut_ptr()); - self_unwrapped.extra = extra + pub fn init(self: &mut Pin<&mut Self>, extra: E) { + unsafe { + let self_unwrapped = Pin::into_inner_unchecked(NonNull::from_mut(self).read()); + self_unwrapped.sys = zeroed(); + self_unwrapped.buff_d[0].len = self_unwrapped.buff.len() as u32; + self_unwrapped.buff_d[0].buf = PSTR(self_unwrapped.buff.as_mut_ptr()); + self_unwrapped.extra = extra + } } pub const BUFFER_LEN: usize = _BUFF_LEN;