Skip to main content

net_wire/udp/
datagram.rs

1//! Checked borrowed UDP datagram views.
2
3use crate::error::ParseError;
4
5pub(super) const HEADER_LENGTH: usize = 8;
6
7/// A structurally validated UDP datagram.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct UdpDatagram<'a> {
10    bytes: &'a [u8],
11}
12
13impl<'a> UdpDatagram<'a> {
14    /// Parses a UDP datagram without checking its checksum.
15    pub fn parse(bytes: &'a [u8]) -> Result<Self, ParseError> {
16        let length = validated_length(bytes)?;
17        Ok(Self {
18            bytes: &bytes[..length],
19        })
20    }
21
22    /// Returns the source port.
23    #[inline]
24    pub fn source_port(&self) -> u16 {
25        u16::from_be_bytes([self.bytes[0], self.bytes[1]])
26    }
27    /// Returns the destination port.
28    #[inline]
29    pub fn destination_port(&self) -> u16 {
30        u16::from_be_bytes([self.bytes[2], self.bytes[3]])
31    }
32    /// Returns the encoded datagram length.
33    #[inline]
34    pub fn length(&self) -> u16 {
35        u16::from_be_bytes([self.bytes[4], self.bytes[5]])
36    }
37    /// Returns the encoded checksum.
38    #[inline]
39    pub fn checksum(&self) -> u16 {
40        u16::from_be_bytes([self.bytes[6], self.bytes[7]])
41    }
42    /// Returns payload bytes.
43    #[inline]
44    pub fn payload(&self) -> &'a [u8] {
45        &self.bytes[HEADER_LENGTH..]
46    }
47    /// Returns all represented datagram bytes.
48    #[inline]
49    pub fn as_bytes(&self) -> &'a [u8] {
50        self.bytes
51    }
52}
53
54/// A mutable structurally validated UDP datagram.
55#[derive(Debug, Eq, PartialEq)]
56pub struct UdpDatagramMut<'a> {
57    bytes: &'a mut [u8],
58}
59
60impl<'a> UdpDatagramMut<'a> {
61    /// Parses a UDP datagram without checking its checksum.
62    pub fn parse(bytes: &'a mut [u8]) -> Result<Self, ParseError> {
63        let length = validated_length(bytes)?;
64        Ok(Self {
65            bytes: &mut bytes[..length],
66        })
67    }
68
69    pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
70        Self { bytes }
71    }
72
73    /// Returns the source port.
74    #[inline]
75    pub fn source_port(&self) -> u16 {
76        u16::from_be_bytes([self.bytes[0], self.bytes[1]])
77    }
78    /// Returns the destination port.
79    #[inline]
80    pub fn destination_port(&self) -> u16 {
81        u16::from_be_bytes([self.bytes[2], self.bytes[3]])
82    }
83    /// Returns the encoded datagram length.
84    #[inline]
85    pub fn length(&self) -> u16 {
86        u16::from_be_bytes([self.bytes[4], self.bytes[5]])
87    }
88    /// Returns the encoded checksum.
89    #[inline]
90    pub fn checksum(&self) -> u16 {
91        u16::from_be_bytes([self.bytes[6], self.bytes[7]])
92    }
93    /// Returns payload bytes.
94    #[inline]
95    pub fn payload(&self) -> &[u8] {
96        &self.bytes[HEADER_LENGTH..]
97    }
98    /// Returns mutable payload bytes without updating the checksum.
99    #[inline]
100    pub fn payload_mut(&mut self) -> &mut [u8] {
101        &mut self.bytes[HEADER_LENGTH..]
102    }
103    /// Returns all represented datagram bytes.
104    #[inline]
105    pub fn as_bytes(&self) -> &[u8] {
106        self.bytes
107    }
108    /// Returns all represented datagram bytes mutably without updating the checksum.
109    #[inline]
110    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
111        self.bytes
112    }
113    /// Replaces the source port without updating the checksum.
114    #[inline]
115    pub fn set_source_port(&mut self, value: u16) {
116        self.bytes[0..2].copy_from_slice(&value.to_be_bytes());
117    }
118    /// Replaces the destination port without updating the checksum.
119    #[inline]
120    pub fn set_destination_port(&mut self, value: u16) {
121        self.bytes[2..4].copy_from_slice(&value.to_be_bytes());
122    }
123    /// Replaces the encoded checksum directly.
124    #[inline]
125    pub fn set_checksum(&mut self, value: u16) {
126        self.bytes[6..8].copy_from_slice(&value.to_be_bytes());
127    }
128}
129
130fn validated_length(bytes: &[u8]) -> Result<usize, ParseError> {
131    if bytes.len() < HEADER_LENGTH {
132        return Err(ParseError::Truncated {
133            minimum: HEADER_LENGTH,
134            available: bytes.len(),
135        });
136    }
137    let length = usize::from(u16::from_be_bytes([bytes[4], bytes[5]]));
138    if length == 0 || length < HEADER_LENGTH {
139        return Err(ParseError::InvalidTotalLength {
140            header_length: HEADER_LENGTH,
141            total_length: length,
142        });
143    }
144    if bytes.len() < length {
145        return Err(ParseError::Truncated {
146            minimum: length,
147            available: bytes.len(),
148        });
149    }
150    Ok(length)
151}