use core::{
fmt::{Debug, Formatter},
num::NonZeroUsize,
};
use bytes::Bytes;
use netcore::{
DisplayExt, HasChannel, Response, raw,
smoltcp::{
iface::SocketHandle,
wire::{IpProtocol, IpVersion},
},
};
pub struct RawSocket {
handle: SocketHandle,
ip_protocol: IpProtocol,
ip_version: IpVersion,
sender: netcore::Channel,
}
impl Debug for RawSocket {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("UdpSocket")
.field("handle", &self.handle.as_display_debug())
.field("version", &self.ip_version)
.field("proto", &self.ip_protocol)
.finish()
}
}
impl RawSocket {
pub(crate) fn new(
sender: netcore::Channel,
handle: SocketHandle,
ip_protocol: IpProtocol,
ip_version: IpVersion,
) -> Self {
Self {
handle,
ip_protocol,
ip_version,
sender,
}
}
pub fn send_blocking(&self, buf: &[u8]) -> Result<(), netcore::Error> {
self.request_blocking(raw::Command::Send {
buf: Bytes::copy_from_slice(buf),
})?
.to_ok()
}
pub async fn send(&self, buf: &[u8]) -> Result<(), netcore::Error> {
self.request(raw::Command::Send {
buf: Bytes::copy_from_slice(buf),
})
.await?
.to_ok()
}
pub fn recv_blocking(&self, buf: &mut [u8]) -> Result<usize, netcore::Error> {
let len = NonZeroUsize::new(buf.len()).ok_or(netcore::Error::zero_buffer())?;
let resp = self.request_blocking(raw::Command::Recv { max_len: Some(len) })?;
self._recv(buf, resp)
}
pub async fn recv(&self, buf: &mut [u8]) -> Result<usize, netcore::Error> {
let len = NonZeroUsize::new(buf.len()).ok_or(netcore::Error::zero_buffer())?;
let resp = self
.request(raw::Command::Recv { max_len: Some(len) })
.await?;
self._recv(buf, resp)
}
pub fn recv_bytes_blocking(&self) -> Result<Bytes, netcore::Error> {
let resp = self.request_blocking(raw::Command::Recv { max_len: None })?;
self._recv_bytes(resp)
}
pub async fn recv_bytes(&self) -> Result<Bytes, netcore::Error> {
let resp = self.request(raw::Command::Recv { max_len: None }).await?;
self._recv_bytes(resp)
}
fn _recv(&self, buf: &mut [u8], resp: Response) -> Result<usize, netcore::Error> {
let ret_buf = self._recv_bytes(resp)?;
let len = buf.len().min(ret_buf.len());
buf[..len].copy_from_slice(&ret_buf[..len]);
Ok(len)
}
fn _recv_bytes(&self, resp: Response) -> Result<Bytes, netcore::Error> {
netcore::try_response_as!(resp, raw::Response::Recv { buf, truncated });
if let Some(truncated) = truncated {
tracing::warn!(truncated, "packet was truncated");
}
Ok(buf)
}
socket_requestor_impl!();
}
impl Drop for RawSocket {
fn drop(&mut self) {
if let Err(e) = self
.sender
.request_nonblocking(Some(self.handle), raw::Command::Close)
{
tracing::warn!(err = %e, "possible socket leak");
}
}
}