diff --git a/network/windows/Cargo.toml b/network/windows/Cargo.toml index 8279b34..7f8952a 100644 --- a/network/windows/Cargo.toml +++ b/network/windows/Cargo.toml @@ -12,4 +12,4 @@ bgtu-networks-2-network-abstract = { path = "../abstract" } [dependencies.windows] version = ">=0.41.0, <=0.62.2" registry = "crates-io" -features = ["Win32_System_IO", "Win32_Networking", "Win32_Networking_WinSock", "Win32_System_Diagnostics", "Win32_System_Diagnostics_Debug", "Win32_System_Threading", "Win32_System_Memory"] \ No newline at end of file +features = ["Win32_System_IO", "Win32_Networking", "Win32_Networking_WinSock", "Win32_System_Diagnostics", "Win32_System_Diagnostics_Debug", "Win32_System_Threading", "Win32_System_Memory", "Win32_System_SystemInformation"] \ No newline at end of file diff --git a/network/windows/src/eventloop/allocator.rs b/network/windows/src/eventloop/allocator.rs index 7de1894..ec20cc2 100644 --- a/network/windows/src/eventloop/allocator.rs +++ b/network/windows/src/eventloop/allocator.rs @@ -84,7 +84,7 @@ impl Allocator { drop(obj.cast::().read()) } - pub unsafe fn free(&self, p: Pin<&mut T>) { + pub unsafe fn free(&self, p: Pin<&mut T>) { let p = NonNull::from_mut(Pin::into_inner_unchecked(p)); let h = NonNull::new_unchecked( p.as_ptr() diff --git a/network/windows/src/eventloop/mod.rs b/network/windows/src/eventloop/mod.rs index 1071473..21af2e3 100644 --- a/network/windows/src/eventloop/mod.rs +++ b/network/windows/src/eventloop/mod.rs @@ -1,124 +1,100 @@ +mod _allocator_tests; +mod allocator; mod socket; mod task; -mod allocator; -mod _allocator_tests; use socket::WindowsOverlappingIcmpSocket; +use std::ffi::c_void; use crate::address::WindowsAddressKnown; +use crate::errors::format_windows_err_code; use allocator::Allocator; -use task::IoTask; use bgtu_networks_2_network_abstract::ServersContext; -use std::mem::uninitialized; -use std::pin::Pin; use std::ptr::NonNull; -use windows::Win32::System::IO::OVERLAPPED; +use windows::Win32::System::SystemInformation::GetTickCount; use windows::Win32::System::Threading::SleepEx; pub unsafe fn run_eventloop>(ctx: *mut Ctx) { - let mut heap = Allocator::new(); - - let mut socket = WindowsOverlappingIcmpSocket::new(); - - let mut recv_task = NonNull::from_mut(&mut heap).as_mut().alloc(|mut p| CallbackData::init_recv( - &mut p, - NonNull::new_unchecked(ctx), - NonNull::from_mut(&mut heap), - )); - + let heap = Allocator::new(); + let mut socket = WindowsOverlappingIcmpSocket::new(&heap); let mut is_receive_enabled = false; + let recv_callback = RecvCallback { + sock: NonNull::from_mut(&mut socket), + ctx, + }; + loop { let (id, it) = (*ctx).start_measuring(); let mut should_recv_being_enabled = false; for address in it { - let mut task = NonNull::from_mut(&mut heap).as_mut().alloc(|mut p| CallbackData::init_send( - &mut p, - NonNull::new_unchecked(ctx), - NonNull::from_mut(&mut heap), + socket.send( address, - )); - - - socket.send(&mut task, Some(sending_done::)); + |buff| {}, + |err, _| println!("Otpravlena hujnya: {}", format_windows_err_code(err)), + ); should_recv_being_enabled = true; } if (!is_receive_enabled && should_recv_being_enabled) { - socket.receive(&mut recv_task, Some(receiving_done::)); + recv_callback.bind_callback(); is_receive_enabled = true; } - SleepEx(1000, true); + let delayStart = GetTickCount(); + let delayEnd = delayStart.wrapping_add(1000); + loop { + let current = GetTickCount(); + if delayStart < delayEnd { + if current < delayEnd { + SleepEx(delayEnd - current, true); + } else { + break; + } + } else { + if current < delayEnd || current > delayEnd.wrapping_sub(1000) { + SleepEx(delayEnd.wrapping_sub(current), true); + } else { + break; + } + } + } } } -struct CallbackData> { - ctx: NonNull, - allocator: NonNull, - address: WindowsAddressKnown, - __flags: u32, - __addrs_size: i32, +struct RecvCallback<'s, Ctx: ServersContext> { + sock: NonNull>, + ctx: *mut Ctx, } -impl> CallbackData { - fn init_send( - task: &mut Pin<&mut IoTask>>, - ctx: NonNull, - allocator: NonNull, - address: WindowsAddressKnown, +impl<'s, Ctx: ServersContext> RecvCallback<'_, Ctx> { + fn _callback_body( + this_ptr: NonNull, + errcode: u32, + addr: WindowsAddressKnown, + buffer: &[u8], ) { - task.init(Self { - ctx, - allocator, - address, - __flags: unsafe { uninitialized() }, - __addrs_size: unsafe { uninitialized() }, - }); + unsafe { + let this = this_ptr.cast::().as_ref(); + this.bind_callback(); + } } - fn init_recv( - task: &mut Pin<&mut IoTask>>, - ctx: NonNull, - allocator: NonNull, + + // I <3 borrow checker + unsafe fn _bind_callback( + this: NonNull, + sock: NonNull>, + f: fn(NonNull, u32, WindowsAddressKnown, &[u8]), ) { - task.init(Self { - ctx, - allocator, - address: unsafe { uninitialized() }, - __flags: unsafe { uninitialized() }, - __addrs_size: unsafe { uninitialized() }, - }); + sock.as_ref().receive(move |err, addr, buffer| { + (f)(this, err, addr, buffer); + }) + } + + unsafe fn bind_callback(&self) { + let self_ptr = NonNull::from_ref(self); + Self::_bind_callback(self_ptr.cast(), self.sock, Self::_callback_body); } } - -unsafe extern "system" fn sending_done>( - dwerror: u32, - cbtransferred: u32, - lpoverlapped: *mut OVERLAPPED, - dwflags: u32, -) { - let mut task = Pin::new_unchecked( - lpoverlapped - .cast::>>() - .as_mut() - .unwrap(), - ); - task.get_extra().allocator.as_mut().free(task); -} - -unsafe extern "system" fn receiving_done>( - dwerror: u32, - cbtransferred: u32, - lpoverlapped: *mut OVERLAPPED, - dwflags: u32, -) { - let mut task = Pin::new_unchecked( - lpoverlapped - .cast::>>() - .as_mut() - .unwrap(), - ); - task.get_extra().allocator.as_mut().free(task); -} diff --git a/network/windows/src/eventloop/socket.rs b/network/windows/src/eventloop/socket.rs index 3c2193a..bd7148e 100644 --- a/network/windows/src/eventloop/socket.rs +++ b/network/windows/src/eventloop/socket.rs @@ -1,25 +1,30 @@ use crate::address::WindowsAddressKnown; use crate::errors::throw_from_windows_err_code; -use crate::eventloop::CallbackData; +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::{ - 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, + 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, WSAGetLastError, WSANOTINITIALISED, WSARecvFrom, - WSASendTo, WSASocketW, + 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 { - s: SOCKET, +pub(super) struct WindowsOverlappingIcmpSocket<'a> { + socket: SOCKET, + heap: &'a Allocator, } -impl WindowsOverlappingIcmpSocket { - pub fn new() -> Self { + +impl<'a> WindowsOverlappingIcmpSocket<'a> { + pub fn new(heap: &'a Allocator) -> Self { let result = unsafe { WSASocketW( AF_UNSPEC.0 as i32, @@ -32,30 +37,71 @@ impl WindowsOverlappingIcmpSocket { }; match result { - Ok(s) => return Self { s }, + Ok(s) => return Self { socket: s, heap }, Err(e) => throw_from_windows_err_code(e.code()), } } - - pub unsafe fn send>( - &mut self, - task: &mut Pin<&mut IoTask>>, - cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + 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 overlapped = task.get_overlapped(); - let address = NonNull::from_ref(&task.get_extra().address.any.native) - .cast::() - .as_ptr(); + let task = + NonNull::from_mut(IoTask::::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 FnOnce(u32, &'xx [u8], WindowsAddressKnown) + 'static>( + _: &IoTask, + ) -> LPWSAOVERLAPPED_COMPLETION_ROUTINE { + return Some(Self::_native_callback::); + } + + 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.s, - task.as_ref().get_buffer_descriptors(), + self.socket, + &task_p.buff_d, None, 0, - Some(address), + Some(NonNull::from_ref(&task_p.addr).cast().as_ptr()), size_of::() as i32, - Some(overlapped), - cb, + Some(NonNull::from_mut(&mut task_p.sys).as_ptr()), + Self::_gen_native_callback(task_p), ); if result != SOCKET_ERROR { @@ -88,28 +134,37 @@ impl WindowsOverlappingIcmpSocket { } } - pub unsafe fn receive>( - &mut self, - task: &mut Pin<&mut IoTask>>, - cb: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + pub unsafe fn receive( + &self, + on_received: impl for<'xx> FnOnce(u32, WindowsAddressKnown, &'xx [u8]) + 'static, ) { - 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 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::() as i32; + task_p._flags = 0; let result = WSARecvFrom( - self.s, - task.as_ref().get_buffer_descriptors(), + self.socket, + &task_p.buff_d, None, - &mut extra.__flags, + &mut task_p._flags, Some( - NonNull::from_mut(&mut extra.address.any.native) + NonNull::from_mut(&mut task_p.addr.any.native) .cast::() .as_ptr(), ), - Some(&mut extra.__addrs_size), - Some(overlapped), - cb, + Some(&mut task_p._addr_size), + Some(&mut task_p.sys), + Self::_gen_native_callback(task_p), ); if result != SOCKET_ERROR { diff --git a/network/windows/src/eventloop/task.rs b/network/windows/src/eventloop/task.rs index a95ac6f..b90b411 100644 --- a/network/windows/src/eventloop/task.rs +++ b/network/windows/src/eventloop/task.rs @@ -1,54 +1,46 @@ +use crate::eventloop::allocator::Allocator; use std::marker::PhantomPinned; -use std::mem::zeroed; +use std::mem::{offset_of, zeroed}; use std::pin::Pin; use std::ptr::NonNull; use windows::Win32::Networking::WinSock::WSABUF; use windows::Win32::System::IO::OVERLAPPED; use windows::core::PSTR; +use crate::address::WindowsAddressKnown; const _BUFF_LEN: usize = 100; #[repr(C)] -pub struct IoTask { - sys: OVERLAPPED, +pub(super) struct IoTask { + pub sys: OVERLAPPED, __pinned: PhantomPinned, - buff_d: [WSABUF; 1], - buff: [u8; _BUFF_LEN], - extra: E, + pub buff_d: [WSABUF; 1], + pub buff: [u8; _BUFF_LEN], + pub addr: WindowsAddressKnown, + pub heap: NonNull, + pub callback: F, + pub _flags: u32, + pub _addr_size: i32, } -impl IoTask { - pub fn init(self: &mut Pin<&mut Self>, extra: E) { +impl IoTask { + pub unsafe fn init(self: &mut Pin<&mut Self>, heap: NonNull, addr: WindowsAddressKnown, callback: F) { 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 + self_unwrapped.addr = addr; + self_unwrapped.heap = heap; + self_unwrapped.callback = callback; } } - pub const BUFFER_LEN: usize = _BUFF_LEN; - - pub fn get_buffer<'s>(self: &'s mut Pin<&mut Self>) -> &'s mut [u8; _BUFF_LEN] { - return &mut unsafe { Pin::into_inner_unchecked(NonNull::from_mut(self).read()) }.buff; - } - - pub fn get_buffer_descriptors<'s>(self: &'s Pin<&Self>) -> &'s [WSABUF] { - return &unsafe { Pin::into_inner_unchecked(NonNull::from_ref(self).read()) }.buff_d; - } - - pub fn get_extra<'s>(self: &'s mut Pin<&mut Self>) -> &'s mut E { - return &mut unsafe { Pin::into_inner_unchecked(NonNull::from_mut(self).read()) }.extra; - } - - pub fn get_overlapped(self: &mut Pin<&mut Self>) -> *mut OVERLAPPED { - return &mut unsafe { Pin::into_inner_unchecked(NonNull::from_mut(self).read()) }.sys; + pub unsafe fn from_overlapped(raw: *mut OVERLAPPED) -> Pin<&'static mut Self> { + return unsafe { + Pin::new_unchecked( + NonNull::new_unchecked(raw.map_addr(|a| a - offset_of!(Self, sys)).cast()).as_mut(), + ) + }; } } - -impl Drop for IoTask { - fn drop(&mut self) { - todo!() - } -} \ No newline at end of file