embassy_net/raw.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//! Raw sockets.
use core::future::poll_fn;
use core::mem;
use core::task::{Context, Poll};
use embassy_net_driver::Driver;
use smoltcp::iface::{Interface, SocketHandle};
use smoltcp::socket::raw;
pub use smoltcp::socket::raw::PacketMetadata;
pub use smoltcp::wire::{IpProtocol, IpVersion};
use crate::Stack;
/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`].
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum RecvError {
/// Provided buffer was smaller than the received packet.
Truncated,
}
/// An Raw socket.
pub struct RawSocket<'a> {
stack: Stack<'a>,
handle: SocketHandle,
}
impl<'a> RawSocket<'a> {
/// Create a new Raw socket using the provided stack and buffers.
pub fn new<D: Driver>(
stack: Stack<'a>,
ip_version: IpVersion,
ip_protocol: IpProtocol,
rx_meta: &'a mut [PacketMetadata],
rx_buffer: &'a mut [u8],
tx_meta: &'a mut [PacketMetadata],
tx_buffer: &'a mut [u8],
) -> Self {
let handle = stack.with_mut(|i| {
let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
i.sockets.add(raw::Socket::new(
ip_version,
ip_protocol,
raw::PacketBuffer::new(rx_meta, rx_buffer),
raw::PacketBuffer::new(tx_meta, tx_buffer),
))
});
Self { stack, handle }
}
fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R {
self.stack.with_mut(|i| {
let socket = i.sockets.get_mut::<raw::Socket>(self.handle);
let res = f(socket, &mut i.iface);
i.waker.wake();
res
})
}
/// Wait until the socket becomes readable.
///
/// A socket is readable when a packet has been received, or when there are queued packets in
/// the buffer.
pub async fn wait_recv_ready(&self) {
poll_fn(move |cx| self.poll_recv_ready(cx)).await
}
/// Receive a datagram.
///
/// This method will wait until a datagram is received.
pub async fn recv(&self, buf: &mut [u8]) -> Result<usize, RecvError> {
poll_fn(move |cx| self.poll_recv(buf, cx)).await
}
/// Wait until a datagram can be read.
///
/// When no datagram is readable, this method will return `Poll::Pending` and
/// register the current task to be notified when a datagram is received.
///
/// When a datagram is received, this method will return `Poll::Ready`.
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
self.with_mut(|s, _| {
if s.can_recv() {
Poll::Ready(())
} else {
// socket buffer is empty wait until at least one byte has arrived
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
}
/// Receive a datagram.
///
/// When no datagram is available, this method will return `Poll::Pending` and
/// register the current task to be notified when a datagram is received.
pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<usize, RecvError>> {
self.with_mut(|s, _| match s.recv_slice(buf) {
Ok(n) => Poll::Ready(Ok(n)),
// No data ready
Err(raw::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)),
Err(raw::RecvError::Exhausted) => {
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
}
/// Wait until the socket becomes writable.
///
/// A socket becomes writable when there is space in the buffer, from initial memory or after
/// dispatching datagrams on a full buffer.
pub async fn wait_send_ready(&self) {
poll_fn(move |cx| self.poll_send_ready(cx)).await
}
/// Wait until a datagram can be sent.
///
/// When no datagram can be sent (i.e. the buffer is full), this method will return
/// `Poll::Pending` and register the current task to be notified when
/// space is freed in the buffer after a datagram has been dispatched.
///
/// When a datagram can be sent, this method will return `Poll::Ready`.
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> {
self.with_mut(|s, _| {
if s.can_send() {
Poll::Ready(())
} else {
// socket buffer is full wait until a datagram has been dispatched
s.register_send_waker(cx.waker());
Poll::Pending
}
})
}
/// Send a datagram.
///
/// This method will wait until the datagram has been sent.`
pub async fn send(&self, buf: &[u8]) {
poll_fn(move |cx| self.poll_send(buf, cx)).await
}
/// Send a datagram.
///
/// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
///
/// When the socket's send buffer is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the buffer has space available.
pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll<()> {
self.with_mut(|s, _| match s.send_slice(buf) {
// Entire datagram has been sent
Ok(()) => Poll::Ready(()),
Err(raw::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
})
}
/// Flush the socket.
///
/// This method will wait until the socket is flushed.
pub async fn flush(&mut self) {
poll_fn(move |cx| {
self.with_mut(|s, _| {
if s.send_queue() == 0 {
Poll::Ready(())
} else {
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
}
}
impl Drop for RawSocket<'_> {
fn drop(&mut self) {
self.stack.with_mut(|i| i.sockets.remove(self.handle));
}
}
fn _assert_covariant<'a, 'b: 'a>(x: RawSocket<'b>) -> RawSocket<'a> {
x
}