Windows eventloop draft
This commit is contained in:
parent
170a81ea3c
commit
b2dcd7819a
@ -1,4 +1,6 @@
|
||||
pub trait Address: Sized {
|
||||
use std::hash::Hash;
|
||||
|
||||
pub trait Address: Sized + PartialEq + Hash {
|
||||
fn parse(raw: &str) -> Result<Self, String>;
|
||||
|
||||
fn to_string(self) -> String;
|
||||
|
||||
0
src/io/abstract/context.rs
Normal file
0
src/io/abstract/context.rs
Normal file
@ -1,3 +1,4 @@
|
||||
mod address;
|
||||
mod context;
|
||||
|
||||
pub use address::Address;
|
||||
@ -3,7 +3,7 @@ use std::mem::uninitialized;
|
||||
use std::pin::Pin;
|
||||
use std::ptr;
|
||||
|
||||
pub struct Allocator<T> {
|
||||
pub(super) struct Allocator<T> {
|
||||
map: HashMap<usize, Pin<Box<T>>>,
|
||||
}
|
||||
|
||||
@ -24,4 +24,7 @@ impl<T> Allocator<T> {
|
||||
.unwrap_or_else(|| unreachable!())
|
||||
.as_mut();
|
||||
}
|
||||
|
||||
pub unsafe fn free(&mut self, p: Pin<&mut T>) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
mod windows;
|
||||
mod allocator;
|
||||
pub mod r#abstract;
|
||||
mod allocator;
|
||||
mod windows;
|
||||
mod servers_context;
|
||||
|
||||
pub type Address = windows::WindowsAddressKnown;
|
||||
use allocator::Allocator;
|
||||
7
src/io/servers_context.rs
Normal file
7
src/io/servers_context.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use super::Address;
|
||||
|
||||
pub trait ServersContext {
|
||||
fn iter_servers(&self) -> impl Iterator<Item=Address>;
|
||||
|
||||
fn report_ping(&mut self, addr: Address, ping_ms: u64);
|
||||
}
|
||||
@ -1,19 +1,24 @@
|
||||
use crate::io::r#abstract::Address;
|
||||
use crate::io::windows::errors::{format_windows_err_code_result, throw_from_windows_err_code};
|
||||
use std::ffi::OsString;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem::size_of;
|
||||
use std::mem::zeroed;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::ptr::{copy_nonoverlapping, null, null_mut};
|
||||
use std::ptr;
|
||||
use std::ptr::{copy_nonoverlapping, null, null_mut};
|
||||
use windows::Win32::Networking::WinSock::{
|
||||
ADDRINFOW, AF_INET, AF_INET6, AF_UNSPEC, FreeAddrInfoW, GetAddrInfoW, SOCKADDR_IN,
|
||||
SOCKADDR_IN6, SOCKADDR_STORAGE, WSAAddressToStringW, WSAGetLastError,
|
||||
};
|
||||
use windows::core::{PCWSTR, PWSTR};
|
||||
use windows::Win32::Networking::WinSock::{FreeAddrInfoW, GetAddrInfoW, WSAAddressToStringW, WSAGetLastError, ADDRINFOW, AF_INET, AF_INET6, SOCKADDR_IN, SOCKADDR_IN6, SOCKADDR_STORAGE};
|
||||
|
||||
pub struct WindowsAddress {
|
||||
native: SOCKADDR_STORAGE,
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WindowsAddressAny {
|
||||
pub(super) native: SOCKADDR_STORAGE,
|
||||
}
|
||||
|
||||
impl Address for WindowsAddress {
|
||||
impl Address for WindowsAddressAny {
|
||||
fn parse(raw: &str) -> Result<Self, String> {
|
||||
let encoded = raw.encode_utf16().collect::<Vec<_>>();
|
||||
unsafe {
|
||||
@ -58,7 +63,7 @@ impl Address for WindowsAddress {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for WindowsAddress {
|
||||
impl PartialEq for WindowsAddressAny {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match self.native.ss_family {
|
||||
AF_INET => {
|
||||
@ -75,8 +80,63 @@ impl PartialEq for WindowsAddress {
|
||||
let self_6 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN6>();
|
||||
let other_6 = *ptr::from_ref(&other.native).cast::<SOCKADDR_IN6>();
|
||||
return self_6.sin6_addr.u.Word == other_6.sin6_addr.u.Word;
|
||||
}
|
||||
},
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for WindowsAddressAny {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self.native.ss_family {
|
||||
AF_INET => {
|
||||
state.write_u16(self.native.ss_family.0);
|
||||
unsafe {
|
||||
let self_4 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN>();
|
||||
state.write_u32(self_4.sin_addr.S_un.S_addr);
|
||||
}
|
||||
}
|
||||
AF_INET6 => {
|
||||
state.write_u16(self.native.ss_family.0);
|
||||
unsafe {
|
||||
let self_6 = *ptr::from_ref(&self.native).cast::<SOCKADDR_IN6>();
|
||||
state.write(&self_6.sin6_addr.u.Byte);
|
||||
}
|
||||
}
|
||||
_ => state.write_u16(AF_UNSPEC.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WindowsAddressKnown {
|
||||
pub(super) any: WindowsAddressAny,
|
||||
}
|
||||
|
||||
impl Address for WindowsAddressKnown {
|
||||
fn parse(raw: &str) -> Result<Self, String> {
|
||||
let any = WindowsAddressAny::parse(raw)?;
|
||||
match any.native.ss_family {
|
||||
AF_INET | AF_INET6 => return Result::Ok(Self { any }),
|
||||
_ => return Result::Err("Address resolved to unsupported AF".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(self) -> String {
|
||||
return self.any.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for WindowsAddressKnown {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
return self.any == other.any;
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WindowsAddressKnown {}
|
||||
|
||||
impl Hash for WindowsAddressKnown {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.any.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
104
src/io/windows/eventloop.rs
Normal file
104
src/io/windows/eventloop.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use crate::io::allocator::Allocator;
|
||||
use crate::io::servers_context::ServersContext;
|
||||
use crate::io::windows::task::IoTask;
|
||||
use crate::io::windows::WindowsAddressKnown;
|
||||
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,
|
||||
};
|
||||
use windows::Win32::System::IO::OVERLAPPED;
|
||||
|
||||
pub unsafe fn run_eventloop<Ctx: ServersContext>(ctx: *mut Ctx) {
|
||||
let mut heap = Allocator::<IoTask<CallbackData<_>>>::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 recv_task = NonNull::from_mut(&mut heap).as_mut().alloc();
|
||||
let mut in_addr_size = 0i32;
|
||||
let mut in_flags = 0u32;
|
||||
|
||||
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),
|
||||
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();
|
||||
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>),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CallbackData<Ctx: ServersContext> {
|
||||
ctx: NonNull<Ctx>,
|
||||
allocator: NonNull<Allocator<IoTask<Self>>>,
|
||||
address: WindowsAddressKnown,
|
||||
}
|
||||
|
||||
unsafe extern "system" fn sending_done<Ctx: ServersContext>(
|
||||
dwerror: u32,
|
||||
cbtransferred: u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
dwflags: u32,
|
||||
) {
|
||||
let mut task = Pin::new_unchecked(
|
||||
lpoverlapped
|
||||
.cast::<IoTask<CallbackData<Ctx>>>()
|
||||
.as_mut()
|
||||
.unwrap(),
|
||||
);
|
||||
task.get_extra().allocator.as_mut().free(task);
|
||||
}
|
||||
|
||||
unsafe extern "system" fn receiving_done<Ctx: ServersContext>(
|
||||
dwerror: u32,
|
||||
cbtransferred: u32,
|
||||
lpoverlapped: *mut OVERLAPPED,
|
||||
dwflags: u32,
|
||||
) {
|
||||
let mut task = Pin::new_unchecked(
|
||||
lpoverlapped
|
||||
.cast::<IoTask<CallbackData<Ctx>>>()
|
||||
.as_mut()
|
||||
.unwrap(),
|
||||
);
|
||||
task.get_extra().allocator.as_mut().free(task);
|
||||
}
|
||||
@ -1,2 +1,6 @@
|
||||
mod address;
|
||||
mod errors;
|
||||
mod eventloop;
|
||||
mod task;
|
||||
|
||||
pub use address::{WindowsAddressAny, WindowsAddressKnown};
|
||||
46
src/io/windows/task.rs
Normal file
46
src/io/windows/task.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::marker::PhantomPinned;
|
||||
use std::mem::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;
|
||||
|
||||
const _BUFF_LEN: usize = 100;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IoTask<E> {
|
||||
sys: OVERLAPPED,
|
||||
__pinned: PhantomPinned,
|
||||
buff_d: [WSABUF; 1],
|
||||
buff: [u8; _BUFF_LEN],
|
||||
extra: E,
|
||||
}
|
||||
|
||||
impl<E> IoTask<E> {
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user