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
9use stun_types::{attribute::*, message::StunParseError};
10
11/// The [`DontFragment`] [`Attribute`].
12///
13/// Requests that the TURN server produce an allocation that does not fragment UDP packets.
14///
15/// Reference: [RFC5766 Section 14.8](https://datatracker.ietf.org/doc/html/rfc5766#section-14.6).
16#[derive(Default, Debug, Clone)]
17pub struct DontFragment {}
18impl AttributeStaticType for DontFragment {
19    const TYPE: AttributeType = AttributeType::new(0x001A);
20}
21
22impl Attribute for DontFragment {
23    fn get_type(&self) -> AttributeType {
24        Self::TYPE
25    }
26
27    fn length(&self) -> u16 {
28        0
29    }
30}
31
32impl AttributeWrite for DontFragment {
33    fn to_raw(&self) -> RawAttribute<'_> {
34        RawAttribute::new(self.get_type(), &[])
35    }
36    fn write_into_unchecked(&self, dest: &mut [u8]) {
37        self.write_header_unchecked(dest);
38    }
39}
40
41impl AttributeFromRaw<'_> for DontFragment {
42    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
43    where
44        Self: Sized,
45    {
46        Self::try_from(raw)
47    }
48}
49
50impl TryFrom<&RawAttribute<'_>> for DontFragment {
51    type Error = StunParseError;
52    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
53        raw.check_type_and_len(Self::TYPE, 0..=0)?;
54        Ok(Self {})
55    }
56}
57
58impl DontFragment {
59    /// Create a new [`DontFragment`] [`Attribute`].
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// # use turn_types::attribute::*;
65    /// let dont_fragment = DontFragment::new();
66    /// ```
67    pub fn new() -> Self {
68        Self {}
69    }
70}
71
72impl std::fmt::Display for DontFragment {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(f, "{}", self.get_type())
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use byteorder::{BigEndian, ByteOrder};
82
83    #[test]
84    fn dont_fragment() {
85        let _log = crate::tests::test_init_log();
86        let frag = DontFragment::new();
87        assert_eq!(frag.get_type(), DontFragment::TYPE);
88        let raw: RawAttribute = frag.to_raw();
89        println!("{}", raw);
90        assert_eq!(raw.get_type(), DontFragment::TYPE);
91        let frag2 = DontFragment::try_from(&raw).unwrap();
92        assert_eq!(frag2.get_type(), DontFragment::TYPE);
93        // provide incorrectly typed data
94        let mut data: Vec<_> = raw.into();
95        BigEndian::write_u16(&mut data[0..2], 0);
96        assert!(matches!(
97            DontFragment::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
98            Err(StunParseError::WrongAttributeImplementation)
99        ));
100    }
101}