stun_rs/attributes/turn/
requested_transport.rs

1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::common::check_buffer_boundaries;
3use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
4use crate::protocols::{ProtocolNumber, UDP};
5use crate::{Decode, Encode, StunError};
6
7const REQUESTED_TRANSPORT: u16 = 0x0019;
8const REQUESTED_TRANSPORT_SIZE: usize = 4;
9
10// Format of Requested-Transport Attribute
11//  0                   1                   2                   3
12//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
13// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14// |    Protocol   |                    RFFU                       |
15// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
17/// This attribute is used by the client to request a specific transport
18//  protocol for the allocated transport address.
19/// # Examples
20///```rust
21/// # use stun_rs::attributes::turn::RequestedTrasport;
22/// # use stun_rs::protocols;
23/// let attr = RequestedTrasport::from(protocols::UDP);
24/// assert_eq!(attr.protocol(), protocols::UDP);
25///```
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct RequestedTrasport(ProtocolNumber);
28
29impl RequestedTrasport {
30    /// Creates a new attribute.
31    /// # Arguments:
32    /// - `protocol`- The protocol specifies the desired protocol. The code points
33    ///               used in this field are taken from those allowed in the Protocol
34    ///               field in the IPv4 header and the Next Header field in the IPv6
35    ///               header [PROTOCOL-NUMBERS](https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml).
36    ///               This specification only allows the use of code point 17
37    ///               (User Datagram Protocol).
38    pub fn new(protocol: ProtocolNumber) -> Self {
39        Self(protocol)
40    }
41
42    /// Returns the protocol number.
43    pub fn protocol(&self) -> ProtocolNumber {
44        self.0
45    }
46}
47
48impl From<ProtocolNumber> for RequestedTrasport {
49    fn from(value: ProtocolNumber) -> Self {
50        RequestedTrasport(value)
51    }
52}
53
54impl Default for RequestedTrasport {
55    fn default() -> Self {
56        RequestedTrasport(UDP)
57    }
58}
59
60impl DecodeAttributeValue for RequestedTrasport {
61    fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
62        let raw_value = ctx.raw_value();
63        check_buffer_boundaries(raw_value, REQUESTED_TRANSPORT_SIZE)?;
64        Ok((
65            Self(ProtocolNumber::decode(raw_value)?.0),
66            REQUESTED_TRANSPORT_SIZE,
67        ))
68    }
69}
70
71impl EncodeAttributeValue for RequestedTrasport {
72    fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
73        let raw_value = ctx.raw_value_mut();
74        check_buffer_boundaries(raw_value, REQUESTED_TRANSPORT_SIZE)?;
75        let size = self.0.encode(raw_value)?;
76        debug_assert!(
77            size == 1,
78            "Unexpected size of type `ProtocolNumber`, {} != 1",
79            size
80        );
81        // Set reserved 24 bits to zero
82        raw_value[size..REQUESTED_TRANSPORT_SIZE].fill(0x0);
83        Ok(REQUESTED_TRANSPORT_SIZE)
84    }
85}
86
87impl crate::attributes::AsVerifiable for RequestedTrasport {}
88
89stunt_attribute!(RequestedTrasport, REQUESTED_TRANSPORT);
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94    use crate::error::StunErrorType;
95    use crate::protocols;
96    use crate::StunAttribute;
97
98    #[test]
99    fn decode_requested_transport_constructor() {
100        let attr = RequestedTrasport::new(protocols::UDP);
101        assert_eq!(attr.protocol(), protocols::UDP);
102
103        let attr = RequestedTrasport::from(protocols::UDP);
104        assert_eq!(attr.protocol(), protocols::UDP);
105    }
106
107    #[test]
108    fn decode_requested_transport_value() {
109        let dummy_msg = [];
110        let buffer = [];
111        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
112        let result = RequestedTrasport::decode(ctx);
113        assert_eq!(
114            result.expect_err("Error expected"),
115            StunErrorType::SmallBuffer
116        );
117
118        let buffer = [0x11, 0x00, 0x00];
119        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
120        let result = RequestedTrasport::decode(ctx);
121        assert_eq!(
122            result.expect_err("Error expected"),
123            StunErrorType::SmallBuffer
124        );
125
126        let buffer = [0x11, 0x00, 0x00, 0x00];
127        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
128        let (attr, size) =
129            RequestedTrasport::decode(ctx).expect("Can not decode RequestedTrasport");
130        assert_eq!(size, 4);
131        assert_eq!(attr.protocol(), protocols::UDP);
132
133        // Try using protocol number 6 (TCP)
134        let buffer = [0x06, 0x01, 0x02, 0x03];
135        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
136        let (attr, size) =
137            RequestedTrasport::decode(ctx).expect("Can not decode RequestedTrasport");
138        assert_eq!(size, 4);
139        assert_eq!(attr.protocol().as_u8(), 6);
140    }
141
142    #[test]
143    fn encode_requested_transport_value() {
144        let attr = RequestedTrasport::default();
145        let dummy_msg = [];
146
147        let mut buffer = [];
148        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
149        let result = attr.encode(ctx);
150        assert_eq!(
151            result.expect_err("Error expected"),
152            StunErrorType::SmallBuffer
153        );
154
155        let mut buffer: [u8; 3] = [0xFF; 3];
156        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
157        let result = attr.encode(ctx);
158        assert_eq!(
159            result.expect_err("Error expected"),
160            StunErrorType::SmallBuffer
161        );
162
163        let mut buffer: [u8; 4] = [0xFF; 4];
164        let attr = RequestedTrasport::new(protocols::UDP);
165        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
166        let result = attr.encode(ctx);
167        assert_eq!(result, Ok(4));
168        let expected_buffer = [0x11, 0x00, 0x00, 0x00];
169        assert_eq!(&buffer[..], &expected_buffer[..]);
170    }
171
172    #[test]
173    fn requested_transport_stunt_attribute() {
174        let attr = StunAttribute::RequestedTrasport(RequestedTrasport::from(protocols::UDP));
175        assert!(attr.is_requested_trasport());
176        assert!(attr.as_requested_trasport().is_ok());
177        assert!(attr.as_unknown().is_err());
178
179        assert!(attr.attribute_type().is_comprehension_required());
180        assert!(!attr.attribute_type().is_comprehension_optional());
181
182        let dbg_fmt = format!("{:?}", attr);
183        assert_eq!(
184            "RequestedTrasport(RequestedTrasport(ProtocolNumber(17)))",
185            dbg_fmt
186        );
187    }
188}