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