pub trait UdpDatagrams {
// Required methods
fn try_send(&self, t: &Datagrams<'_>) -> Result<()>;
fn poll_writable(&self, cx: &mut Context<'_>) -> Poll<Result<()>>;
fn poll_recv(
&self,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
meta: &mut [RecvMeta],
) -> Poll<Result<usize>>;
fn local_addr(&self) -> Result<SocketAddr>;
// Provided method
fn caps(&self) -> UdpCaps { ... }
}Expand description
Datagram I/O on a bound socket.
Required Methods§
Sourcefn try_send(&self, t: &Datagrams<'_>) -> Result<()>
fn try_send(&self, t: &Datagrams<'_>) -> Result<()>
Send one Datagrams — which is one syscall and one or more
datagrams, see Datagrams::segment_size.
std::io::ErrorKind::WouldBlock is a real answer, not a failure:
it obliges the caller to call poll_writable
before trying again.
Sourcefn poll_writable(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
fn poll_writable(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
Wait for the socket to become writable.
§Why this is separate from try_send rather than a fused poll_send
A fused poll_send(cx, t) reads better and cannot be implemented
against a QUIC stack. Two reasons, both of which come from the same
place (quinn-0.11.11/src/runtime.rs:44-66):
- a QUIC endpoint has several tasks that may all be waiting to write, and one socket object can store one waker, so the waiting has to be expressible without a datagram in hand;
- the retry after
WouldBlockis driven by the stack’s own pacer, which decides what to send only once the socket is writable.
Both target runtimes provide this natively —
tokio::net::UdpSocket::poll_send_ready and
async_io::Async::poll_writable — so the split costs no
implementation anywhere and buys the one consumer that exists.
Sourcefn poll_recv(
&self,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
meta: &mut [RecvMeta],
) -> Poll<Result<usize>>
fn poll_recv( &self, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta], ) -> Poll<Result<usize>>
Receive into caller-owned buffers, with one metadata slot each.
Not recv_from(&mut [u8]) -> (usize, SocketAddr), for two reasons
that are facts about the wire rather than about taste: a GRO read
returns several datagrams coalesced into one buffer and needs
RecvMeta::stride to split them again, and each read needs its
own RecvMeta::ecn and its own destination address. A recv_from
shape can carry neither, so a capability built on it would silently
drop ECN — see UdpCaps.
Returns the number of meta/bufs slots filled.
fn local_addr(&self) -> Result<SocketAddr>
Provided Methods§
Sourcefn caps(&self) -> UdpCaps
fn caps(&self) -> UdpCaps
Which offloads this socket has.
§Why a method on the socket and not an associated const on the trait
TcpConnect::APPLIES is a const because “does this runtime hand
the whole TcpOpts set to a socket2::Socket” is a fact about the
runtime crate. GSO, GRO and ECN are not: they are cmsg support on
a descriptor on a kernel, and two sockets from the same runtime can
answer differently — quinn-udp’s own unix backend carries “mac and
ios do not support IP_RECVTOS on dual-stack sockets”
(quinn-udp-0.5.15/src/unix.rs:114), i.e. a v4 socket and a
dual-stack v6 socket differ on the same machine in the same process.
A const would be a claim the runtime crate is not in a position to
make.
The default is UdpCaps::NONE, the weakest answer, for the reason
TcpConnect::APPLIES defaults to TcpOptsSupport::NONE: a
default is a claim made by silence and must never be stronger than
the truth.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".