stun_types/attribute/
ice.rs

1// Copyright (C) 2020 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 std::convert::TryFrom;
10
11use byteorder::{BigEndian, ByteOrder};
12
13use crate::message::StunParseError;
14
15use super::{
16    Attribute, AttributeStaticType, AttributeType, AttributeWrite, AttributeWriteExt, RawAttribute,
17};
18
19/// The Priority [`Attribute`]
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Priority {
22    priority: u32,
23}
24
25impl AttributeStaticType for Priority {
26    const TYPE: AttributeType = AttributeType(0x0024);
27}
28impl Attribute for Priority {
29    fn get_type(&self) -> AttributeType {
30        Self::TYPE
31    }
32
33    fn length(&self) -> u16 {
34        4
35    }
36}
37impl AttributeWrite for Priority {
38    fn to_raw(&self) -> RawAttribute {
39        let mut buf = [0; 4];
40        BigEndian::write_u32(&mut buf[0..4], self.priority);
41        RawAttribute::new(Priority::TYPE, &buf).into_owned()
42    }
43    fn write_into_unchecked(&self, dest: &mut [u8]) {
44        self.write_header_unchecked(dest);
45        BigEndian::write_u32(&mut dest[4..8], self.priority);
46    }
47}
48impl<'a> TryFrom<&RawAttribute<'a>> for Priority {
49    type Error = StunParseError;
50
51    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
52        raw.check_type_and_len(Self::TYPE, 4..=4)?;
53        Ok(Self {
54            priority: BigEndian::read_u32(&raw.value[..4]),
55        })
56    }
57}
58
59impl Priority {
60    /// Create a new Priority [`Attribute`]
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// # use stun_types::attribute::*;
66    /// let priority = Priority::new(1234);
67    /// assert_eq!(priority.priority(), 1234);
68    /// ```
69    pub fn new(priority: u32) -> Self {
70        Self { priority }
71    }
72
73    /// Retrieve the priority value
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// # use stun_types::attribute::*;
79    /// let priority = Priority::new(1234);
80    /// assert_eq!(priority.priority(), 1234);
81    /// ```
82    pub fn priority(&self) -> u32 {
83        self.priority
84    }
85}
86
87impl std::fmt::Display for Priority {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(f, "{}: {}", Self::TYPE, self.priority)
90    }
91}
92
93/// The UseCandidate [`Attribute`]
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct UseCandidate {}
96
97impl AttributeStaticType for UseCandidate {
98    const TYPE: AttributeType = AttributeType(0x0025);
99}
100impl Attribute for UseCandidate {
101    fn get_type(&self) -> AttributeType {
102        Self::TYPE
103    }
104
105    fn length(&self) -> u16 {
106        0
107    }
108}
109impl AttributeWrite for UseCandidate {
110    fn to_raw(&self) -> RawAttribute {
111        static BUF: [u8; 0] = [0; 0];
112        RawAttribute::new(UseCandidate::TYPE, &BUF)
113    }
114    fn write_into_unchecked(&self, dest: &mut [u8]) {
115        self.write_header_unchecked(dest);
116    }
117}
118impl<'a> TryFrom<&RawAttribute<'a>> for UseCandidate {
119    type Error = StunParseError;
120
121    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
122        raw.check_type_and_len(Self::TYPE, 0..=0)?;
123        Ok(Self {})
124    }
125}
126
127impl Default for UseCandidate {
128    fn default() -> Self {
129        UseCandidate::new()
130    }
131}
132
133impl UseCandidate {
134    /// Create a new UseCandidate [`Attribute`]
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// # use stun_types::attribute::*;
140    /// let _use_candidate = UseCandidate::new();
141    /// ```
142    pub fn new() -> Self {
143        Self {}
144    }
145}
146
147impl std::fmt::Display for UseCandidate {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        write!(f, "{}", Self::TYPE)
150    }
151}
152
153/// The IceControlled [`Attribute`]
154#[derive(Debug, Clone, PartialEq, Eq)]
155pub struct IceControlled {
156    tie_breaker: u64,
157}
158
159impl AttributeStaticType for IceControlled {
160    const TYPE: AttributeType = AttributeType(0x8029);
161}
162impl Attribute for IceControlled {
163    fn get_type(&self) -> AttributeType {
164        Self::TYPE
165    }
166
167    fn length(&self) -> u16 {
168        8
169    }
170}
171impl AttributeWrite for IceControlled {
172    fn to_raw(&self) -> RawAttribute {
173        let mut buf = [0; 8];
174        BigEndian::write_u64(&mut buf[..8], self.tie_breaker);
175        RawAttribute::new(IceControlled::TYPE, &buf).into_owned()
176    }
177    fn write_into_unchecked(&self, dest: &mut [u8]) {
178        self.write_header_unchecked(dest);
179        BigEndian::write_u64(&mut dest[4..12], self.tie_breaker);
180    }
181}
182impl<'a> TryFrom<&RawAttribute<'a>> for IceControlled {
183    type Error = StunParseError;
184
185    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
186        raw.check_type_and_len(Self::TYPE, 8..=8)?;
187        Ok(Self {
188            tie_breaker: BigEndian::read_u64(&raw.value),
189        })
190    }
191}
192
193impl IceControlled {
194    /// Create a new IceControlled [`Attribute`]
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// # use stun_types::attribute::*;
200    /// let ice_controlled = IceControlled::new(1234);
201    /// assert_eq!(ice_controlled.tie_breaker(), 1234);
202    /// ```
203    pub fn new(tie_breaker: u64) -> Self {
204        Self { tie_breaker }
205    }
206
207    /// Retrieve the tie breaker value
208    ///
209    /// # Examples
210    ///
211    /// ```
212    /// # use stun_types::attribute::*;
213    /// let ice_controlled = IceControlled::new(1234);
214    /// assert_eq!(ice_controlled.tie_breaker(), 1234);
215    /// ```
216    pub fn tie_breaker(&self) -> u64 {
217        self.tie_breaker
218    }
219}
220
221impl std::fmt::Display for IceControlled {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        write!(f, "{}", Self::TYPE)
224    }
225}
226
227/// The IceControlling [`Attribute`]
228#[derive(Debug, Clone, PartialEq, Eq)]
229pub struct IceControlling {
230    tie_breaker: u64,
231}
232
233impl AttributeStaticType for IceControlling {
234    const TYPE: AttributeType = AttributeType(0x802A);
235}
236impl Attribute for IceControlling {
237    fn get_type(&self) -> AttributeType {
238        Self::TYPE
239    }
240
241    fn length(&self) -> u16 {
242        8
243    }
244}
245impl AttributeWrite for IceControlling {
246    fn to_raw(&self) -> RawAttribute {
247        let mut buf = [0; 8];
248        BigEndian::write_u64(&mut buf[..8], self.tie_breaker);
249        RawAttribute::new(IceControlling::TYPE, &buf).into_owned()
250    }
251    fn write_into_unchecked(&self, dest: &mut [u8]) {
252        self.write_header_unchecked(dest);
253        BigEndian::write_u64(&mut dest[4..12], self.tie_breaker);
254    }
255}
256impl<'a> TryFrom<&RawAttribute<'a>> for IceControlling {
257    type Error = StunParseError;
258
259    fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
260        raw.check_type_and_len(Self::TYPE, 8..=8)?;
261        Ok(Self {
262            tie_breaker: BigEndian::read_u64(&raw.value),
263        })
264    }
265}
266
267impl IceControlling {
268    /// Create a new IceControlling [`Attribute`]
269    ///
270    /// # Examples
271    ///
272    /// ```
273    /// # use stun_types::attribute::*;
274    /// let ice_controlling = IceControlling::new(1234);
275    /// assert_eq!(ice_controlling.tie_breaker(), 1234);
276    /// ```
277    pub fn new(tie_breaker: u64) -> Self {
278        Self { tie_breaker }
279    }
280
281    /// Create a new IceControlling [`Attribute`]
282    ///
283    /// # Examples
284    ///
285    /// ```
286    /// # use stun_types::attribute::*;
287    /// let ice_controlling = IceControlling::new(1234);
288    /// assert_eq!(ice_controlling.tie_breaker(), 1234);
289    /// ```
290    pub fn tie_breaker(&self) -> u64 {
291        self.tie_breaker
292    }
293}
294
295impl std::fmt::Display for IceControlling {
296    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297        write!(f, "{}", Self::TYPE)
298    }
299}
300
301#[cfg(test)]
302mod tests {
303    use super::*;
304    use tracing::trace;
305
306    #[test]
307    fn priority() {
308        let _log = crate::tests::test_init_log();
309        let val = 100;
310        let priority = Priority::new(val);
311        trace!("{priority}");
312        assert_eq!(priority.priority(), val);
313        assert_eq!(priority.length(), 4);
314        let raw = RawAttribute::from(&priority);
315        trace!("{raw}");
316        assert_eq!(raw.get_type(), Priority::TYPE);
317        let mapped2 = Priority::try_from(&raw).unwrap();
318        assert_eq!(mapped2.priority(), val);
319        // truncate by one byte
320        let mut data: Vec<_> = raw.clone().into();
321        let len = data.len();
322        BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
323        assert!(matches!(
324            Priority::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
325            Err(StunParseError::Truncated {
326                expected: 4,
327                actual: 3
328            })
329        ));
330        // provide incorrectly typed data
331        let mut data: Vec<_> = raw.into();
332        BigEndian::write_u16(&mut data[0..2], 0);
333        assert!(matches!(
334            Priority::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
335            Err(StunParseError::WrongAttributeImplementation)
336        ));
337    }
338
339    #[test]
340    fn use_candidate() {
341        let _log = crate::tests::test_init_log();
342        let use_candidate = UseCandidate::default();
343        trace!("{use_candidate}");
344        assert_eq!(use_candidate.length(), 0);
345        let raw = RawAttribute::from(&use_candidate);
346        trace!("{raw}");
347        assert_eq!(raw.get_type(), UseCandidate::TYPE);
348        let _mapped2 = UseCandidate::try_from(&raw).unwrap();
349        // provide incorrectly typed data
350        let mut data: Vec<_> = raw.into();
351        BigEndian::write_u16(&mut data[0..2], 0);
352        assert!(matches!(
353            UseCandidate::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
354            Err(StunParseError::WrongAttributeImplementation)
355        ));
356    }
357
358    #[test]
359    fn ice_controlling() {
360        let _log = crate::tests::test_init_log();
361        let tb = 100;
362        let attr = IceControlling::new(tb);
363        trace!("{attr}");
364        assert_eq!(attr.tie_breaker(), tb);
365        assert_eq!(attr.length(), 8);
366        let raw = RawAttribute::from(&attr);
367        trace!("{raw}");
368        assert_eq!(raw.get_type(), IceControlling::TYPE);
369        let mapped2 = IceControlling::try_from(&raw).unwrap();
370        assert_eq!(mapped2.tie_breaker(), tb);
371        // truncate by one byte
372        let mut data: Vec<_> = raw.clone().into();
373        let len = data.len();
374        BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
375        assert!(matches!(
376            IceControlling::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
377            Err(StunParseError::Truncated {
378                expected: 8,
379                actual: 7
380            })
381        ));
382        // provide incorrectly typed data
383        let mut data: Vec<_> = raw.into();
384        BigEndian::write_u16(&mut data[0..2], 0);
385        assert!(matches!(
386            IceControlling::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
387            Err(StunParseError::WrongAttributeImplementation)
388        ));
389    }
390
391    #[test]
392    fn ice_controlled() {
393        let _log = crate::tests::test_init_log();
394        let tb = 100;
395        let attr = IceControlled::new(tb);
396        trace!("{attr}");
397        assert_eq!(attr.tie_breaker(), tb);
398        assert_eq!(attr.length(), 8);
399        let raw = RawAttribute::from(&attr);
400        trace!("{raw}");
401        assert_eq!(raw.get_type(), IceControlled::TYPE);
402        let mapped2 = IceControlled::try_from(&raw).unwrap();
403        assert_eq!(mapped2.tie_breaker(), tb);
404        // truncate by one byte
405        let mut data: Vec<_> = raw.clone().into();
406        let len = data.len();
407        BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
408        assert!(matches!(
409            IceControlled::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
410            Err(StunParseError::Truncated {
411                expected: 8,
412                actual: 7
413            })
414        ));
415        // provide incorrectly typed data
416        let mut data: Vec<_> = raw.into();
417        BigEndian::write_u16(&mut data[0..2], 0);
418        assert!(matches!(
419            IceControlled::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
420            Err(StunParseError::WrongAttributeImplementation)
421        ));
422    }
423}