Skip to main content

UdpDatagrams

Trait UdpDatagrams 

Source
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§

Source

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.

Source

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 WouldBlock is 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.

Source

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.

Source

fn local_addr(&self) -> Result<SocketAddr>

Provided Methods§

Source

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".

Implementors§