use std::{ io::{self, IoSliceMut}, mem::MaybeUninit, sync::Mutex, time::Instant, }; use super::{IO_ERROR_LOG_INTERVAL, RecvMeta, Transmit, UdpSockRef, log_sendmsg_error}; /// UDP socket interface for WASI /// /// `wasi:sockets` exposes none of this crate's advanced features, so they are stubbed out. #[derive(Debug)] pub struct UdpSocketState { last_send_error: Mutex, } impl UdpSocketState { pub fn new(socket: UdpSockRef<'_>) -> io::Result { socket.set_nonblocking(true)?; let now = Instant::now(); Ok(Self { last_send_error: Mutex::new(now.checked_sub(2 * IO_ERROR_LOG_INTERVAL).unwrap_or(now)), }) } /// Sends a [`Transmit`] on the given socket. /// /// This function will only ever return errors of kind [`io::ErrorKind::WouldBlock`]. /// All other errors will be logged and converted to `Ok`. /// /// UDP transmission errors are considered non-fatal because higher-level protocols must /// employ retransmits and timeouts anyway in order to deal with UDP's unreliable nature. /// Thus, logging is most likely the only thing you can do with these errors. /// /// If you would like to handle these errors yourself, use [`UdpSocketState::try_send`] /// instead. #[deprecated(note = "silences I/O errors; use `UdpSocketState::try_send() instead")] pub fn send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { match send(socket, transmit) { Ok(()) => Ok(()), Err(e) if e.kind() == io::ErrorKind::WouldBlock => Err(e), Err(e) => { log_sendmsg_error(&self.last_send_error, e, transmit); Ok(()) } } } /// Sends a [`Transmit`] on the given socket without any additional error handling. pub fn try_send(&self, socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { send(socket, transmit) } pub fn recv( &self, socket: UdpSockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta], ) -> io::Result { // `wasi:sockets` has no vectored receive, and `BATCH_SIZE` is 1 regardless. // Safety: `MaybeUninit` shares the layout of `u8`, and `recv_from` writes only // the prefix it reports as filled. let buf = unsafe { &mut *(&mut *bufs[0] as *mut [u8] as *mut [MaybeUninit]) }; let (len, addr) = socket.0.recv_from(buf)?; meta[0] = RecvMeta { len, stride: len, addr: addr.as_socket().unwrap(), ecn: None, dst_ip: None, interface_index: None, timestamp: None, }; Ok(1) } #[inline] pub fn max_gso_segments(&self) -> usize { 1 } #[inline] pub fn gro_segments(&self) -> usize { 1 } /// Resize the send buffer of `socket` to `bytes` #[inline] pub fn set_send_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { socket.0.set_send_buffer_size(bytes) } /// Resize the receive buffer of `socket` to `bytes` #[inline] pub fn set_recv_buffer_size(&self, socket: UdpSockRef<'_>, bytes: usize) -> io::Result<()> { socket.0.set_recv_buffer_size(bytes) } /// Get the size of the `socket` send buffer #[inline] pub fn send_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result { socket.0.send_buffer_size() } /// Get the size of the `socket` receive buffer #[inline] pub fn recv_buffer_size(&self, socket: UdpSockRef<'_>) -> io::Result { socket.0.recv_buffer_size() } #[inline] pub fn may_fragment(&self) -> bool { true } } fn send(socket: UdpSockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> { socket.0.send_to( transmit.contents, &socket2::SockAddr::from(transmit.destination), )?; Ok(()) } pub(crate) const BATCH_SIZE: usize = 1;