1use stun_types::message::StunParseError;
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19pub struct ChannelData<'a> {
20 id: u16,
21 data: &'a [u8],
22}
23
24impl<'a> ChannelData<'a> {
25 pub fn new(id: u16, data: &'a [u8]) -> Self {
27 Self { id, data }
28 }
29
30 pub fn id(&self) -> u16 {
32 self.id
33 }
34
35 pub fn data(&self) -> &[u8] {
37 self.data
38 }
39
40 pub fn parse(data: &'a [u8]) -> Result<Self, StunParseError> {
54 let (id, len) = Self::parse_header(data)?;
55
56 if len + 4 > data.len() {
57 return Err(stun_types::message::StunParseError::Truncated {
58 expected: 4 + len,
59 actual: data.len(),
60 });
61 }
62
63 Ok(ChannelData {
64 id,
65 data: &data[4..4 + len],
66 })
67 }
68
69 pub fn parse_header(data: &[u8]) -> Result<(u16, usize), StunParseError> {
84 if data.len() < 4 {
85 return Err(stun_types::message::StunParseError::Truncated {
86 expected: 4,
87 actual: data.len(),
88 });
89 }
90 let id = u16::from_be_bytes([data[0], data[1]]);
91 let len = u16::from_be_bytes([data[2], data[3]]) as usize;
92
93 if !(0x4000..=0xFFFE).contains(&id) {
94 return Err(stun_types::message::StunParseError::InvalidAttributeData);
95 }
96
97 Ok((id, len))
98 }
99
100 pub fn write_into_unchecked(self, dest: &mut [u8]) -> usize {
104 dest[..2].copy_from_slice(self.id.to_be_bytes().as_ref());
105 dest[2..4].copy_from_slice((self.data.len() as u16).to_be_bytes().as_ref());
106 dest[4..].copy_from_slice(self.data);
107 self.data.len() + 4
108 }
109}
110
111impl core::fmt::Display for ChannelData<'_> {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113 write!(
114 f,
115 "ChannelData(id: {}, data of {} bytes)",
116 self.id,
117 self.data.len()
118 )
119 }
120}
121
122impl AsRef<[u8]> for ChannelData<'_> {
123 fn as_ref(&self) -> &[u8] {
124 self.data
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn channel_data_parse_invalid_id() {
134 let data = [0x00, 0x00, 0x00, 0x00];
135 assert!(matches!(
136 ChannelData::parse(&data),
137 Err(StunParseError::InvalidAttributeData)
138 ));
139 }
140
141 #[test]
142 fn channel_data_parse_empty() {
143 let data = [0x40, 0x00, 0x00, 0x00];
144 let channel = ChannelData::parse(&data).unwrap();
145 assert_eq!(channel.data(), &[]);
146 }
147
148 #[test]
149 fn channel_data_parse_truncated_data() {
150 let data = [0x40, 0x00, 0x00, 0x01];
151 let Err(StunParseError::Truncated { expected, actual }) = ChannelData::parse(&data) else {
152 unreachable!();
153 };
154 assert_eq!(expected, 5);
155 assert_eq!(actual, 4);
156 assert_eq!(ChannelData::parse_header(&data).unwrap(), (0x4000, 1));
157 }
158
159 #[test]
160 fn channel_data_parse_truncated_header() {
161 let data = [0x40, 0x00, 0x00];
162 let Err(StunParseError::Truncated { expected, actual }) = ChannelData::parse(&data) else {
163 unreachable!();
164 };
165 assert_eq!(expected, 4);
166 assert_eq!(actual, 3);
167 }
168}