medea_turn/
chandata.rs

1//! [TURN ChannelData Message][1] implementation.
2//!
3//! [1]: https://tools.ietf.org/html/rfc5766#section-11.4
4
5use derive_more::with_trait::{Display, Error};
6
7use crate::attr::ChannelNumber;
8
9/// [`ChannelData`] message MUST be padded to a multiple of four bytes in order
10/// to ensure the alignment of subsequent messages.
11const PADDING: usize = 4;
12
13/// [Channel Number] field size.
14///
15/// [Channel Number]: https://tools.ietf.org/html/rfc5766#section-11.4
16const NUMBER_SIZE: usize = 2;
17
18/// [Length] field size.
19///
20/// [Length]: https://tools.ietf.org/html/rfc5766#section-11.4
21const LENGTH_SIZE: usize = 2;
22
23/// Representation of [TURN ChannelData Message][1] defined in [RFC 5766].
24///
25/// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
26/// [RFC 5766]: https://tools.ietf.org/html/rfc5766
27#[derive(Debug)]
28pub struct ChannelData {
29    /// Parsed [Channel Number][1].
30    ///
31    /// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
32    number: u16,
33
34    /// Parsed payload.
35    data: Vec<u8>,
36}
37
38impl ChannelData {
39    /// [ChannelData Message][1] header size.
40    ///
41    /// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
42    pub const HEADER_SIZE: usize = LENGTH_SIZE + NUMBER_SIZE;
43
44    /// Checks whether the provided `data` represents a [`ChannelData`] message.
45    #[expect( // false positive
46        clippy::missing_asserts_for_indexing,
47        reason = "length is checked with the first `if` expression",
48    )]
49    pub(crate) fn is_channel_data(data: &[u8]) -> bool {
50        if data.len() < Self::HEADER_SIZE {
51            return false;
52        }
53        let len = usize::from(u16::from_be_bytes([
54            data[NUMBER_SIZE],
55            data[NUMBER_SIZE + 1],
56        ]));
57
58        if len > data[Self::HEADER_SIZE..].len() {
59            return false;
60        }
61
62        ChannelNumber::new(u16::from_be_bytes([data[0], data[1]])).is_ok()
63    }
64
65    /// Decodes the provided `raw` message as a [`ChannelData`] message.
66    ///
67    /// # Errors
68    ///
69    /// See the [`FormatError`] for details.
70    pub(crate) fn decode(mut raw: Vec<u8>) -> Result<Self, FormatError> {
71        if raw.len() < Self::HEADER_SIZE {
72            return Err(FormatError::BadChannelDataLength);
73        }
74
75        let number = u16::from_be_bytes([raw[0], raw[1]]);
76        if ChannelNumber::new(number).is_err() {
77            return Err(FormatError::InvalidChannelNumber);
78        }
79
80        let l = usize::from(u16::from_be_bytes([
81            raw[NUMBER_SIZE],
82            raw[NUMBER_SIZE + 1],
83        ]));
84
85        if l > raw[Self::HEADER_SIZE..].len() {
86            return Err(FormatError::BadChannelDataLength);
87        }
88
89        // Discard header and padding.
90        drop(raw.drain(0..Self::HEADER_SIZE));
91        if l != raw.len() {
92            raw.truncate(l);
93        }
94
95        Ok(Self { data: raw, number })
96    }
97
98    /// Returns payload of this [`ChannelData`] message.
99    pub(crate) fn data(self) -> Vec<u8> {
100        self.data
101    }
102
103    /// Returns [Channel Number][1] of this [`ChannelData`] message.
104    ///
105    /// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
106    pub(crate) const fn num(&self) -> u16 {
107        self.number
108    }
109
110    /// Encodes the provided `buf` and [Channel Number][1] as [`ChannelData`]
111    /// message bytes.
112    ///
113    /// Modifies the provided buffer in place returning the encoded message's
114    /// length.
115    ///
116    /// Also modifies first [`Self::HEADER_SIZE`] bytes of the provided buffer
117    /// with [`ChannelData`] header, so the payload must start right after.
118    ///
119    /// Pads the message, so the provided `buf` must be big enough:
120    /// [`Self::HEADER_SIZE`]` + payload + padding (3 bytes max)`.
121    ///
122    /// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
123    pub(crate) fn encode(
124        buf: &mut [u8],
125        payload_n: usize,
126        chan_num: u16,
127    ) -> Result<usize, FormatError> {
128        let length = Self::HEADER_SIZE + payload_n;
129        let padded_length = nearest_padded_value_length(length);
130        if buf.len() < padded_length {
131            return Err(FormatError::BufferTooShort);
132        }
133
134        #[expect(clippy::map_err_ignore, reason = "useless")]
135        let len = u16::try_from(payload_n)
136            .map_err(|_| FormatError::BadChannelDataLength)?;
137
138        buf[..NUMBER_SIZE].copy_from_slice(&chan_num.to_be_bytes());
139        buf[NUMBER_SIZE..Self::HEADER_SIZE].copy_from_slice(&len.to_be_bytes());
140        buf[length..padded_length].fill(0);
141
142        Ok(padded_length)
143    }
144}
145
146/// Calculates a nearest padded length for a [`ChannelData`] message.
147pub(crate) const fn nearest_padded_value_length(l: usize) -> usize {
148    let mut n = PADDING * (l / PADDING);
149    if n < l {
150        n += PADDING;
151    }
152    n
153}
154
155/// Possible errors of a [`ChannelData`] message format.
156#[derive(Clone, Copy, Debug, Display, Error, Eq, PartialEq)]
157pub enum FormatError {
158    /// [Channel Number][1] is incorrect.
159    ///
160    /// [1]: https://tools.ietf.org/html/rfc5766#section-11.4
161    #[display("Channel Number not in [0x4000, 0x7FFF]")]
162    InvalidChannelNumber,
163
164    /// Incorrect message length.
165    #[display("Invalid `ChannelData` length")]
166    BadChannelDataLength,
167
168    /// Provided buffer is too short.
169    #[display("Provided buffer cannot fit encoded message")]
170    BufferTooShort,
171}
172
173#[cfg(test)]
174mod spec {
175    use super::{ChannelData, FormatError};
176    use crate::attr::ChannelNumber;
177
178    #[test]
179    fn encodes() {
180        let mut buf = [0, 0, 0, 0, 1, 2, 3, 4];
181        let encoded_n =
182            ChannelData::encode(&mut buf, 4, ChannelNumber::MIN + 1).unwrap();
183        assert_eq!(encoded_n, 8);
184        let decoded = ChannelData::decode(buf.to_vec()).unwrap();
185
186        assert!(
187            ChannelData::is_channel_data(&buf[..encoded_n]),
188            "wrong `is_channel_data`",
189        );
190        assert_eq!(vec![1, 2, 3, 4], decoded.data, "wrong decoded data");
191        assert_eq!(ChannelNumber::MIN + 1, decoded.number, "wrong number");
192    }
193
194    #[test]
195    fn encoded_equality() {
196        let tests = [
197            (
198                "equal",
199                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
200                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
201                true,
202            ),
203            (
204                "number",
205                ChannelData {
206                    number: ChannelNumber::MIN + 1,
207                    data: vec![1, 2, 3],
208                },
209                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
210                false,
211            ),
212            (
213                "length",
214                ChannelData {
215                    number: ChannelNumber::MIN,
216                    data: vec![1, 2, 3, 4],
217                },
218                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
219                false,
220            ),
221            (
222                "data",
223                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 2] },
224                ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
225                false,
226            ),
227        ];
228
229        for (name, a, b, r) in tests {
230            let mut a_buf = vec![0; 100];
231            a_buf[ChannelData::HEADER_SIZE
232                ..ChannelData::HEADER_SIZE + a.data.len()]
233                .copy_from_slice(&a.data);
234            let a_enc_len =
235                ChannelData::encode(a_buf.as_mut(), a.data.len(), a.number)
236                    .unwrap();
237
238            let mut b_buf = vec![0; 100];
239            b_buf[ChannelData::HEADER_SIZE
240                ..ChannelData::HEADER_SIZE + b.data.len()]
241                .copy_from_slice(&b.data);
242            let b_enc_len =
243                ChannelData::encode(b_buf.as_mut(), b.data.len(), b.number)
244                    .unwrap();
245
246            let v = a_buf[..a_enc_len] == b_buf[..b_enc_len];
247
248            assert_eq!(v, r, "wrong equality of {name}");
249        }
250    }
251
252    #[test]
253    fn fails_decoding_correctly() {
254        let tests = [
255            ("small", vec![1, 2, 3], FormatError::BadChannelDataLength),
256            (
257                "zeroes",
258                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
259                FormatError::InvalidChannelNumber,
260            ),
261            (
262                "bad chan number",
263                vec![63, 255, 0, 0, 0, 4, 0, 0, 1, 2, 3, 4],
264                FormatError::InvalidChannelNumber,
265            ),
266            (
267                "bad length",
268                vec![0x40, 0x40, 0x02, 0x23, 0x16, 0, 0, 0, 0, 0, 0, 0],
269                FormatError::BadChannelDataLength,
270            ),
271        ];
272        for (name, buf, want_err) in tests {
273            if let Err(e) = ChannelData::decode(buf) {
274                assert_eq!(want_err, e, "wrong error of {name}");
275            } else {
276                panic!("expected `Err`, but got `Ok` in {name}");
277            }
278        }
279    }
280
281    #[test]
282    fn is_channel_data_detects_correctly() {
283        let tests = [
284            ("small", vec![1, 2, 3, 4], false),
285            ("zeroes", vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], false),
286        ];
287        for (name, buf, r) in tests {
288            let v = ChannelData::is_channel_data(&buf);
289
290            assert_eq!(v, r, "wrong result in {name}");
291        }
292    }
293
294    const CHANDATA_TEST_HEX: [&str; 2] = [
295        "40000064000100502112a442453731722f2b322b6e4e7a5800060009443758343a3377\
296         6c59000000c0570004000003e7802a00081d5136dab65b169300250000002400046e00\
297         1eff0008001465d11a330e104a9f5f598af4abc6a805f26003cf802800046b334442",
298        "4000022316fefd0000000000000011012c0b000120000100000000012000011d00011a\
299         308201163081bda003020102020900afe52871340bd13e300a06082a8648ce3d040302\
300         3011310f300d06035504030c06576562525443301e170d313830383131303335323030\
301         5a170d3138303931313033353230305a3011310f300d06035504030c06576562525443\
302         3059301306072a8648ce3d020106082a8648ce3d030107034200048080e348bd41469c\
303         fb7a7df316676fd72a06211765a50a0f0b07526c872dcf80093ed5caa3f5a40a725dd7\
304         4b41b79bdd19ee630c5313c8601d6983286c8722c1300a06082a8648ce3d0403020348\
305         003045022100d13a0a131bc2a9f27abd3d4c547f7ef172996a0c0755c707b6a3e048d8\
306         762ded0220055fc8182818a644a3d3b5b157304cc3f1421fadb06263bfb451cd28be4b\
307         c9ee16fefd0000000000000012002d10000021000200000000002120f7e23c97df45a9\
308         6e13cb3e76b37eff5e73e2aee0b6415d29443d0bd24f578b7e16fefd00000000000000\
309         1300580f00004c000300000000004c040300483046022100fdbb74eab1aca1532e6ac0\
310         ab267d5b83a24bb4d5d7d504936e2785e6e388b2bd022100f6a457b9edd9ead52a9d0e\
311         9a19240b3a68b95699546c044f863cf8349bc8046214fefd0000000000000014000101\
312         16fefd0001000000000004003000010000000000040aae2421e7d549632a7def8ed068\
313         98c3c5b53f5b812a963a39ab6cdd303b79bdb237f3314c1da21b",
314    ];
315
316    #[test]
317    fn chrome_channel_data() {
318        let mut data = vec![];
319        let mut messages = vec![];
320
321        // Decoding HEX data into binary.
322        for h in &CHANDATA_TEST_HEX {
323            let b = match hex::decode(h) {
324                Ok(b) => b,
325                Err(_) => panic!("hex decode error"),
326            };
327            data.push(b);
328        }
329
330        // All HEX streams decoded to raw binary format and stored in the `data`
331        // slice. Decoding packets to messages.
332        for packet in data {
333            let m = ChannelData::decode(packet.clone()).unwrap();
334
335            let mut buf = m.data.clone();
336            let payload_size = m.data.len();
337            // Reserve for header and padding.
338            buf.splice(
339                0..0,
340                std::iter::repeat(0u8).take(ChannelData::HEADER_SIZE),
341            );
342            buf.resize(buf.len() + 3, 0);
343
344            let encoded_len =
345                ChannelData::encode(&mut buf, payload_size, m.number).unwrap();
346            let decoded =
347                ChannelData::decode(buf[..encoded_len].to_vec()).unwrap();
348
349            assert_eq!(m.data, decoded.data, "wrong payload");
350            assert_eq!(m.number, decoded.number, "wrong number");
351
352            messages.push(m);
353        }
354
355        assert_eq!(messages.len(), 2, "wrong number of messages");
356    }
357}