Lambda oriented async socket

This commit is contained in:
Andrew Golovashevich 2026-03-09 01:25:19 +03:00
parent 744ecde879
commit 7f8187a43e
5 changed files with 182 additions and 159 deletions

View File

@ -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"]
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"]

View File

@ -84,7 +84,7 @@ impl Allocator {
drop(obj.cast::<T>().read())
}
pub unsafe fn free<T: Drop>(&self, p: Pin<&mut T>) {
pub unsafe fn free<T>(&self, p: Pin<&mut T>) {
let p = NonNull::from_mut(Pin::into_inner_unchecked(p));
let h = NonNull::new_unchecked(
p.as_ptr()

View File

@ -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: ServersContext<WindowsAddressKnown>>(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::<Ctx>));
|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::<Ctx>));
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: ServersContext<WindowsAddressKnown>> {
ctx: NonNull<Ctx>,
allocator: NonNull<Allocator>,
address: WindowsAddressKnown,
__flags: u32,
__addrs_size: i32,
struct RecvCallback<'s, Ctx: ServersContext<WindowsAddressKnown>> {
sock: NonNull<WindowsOverlappingIcmpSocket<'s>>,
ctx: *mut Ctx,
}
impl<Ctx: ServersContext<WindowsAddressKnown>> CallbackData<Ctx> {
fn init_send(
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
ctx: NonNull<Ctx>,
allocator: NonNull<Allocator>,
address: WindowsAddressKnown,
impl<'s, Ctx: ServersContext<WindowsAddressKnown>> RecvCallback<'_, Ctx> {
fn _callback_body(
this_ptr: NonNull<c_void>,
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::<Self>().as_ref();
this.bind_callback();
}
fn init_recv(
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
ctx: NonNull<Ctx>,
allocator: NonNull<Allocator>,
}
// I <3 borrow checker
unsafe fn _bind_callback(
this: NonNull<c_void>,
sock: NonNull<WindowsOverlappingIcmpSocket<'s>>,
f: fn(NonNull<c_void>, 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<Ctx: ServersContext<WindowsAddressKnown>>(
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<WindowsAddressKnown>>(
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);
}

View File

@ -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<Ctx: ServersContext<WindowsAddressKnown>>(
&mut self,
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
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::<SOCKADDR>()
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.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::<SOCKADDR_STORAGE>() 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<Ctx: ServersContext<WindowsAddressKnown>>(
&mut self,
task: &mut Pin<&mut IoTask<CallbackData<Ctx>>>,
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::<SOCKADDR_STORAGE>() 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::<SOCKADDR_STORAGE>() 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::<SOCKADDR>()
.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 {

View File

@ -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<E> {
sys: OVERLAPPED,
pub(super) struct IoTask<F: 'static> {
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<Allocator>,
pub callback: F,
pub _flags: u32,
pub _addr_size: i32,
}
impl<E> IoTask<E> {
pub fn init(self: &mut Pin<&mut Self>, extra: E) {
impl<F: 'static> IoTask<F> {
pub unsafe fn init(self: &mut Pin<&mut Self>, heap: NonNull<Allocator>, 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;
}
}
impl <E> Drop for IoTask<E> {
fn drop(&mut self) {
todo!()
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(),
)
};
}
}