Skip to main content

trillium_server_common/
udp_transport.rs

1use std::{
2    fmt::Debug,
3    io::{self, ErrorKind},
4    net::{SocketAddr, UdpSocket},
5    task::{Context, Poll},
6};
7
8/// Async UDP socket abstraction for QUIC transport.
9///
10/// Runtime adapters implement this for their platform's async UDP type.
11/// QUIC library adapters (e.g. trillium-quinn) consume this to bridge
12/// to their own socket traits.
13///
14/// The `poll_recv_io` and `try_send_io` methods pass `&Self` to the
15/// caller's closure, allowing the caller to access platform-specific
16/// traits (e.g. `AsFd` on unix, `AsSocket` on windows) without those
17/// traits appearing in this trait's definition.
18///
19/// Runtimes that do not support UDP can use `()` as their
20/// `UdpTransport` type — it returns errors from all operations.
21pub trait UdpTransport: Send + Sync + Debug + Sized + 'static {
22    /// Wrap a bound, non-blocking std UDP socket into this async type.
23    fn from_std(socket: UdpSocket) -> io::Result<Self>;
24
25    /// The local address this socket is bound to.
26    fn local_addr(&self) -> io::Result<SocketAddr>;
27
28    /// Poll for read readiness, then attempt a receive operation.
29    ///
30    /// When the socket is readable, calls `recv` with `&self`. If
31    /// `recv` returns [`ErrorKind::WouldBlock`], the implementation
32    /// clears readiness and re-polls on the next call.
33    fn poll_recv_io<R>(
34        &self,
35        cx: &mut Context<'_>,
36        recv: impl FnMut(&Self) -> io::Result<R>,
37    ) -> Poll<io::Result<R>>;
38
39    /// Poll for write readiness without attempting any I/O.
40    ///
41    /// Used by QUIC implementations that separate readiness polling
42    /// from the send attempt (e.g. quinn's multi-sender pattern).
43    fn poll_writable(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
44
45    /// Attempt a send operation, managing readiness state.
46    ///
47    /// Calls `send` with `&self`. On [`ErrorKind::WouldBlock`], the
48    /// implementation ensures the next [`poll_writable`](UdpTransport::poll_writable)
49    /// call returns [`Poll::Pending`].
50    fn try_send_io<R>(&self, send: impl FnOnce(&Self) -> io::Result<R>) -> io::Result<R>;
51
52    /// Maximum number of datagrams to send in a single syscall (GSO).
53    fn max_transmit_segments(&self) -> usize {
54        1
55    }
56
57    /// Maximum number of datagrams to receive in a single syscall (GRO).
58    fn max_receive_segments(&self) -> usize {
59        1
60    }
61
62    /// Whether outbound datagrams may be fragmented by the network layer.
63    fn may_fragment(&self) -> bool {
64        true
65    }
66}
67
68fn unsupported() -> io::Error {
69    io::Error::new(ErrorKind::Unsupported, "UDP not supported by this runtime")
70}
71
72impl UdpTransport for () {
73    fn from_std(_: UdpSocket) -> io::Result<Self> {
74        Err(unsupported())
75    }
76
77    fn local_addr(&self) -> io::Result<SocketAddr> {
78        Err(unsupported())
79    }
80
81    fn poll_recv_io<R>(
82        &self,
83        _: &mut Context<'_>,
84        _: impl FnMut(&Self) -> io::Result<R>,
85    ) -> Poll<io::Result<R>> {
86        Poll::Ready(Err(unsupported()))
87    }
88
89    fn poll_writable(&self, _: &mut Context<'_>) -> Poll<io::Result<()>> {
90        Poll::Ready(Err(unsupported()))
91    }
92
93    fn try_send_io<R>(&self, _: impl FnOnce(&Self) -> io::Result<R>) -> io::Result<R> {
94        Err(unsupported())
95    }
96}