rtc_ice/attributes/control/
mod.rs

1#[cfg(test)]
2mod control_test;
3
4use std::fmt;
5
6use shared::error::*;
7use stun::attributes::*;
8use stun::checks::*;
9use stun::message::*;
10
11/// Common helper for ICE-{CONTROLLED,CONTROLLING} and represents the so-called Tiebreaker number.
12#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
13pub struct TieBreaker(pub u64);
14
15pub(crate) const TIE_BREAKER_SIZE: usize = 8; // 64 bit
16
17impl TieBreaker {
18    /// Adds Tiebreaker value to m as t attribute.
19    pub fn add_to_as(self, m: &mut Message, t: AttrType) -> Result<()> {
20        let mut v = vec![0; TIE_BREAKER_SIZE];
21        v.copy_from_slice(&self.0.to_be_bytes());
22        m.add(t, &v);
23        Ok(())
24    }
25
26    /// Decodes Tiebreaker value in message getting it as for t type.
27    pub fn get_from_as(&mut self, m: &Message, t: AttrType) -> Result<()> {
28        let v = m.get(t)?;
29        check_size(t, v.len(), TIE_BREAKER_SIZE)?;
30        self.0 = u64::from_be_bytes([v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]]);
31        Ok(())
32    }
33}
34/// Represents ICE-CONTROLLED attribute.
35#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
36pub struct AttrControlled(pub u64);
37
38impl Setter for AttrControlled {
39    /// Adds ICE-CONTROLLED to message.
40    fn add_to(&self, m: &mut Message) -> Result<()> {
41        TieBreaker(self.0).add_to_as(m, ATTR_ICE_CONTROLLED)
42    }
43}
44
45impl Getter for AttrControlled {
46    /// Decodes ICE-CONTROLLED from message.
47    fn get_from(&mut self, m: &Message) -> Result<()> {
48        let mut t = TieBreaker::default();
49        t.get_from_as(m, ATTR_ICE_CONTROLLED)?;
50        self.0 = t.0;
51        Ok(())
52    }
53}
54
55/// Represents ICE-CONTROLLING attribute.
56#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
57pub struct AttrControlling(pub u64);
58
59impl Setter for AttrControlling {
60    // add_to adds ICE-CONTROLLING to message.
61    fn add_to(&self, m: &mut Message) -> Result<()> {
62        TieBreaker(self.0).add_to_as(m, ATTR_ICE_CONTROLLING)
63    }
64}
65
66impl Getter for AttrControlling {
67    // get_from decodes ICE-CONTROLLING from message.
68    fn get_from(&mut self, m: &Message) -> Result<()> {
69        let mut t = TieBreaker::default();
70        t.get_from_as(m, ATTR_ICE_CONTROLLING)?;
71        self.0 = t.0;
72        Ok(())
73    }
74}
75
76/// Helper that wraps ICE-{CONTROLLED,CONTROLLING}.
77#[derive(Default, PartialEq, Eq, Debug, Copy, Clone)]
78pub struct AttrControl {
79    role: Role,
80    tie_breaker: TieBreaker,
81}
82
83impl Setter for AttrControl {
84    // add_to adds ICE-CONTROLLED or ICE-CONTROLLING attribute depending on Role.
85    fn add_to(&self, m: &mut Message) -> Result<()> {
86        if self.role == Role::Controlling {
87            self.tie_breaker.add_to_as(m, ATTR_ICE_CONTROLLING)
88        } else {
89            self.tie_breaker.add_to_as(m, ATTR_ICE_CONTROLLED)
90        }
91    }
92}
93
94impl Getter for AttrControl {
95    // get_from decodes Role and Tiebreaker value from message.
96    fn get_from(&mut self, m: &Message) -> Result<()> {
97        if m.contains(ATTR_ICE_CONTROLLING) {
98            self.role = Role::Controlling;
99            return self.tie_breaker.get_from_as(m, ATTR_ICE_CONTROLLING);
100        }
101        if m.contains(ATTR_ICE_CONTROLLED) {
102            self.role = Role::Controlled;
103            return self.tie_breaker.get_from_as(m, ATTR_ICE_CONTROLLED);
104        }
105
106        Err(Error::ErrAttributeNotFound)
107    }
108}
109
110/// Represents ICE agent role, which can be controlling or controlled.
111/// Possible ICE agent roles.
112#[derive(PartialEq, Eq, Copy, Clone, Debug)]
113pub enum Role {
114    Controlling,
115    Controlled,
116    Unspecified,
117}
118
119impl Default for Role {
120    fn default() -> Self {
121        Self::Controlling
122    }
123}
124
125impl From<&str> for Role {
126    fn from(raw: &str) -> Self {
127        match raw {
128            "controlling" => Self::Controlling,
129            "controlled" => Self::Controlled,
130            _ => Self::Unspecified,
131        }
132    }
133}
134
135impl fmt::Display for Role {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        let s = match *self {
138            Self::Controlling => "controlling",
139            Self::Controlled => "controlled",
140            Self::Unspecified => "unspecified",
141        };
142        write!(f, "{s}")
143    }
144}