turn_types/attribute/
transport.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 RequestedTransport [`Attribute`]
12#[derive(Debug, Clone)]
13pub struct RequestedTransport {
14    protocol: u8,
15}
16
17impl AttributeStaticType for RequestedTransport {
18    const TYPE: AttributeType = AttributeType::new(0x0019);
19}
20
21impl Attribute for RequestedTransport {
22    fn get_type(&self) -> AttributeType {
23        Self::TYPE
24    }
25
26    fn length(&self) -> u16 {
27        4
28    }
29}
30
31impl AttributeWrite for RequestedTransport {
32    fn to_raw(&self) -> RawAttribute {
33        RawAttribute::new(self.get_type(), &[self.protocol, 0, 0, 0]).into_owned()
34    }
35
36    fn write_into_unchecked(&self, dest: &mut [u8]) {
37        self.write_header_unchecked(dest);
38        dest[4] = self.protocol;
39        dest[5] = 0x0;
40        dest[6] = 0x0;
41        dest[7] = 0x0;
42    }
43}
44
45impl AttributeFromRaw<'_> for RequestedTransport {
46    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
47    where
48        Self: Sized,
49    {
50        Self::try_from(raw)
51    }
52}
53
54impl TryFrom<&RawAttribute<'_>> for RequestedTransport {
55    type Error = StunParseError;
56    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
57        raw.check_type_and_len(Self::TYPE, 4..=4)?;
58        Ok(Self {
59            protocol: raw.value[0],
60        })
61    }
62}
63
64impl RequestedTransport {
65    /// The UDP transport type.
66    pub const UDP: u8 = 17;
67
68    /// Create a new RequestedTransport [`Attribute`]
69    ///
70    /// # Examples
71    ///
72    /// ```
73    /// # use turn_types::attribute::*;
74    /// let requested_transport = RequestedTransport::new(RequestedTransport::UDP);
75    /// assert_eq!(requested_transport.protocol(), RequestedTransport::UDP);
76    /// ```
77    pub fn new(protocol: u8) -> Self {
78        Self { protocol }
79    }
80
81    /// Retrieve the protocol stored in a RequestedTransport
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// # use turn_types::attribute::*;
87    /// let requested_transport = RequestedTransport::new(RequestedTransport::UDP);
88    /// assert_eq!(requested_transport.protocol(), RequestedTransport::UDP);
89    /// ```
90    pub fn protocol(&self) -> u8 {
91        self.protocol
92    }
93}
94
95impl std::fmt::Display for RequestedTransport {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        write!(f, "{}: {}", self.get_type(), self.protocol())
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use byteorder::{BigEndian, ByteOrder};
105
106    #[test]
107    fn requested_transport() {
108        let _log = crate::tests::test_init_log();
109        let trans = RequestedTransport::new(17);
110        assert_eq!(trans.get_type(), RequestedTransport::TYPE);
111        assert_eq!(trans.protocol(), 17);
112        let raw: RawAttribute = trans.to_raw();
113        println!("raw: {raw:?}");
114        assert_eq!(raw.get_type(), RequestedTransport::TYPE);
115        let trans2 = RequestedTransport::try_from(&raw).unwrap();
116        assert_eq!(trans2.get_type(), RequestedTransport::TYPE);
117        assert_eq!(trans2.protocol(), 17);
118        // provide incorrectly typed data
119        let mut data: Vec<_> = raw.into();
120        BigEndian::write_u16(&mut data[0..2], 0);
121        assert!(matches!(
122            RequestedTransport::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
123            Err(StunParseError::WrongAttributeImplementation)
124        ));
125        let mut data = [0; 8];
126        trans.write_into(&mut data).unwrap();
127        let raw = RawAttribute::from_bytes(&data).unwrap();
128        let trans2 = RequestedTransport::from_raw_ref(&raw).unwrap();
129        assert_eq!(trans.protocol(), trans2.protocol());
130    }
131}