use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6};
#[link(wasm_import_module = "wasi:clocks/monotonic-clock@0.3.0")]
unsafe extern "C" {
#[link_name = "[async-lower]wait-until"]
pub(super) fn deadline(at: u64) -> u32;
}
#[link(wasm_import_module = "wasi:sockets/types@0.3.0")]
unsafe extern "C" {
#[link_name = "[async-lower][method]tcp-socket.connect"]
fn raw_connect(params: *mut u32, result: *mut u32) -> u32;
#[link_name = "[async-lower][method]udp-socket.send"]
fn raw_send(params: *mut u32, result: *mut u32) -> u32;
#[link_name = "[async-lower][method]udp-socket.receive"]
fn raw_receive(socket: u32, result: *mut u32) -> u32;
}
pub fn encode_addr(storage: &mut [u32], addr: SocketAddr) {
storage.fill(0);
let bytes = unsafe { std::slice::from_raw_parts_mut(storage.as_mut_ptr().cast::<u8>(), 32) };
bytes[4..6].copy_from_slice(&addr.port().to_le_bytes());
match addr {
SocketAddr::V4(a) => bytes[6..10].copy_from_slice(&a.ip().octets()),
SocketAddr::V6(a) => {
bytes[0] = 1;
bytes[8..12].copy_from_slice(&a.flowinfo().to_le_bytes());
bytes[28..32].copy_from_slice(&a.scope_id().to_le_bytes());
for (i, s) in a.ip().segments().into_iter().enumerate() {
bytes[12 + i * 2..14 + i * 2].copy_from_slice(&s.to_le_bytes());
}
}
}
}
pub fn decode_addr(storage: &[u32]) -> SocketAddr {
let b = unsafe { std::slice::from_raw_parts(storage.as_ptr().cast::<u8>(), 32) };
let port = u16::from_le_bytes([b[4], b[5]]);
if b[0] == 0 {
(Ipv4Addr::new(b[6], b[7], b[8], b[9]), port).into()
} else {
let segments = std::array::from_fn(|i| u16::from_le_bytes([b[12 + i * 2], b[13 + i * 2]]));
SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::from(segments),
port,
u32::from_le_bytes(b[8..12].try_into().expect("flow")),
u32::from_le_bytes(b[28..32].try_into().expect("scope")),
))
}
}
#[link(wasm_import_module = "env")]
unsafe extern "C" {
fn __wasm_get_stack_pointer() -> u32;
fn __wasm_set_stack_pointer(pointer: u32);
}
pub(super) fn preserving_stack<T>(f: impl FnOnce() -> T) -> T {
let stack = unsafe { __wasm_get_stack_pointer() };
super::return_storage::scoped(|| {
let result = f();
unsafe { __wasm_set_stack_pointer(stack) };
result
})
}
pub(super) unsafe fn connect(params: *mut u32, result: *mut u32) -> u32 {
preserving_stack(|| unsafe { raw_connect(params, result) })
}
pub(super) unsafe fn send(params: *mut u32, result: *mut u32) -> u32 {
preserving_stack(|| unsafe { raw_send(params, result) })
}
pub(super) unsafe fn receive(socket: u32, result: *mut u32) -> u32 {
preserving_stack(|| unsafe { raw_receive(socket, result) })
}