stun_rs/attributes/turn/
even_port.rs

1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::common::check_buffer_boundaries;
3use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
4use crate::StunError;
5
6const EVEN_PORT: u16 = 0x0018;
7const EVEN_PORT_SIZE: usize = 1;
8
9// Format of Even-Port Attribute
10//  0
11//  0 1 2 3 4 5 6 7
12// +-+-+-+-+-+-+-+-+
13// |R|    RFFU     |
14// +-+-+-+-+-+-+-+-+
15
16/// This attribute allows the client to request that the port in the
17/// relayed transport address be even and (optionally) that the server
18/// reserve the next-higher port number.
19/// # Examples
20///```rust
21/// # use stun_rs::attributes::turn::EvenPort;
22/// let attr = EvenPort::new(true);
23/// assert!(attr.reserve());
24///```
25#[derive(Debug, Clone, Default, PartialEq, Eq)]
26pub struct EvenPort(bool);
27
28impl EvenPort {
29    /// Creates a new [`EvenPort`] attribute
30    /// # Arguments:
31    /// `reserve`- true if the server is requested to reserve the next-higher port
32    ///            number (on the same IP address) for a subsequent allocation. False,
33    ///            no such reservation is requested.
34    pub fn new(reserve: bool) -> Self {
35        Self(reserve)
36    }
37
38    /// Indicates whether the server is requested to reserve the next-higher port number
39    /// for a subsequent allocation or not.
40    pub fn reserve(&self) -> bool {
41        self.0
42    }
43}
44
45impl From<bool> for EvenPort {
46    fn from(value: bool) -> Self {
47        EvenPort::new(value)
48    }
49}
50
51impl DecodeAttributeValue for EvenPort {
52    fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
53        let raw_value = ctx.raw_value();
54        check_buffer_boundaries(raw_value, EVEN_PORT_SIZE)?;
55        Ok((Self(raw_value[0] & 0x80 == 0x80), EVEN_PORT_SIZE))
56    }
57}
58
59impl EncodeAttributeValue for EvenPort {
60    fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
61        let raw_value = ctx.raw_value_mut();
62        check_buffer_boundaries(raw_value, EVEN_PORT_SIZE)?;
63        raw_value[0] = if self.0 { 0x80 } else { 0x00 };
64        Ok(EVEN_PORT_SIZE)
65    }
66}
67
68impl crate::attributes::AsVerifiable for EvenPort {}
69
70stunt_attribute!(EvenPort, EVEN_PORT);
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::error::StunErrorType;
75    use crate::StunAttribute;
76
77    #[test]
78    fn even_port_constructor() {
79        let attr = EvenPort::new(true);
80        assert!(attr.reserve());
81
82        let attr = EvenPort::new(false);
83        assert!(!attr.reserve());
84
85        let attr = EvenPort::default();
86        assert!(!attr.reserve());
87
88        let attr = EvenPort::from(true);
89        assert!(attr.reserve());
90
91        let attr = EvenPort::from(false);
92        assert!(!attr.reserve());
93    }
94
95    #[test]
96    fn decode_even_port_value() {
97        let dummy_msg = [];
98        let buffer = [];
99        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
100        let result = EvenPort::decode(ctx);
101        assert_eq!(
102            result.expect_err("Error expected"),
103            StunErrorType::SmallBuffer
104        );
105
106        let buffer = [0x00];
107        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
108        let (attr, size) = EvenPort::decode(ctx).expect("Can not decode EvenPort");
109        assert_eq!(size, 1);
110        assert!(!attr.reserve());
111
112        let buffer = [0x80];
113        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
114        let (attr, size) = EvenPort::decode(ctx).expect("Can not decode EvenPort");
115        assert_eq!(size, 1);
116        assert!(attr.reserve());
117    }
118
119    #[test]
120    fn encode_even_port_value() {
121        let attr = EvenPort::new(true);
122        let dummy_msg = [];
123
124        let mut buffer = [];
125        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
126        let result = attr.encode(ctx);
127        assert_eq!(
128            result.expect_err("Error expected"),
129            StunErrorType::SmallBuffer
130        );
131
132        let mut buffer = [0xFF];
133        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
134        let result = attr.encode(ctx);
135        assert_eq!(result, Ok(1));
136        let expected_buffer = [0x80];
137        assert_eq!(&buffer[..], &expected_buffer[..]);
138
139        let attr = EvenPort::default();
140        let mut buffer = [0xFF];
141        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
142        let result = attr.encode(ctx);
143        assert_eq!(result, Ok(1));
144        let expected_buffer = [0x00];
145        assert_eq!(&buffer[..], &expected_buffer[..]);
146    }
147
148    #[test]
149    fn even_port_stunt_attribute() {
150        let attr = StunAttribute::EvenPort(EvenPort::new(true));
151        assert!(attr.is_even_port());
152        assert!(attr.as_even_port().is_ok());
153        assert!(attr.as_error_code().is_err());
154
155        assert!(attr.attribute_type().is_comprehension_required());
156        assert!(!attr.attribute_type().is_comprehension_optional());
157
158        let dbg_fmt = format!("{:?}", attr);
159        assert_eq!("EvenPort(EvenPort(true))", dbg_fmt);
160    }
161}