1use stun_types::message::StunParseError;
15
16#[derive(Debug, Copy, Clone)]
18pub struct ChannelData<'a> {
19 id: u16,
20 data: &'a [u8],
21}
22
23impl<'a> ChannelData<'a> {
24 pub fn new(id: u16, data: &'a [u8]) -> Self {
26 Self { id, data }
27 }
28
29 pub fn id(&self) -> u16 {
31 self.id
32 }
33
34 pub fn data(&self) -> &[u8] {
36 self.data
37 }
38
39 pub fn parse(data: &'a [u8]) -> Result<Self, StunParseError> {
53 if data.len() < 4 {
54 return Err(stun_types::message::StunParseError::Truncated {
55 expected: 4,
56 actual: data.len(),
57 });
58 }
59 let id = u16::from_be_bytes([data[0], data[1]]);
60 let len = u16::from_be_bytes([data[2], data[3]]) as usize;
61 if len + 4 > data.len() {
62 return Err(stun_types::message::StunParseError::Truncated {
63 expected: 4 + len,
64 actual: data.len(),
65 });
66 }
67
68 if !(0x4000..=0xFFFE).contains(&id) {
69 return Err(stun_types::message::StunParseError::InvalidAttributeData);
70 }
71
72 Ok(ChannelData {
73 id,
74 data: &data[4..4 + len],
75 })
76 }
77
78 pub fn write_into_unchecked(self, dest: &mut [u8]) -> usize {
82 dest[..2].copy_from_slice(self.id.to_be_bytes().as_ref());
83 dest[2..4].copy_from_slice((self.data.len() as u16).to_be_bytes().as_ref());
84 dest[4..].copy_from_slice(self.data);
85 self.data.len() + 4
86 }
87}
88
89impl std::fmt::Display for ChannelData<'_> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 write!(
92 f,
93 "ChannelData(id: {}, data of {} bytes)",
94 self.id,
95 self.data.len()
96 )
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn channel_data_parse_invalid_id() {
106 let data = [0x00, 0x00, 0x00, 0x00];
107 assert!(matches!(
108 ChannelData::parse(&data),
109 Err(StunParseError::InvalidAttributeData)
110 ));
111 }
112
113 #[test]
114 fn channel_data_parse_empty() {
115 let data = [0x40, 0x00, 0x00, 0x00];
116 let channel = ChannelData::parse(&data).unwrap();
117 assert_eq!(channel.data(), &[]);
118 }
119
120 #[test]
121 fn channel_data_parse_truncated_data() {
122 let data = [0x40, 0x00, 0x00, 0x01];
123 let Err(StunParseError::Truncated { expected, actual }) = ChannelData::parse(&data) else {
124 unreachable!();
125 };
126 assert_eq!(expected, 5);
127 assert_eq!(actual, 4);
128 }
129
130 #[test]
131 fn channel_data_parse_truncated_header() {
132 let data = [0x40, 0x00, 0x00];
133 let Err(StunParseError::Truncated { expected, actual }) = ChannelData::parse(&data) else {
134 unreachable!();
135 };
136 assert_eq!(expected, 4);
137 assert_eq!(actual, 3);
138 }
139}