Skip to main content

tokio_fast_udp/
item.rs

1use std::net::SocketAddr;
2
3use crate::Ecn;
4
5/// A single outbound UDP datagram.
6///
7/// Build with [`SendItem::new`] and optionally chain [`ecn`] / [`segment_size`]
8/// to attach ancillary data.
9///
10/// When [`segment_size`] is set and the platform supports it (Linux GSO), the
11/// kernel will segment `data` into multiple datagrams of `segment_size` bytes
12/// each (the final segment may be shorter). This allows sending N packets in
13/// a single syscall. On platforms without GSO the same datagrams are produced
14/// by splitting `data` in user space.
15///
16/// [`ecn`]: SendItem::ecn
17/// [`segment_size`]: SendItem::segment_size
18#[derive(Clone, Copy)]
19pub struct SendItem<'a> {
20    pub(crate) data: &'a [u8],
21    pub(crate) destination: SocketAddr,
22    pub(crate) ecn: Option<Ecn>,
23    pub(crate) segment_size: Option<u16>,
24}
25
26impl<'a> SendItem<'a> {
27    /// Create a datagram targeting `destination` with the given `data` payload.
28    /// Address comes first, then data.
29    pub fn new(destination: SocketAddr, data: &'a [u8]) -> Self {
30        SendItem {
31            data,
32            destination,
33            ecn: None,
34            segment_size: None,
35        }
36    }
37
38    /// Attach an ECN codepoint to the outgoing datagram.
39    pub fn ecn(mut self, ecn: Ecn) -> Self {
40        self.ecn = Some(ecn);
41        self
42    }
43
44    /// Enable UDP segmentation offload (GSO on Linux). `data` is split into
45    /// consecutive chunks of `segment_size` bytes and each chunk is sent as a
46    /// separate UDP datagram to the same `destination` (the final chunk may be
47    /// shorter).
48    ///
49    /// On Linux with GSO available the kernel performs the segmentation from a
50    /// single `sendmsg`; everywhere else the chunks are emitted as individual
51    /// datagrams in user space.
52    ///
53    /// `segment_size` must be greater than zero: a zero value makes the next
54    /// send fail with [`io::ErrorKind::InvalidInput`].
55    ///
56    /// [`io::ErrorKind::InvalidInput`]: std::io::ErrorKind::InvalidInput
57    pub fn segment_size(mut self, segment_size: u16) -> Self {
58        self.segment_size = Some(segment_size);
59        self
60    }
61}
62
63/// A single inbound UDP datagram slot.
64///
65/// Create with [`ReceiveItem::new`] passing a buffer, then call
66/// [`FastUdpSocket::receive_many`] to fill it. After a successful receive,
67/// [`data`] / [`source`] / [`ecn`] / [`len`] return the received datagram's
68/// metadata.
69///
70/// [`data`]: ReceiveItem::data
71/// [`source`]: ReceiveItem::source
72/// [`ecn`]: ReceiveItem::ecn
73/// [`len`]: ReceiveItem::len
74/// [`FastUdpSocket::receive_many`]: crate::FastUdpSocket::receive_many
75pub struct ReceiveItem<'a> {
76    pub(crate) buf: &'a mut [u8],
77    pub(crate) source: SocketAddr,
78    pub(crate) ecn: Option<Ecn>,
79    pub(crate) len: usize,
80}
81
82impl<'a> ReceiveItem<'a> {
83    /// Create an empty receive slot backed by `buf`.
84    pub fn new(buf: &'a mut [u8]) -> Self {
85        ReceiveItem {
86            buf,
87            source: SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), 0),
88            ecn: None,
89            len: 0,
90        }
91    }
92
93    /// The received payload (first `len` bytes of the internal buffer).
94    pub fn data(&self) -> &[u8] {
95        &self.buf[..self.len]
96    }
97
98    /// The source address of the received datagram.
99    pub fn source(&self) -> SocketAddr {
100        self.source
101    }
102
103    /// The ECN codepoint received with the datagram, if any.
104    pub fn ecn(&self) -> Option<Ecn> {
105        self.ecn
106    }
107
108    /// Number of bytes received.
109    pub fn len(&self) -> usize {
110        self.len
111    }
112
113    /// Whether zero bytes were received.
114    pub fn is_empty(&self) -> bool {
115        self.len == 0
116    }
117}