Skip to main content

turn_types/attribute/
fragment.rs

1// Copyright (C) 2025 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// SPDX-License-Identifier: MIT OR Apache-2.0
10
11use stun_types::{attribute::*, message::StunParseError};
12
13/// The [`DontFragment`] [`Attribute`].
14///
15/// Requests that the TURN server produce an allocation that does not fragment UDP packets.
16///
17/// Reference: [RFC5766 Section 14.8](https://datatracker.ietf.org/doc/html/rfc5766#section-14.6).
18#[derive(Default, Debug, Clone)]
19pub struct DontFragment {}
20impl AttributeStaticType for DontFragment {
21    const TYPE: AttributeType = AttributeType::new(0x001A);
22}
23
24impl Attribute for DontFragment {
25    fn get_type(&self) -> AttributeType {
26        Self::TYPE
27    }
28
29    fn length(&self) -> u16 {
30        0
31    }
32}
33
34impl AttributeWrite for DontFragment {
35    fn to_raw(&self) -> RawAttribute<'_> {
36        RawAttribute::new(self.get_type(), &[])
37    }
38    fn write_into_unchecked(&self, dest: &mut [u8]) {
39        self.write_header_unchecked(dest);
40    }
41}
42
43impl AttributeFromRaw<'_> for DontFragment {
44    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
45    where
46        Self: Sized,
47    {
48        Self::try_from(raw)
49    }
50}
51
52impl TryFrom<&RawAttribute<'_>> for DontFragment {
53    type Error = StunParseError;
54    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
55        raw.check_type_and_len(Self::TYPE, 0..=0)?;
56        Ok(Self {})
57    }
58}
59
60impl DontFragment {
61    /// Create a new [`DontFragment`] [`Attribute`].
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// # use turn_types::attribute::*;
67    /// let dont_fragment = DontFragment::new();
68    /// ```
69    pub fn new() -> Self {
70        Self {}
71    }
72}
73
74impl core::fmt::Display for DontFragment {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        write!(f, "{}", self.get_type())
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use alloc::{vec, vec::Vec};
84    use byteorder::{BigEndian, ByteOrder};
85    use tracing::trace;
86
87    #[test]
88    fn dont_fragment() {
89        let _log = crate::tests::test_init_log();
90        let frag = DontFragment::new();
91        assert_eq!(frag.get_type(), DontFragment::TYPE);
92    }
93
94    #[test]
95    fn dont_fragment_raw() {
96        let _log = crate::tests::test_init_log();
97        let frag = DontFragment::new();
98        let raw: RawAttribute = frag.to_raw();
99        trace!("{}", raw);
100        assert_eq!(raw.get_type(), DontFragment::TYPE);
101        let frag2 = DontFragment::try_from(&raw).unwrap();
102        assert_eq!(frag2.get_type(), DontFragment::TYPE);
103    }
104
105    #[test]
106    fn dont_fragment_raw_wrong_type() {
107        let _log = crate::tests::test_init_log();
108        let frag = DontFragment::new();
109        let raw: RawAttribute = frag.to_raw();
110        assert_eq!(raw.get_type(), DontFragment::TYPE);
111        let frag2 = DontFragment::try_from(&raw).unwrap();
112        assert_eq!(frag2.get_type(), DontFragment::TYPE);
113        // provide incorrectly typed data
114        let mut data: Vec<_> = raw.into();
115        BigEndian::write_u16(&mut data[0..2], 0);
116        assert!(matches!(
117            DontFragment::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
118            Err(StunParseError::WrongAttributeImplementation)
119        ));
120    }
121
122    #[test]
123    fn dont_fragment_write_into() {
124        let _log = crate::tests::test_init_log();
125        let frag = DontFragment::new();
126        let raw: RawAttribute = frag.to_raw();
127        let mut dest = vec![0; raw.padded_len()];
128        frag.write_into(&mut dest).unwrap();
129        let raw = RawAttribute::from_bytes(&dest).unwrap();
130        let frag2 = DontFragment::try_from(&raw).unwrap();
131        assert_eq!(frag2.get_type(), DontFragment::TYPE);
132    }
133
134    #[test]
135    #[should_panic = "out of range"]
136    fn dont_fragment_write_into_unchcked() {
137        let _log = crate::tests::test_init_log();
138        let frag = DontFragment::new();
139        let raw: RawAttribute = frag.to_raw();
140        let mut dest = vec![0; raw.padded_len() - 1];
141        frag.write_into_unchecked(&mut dest);
142    }
143}