msf_ice/
session.rs

1use std::{
2    net::IpAddr,
3    sync::{Arc, Mutex, MutexGuard},
4};
5
6use crate::{
7    candidate::{CandidateKind, LocalCandidate},
8    AgentRole,
9};
10
11/// Credentials.
12#[derive(Clone)]
13pub struct Credentials {
14    username: String,
15    password: String,
16}
17
18impl Credentials {
19    /// Create random credentials.
20    fn random() -> Self {
21        Self {
22            username: crate::utils::random_ice_string(4),
23            password: crate::utils::random_ice_string(22),
24        }
25    }
26
27    /// Create new credentials.
28    #[inline]
29    pub fn new<U, P>(username: U, password: P) -> Self
30    where
31        U: ToString,
32        P: ToString,
33    {
34        Self {
35            username: username.to_string(),
36            password: password.to_string(),
37        }
38    }
39
40    /// Get the username.
41    #[inline]
42    pub fn username(&self) -> &str {
43        &self.username
44    }
45
46    /// Get the password.
47    #[inline]
48    pub fn password(&self) -> &str {
49        &self.password
50    }
51}
52
53/// ICE session.
54#[derive(Clone)]
55pub struct Session {
56    context: Arc<Mutex<SessionContext>>,
57}
58
59impl Session {
60    /// Create a new ICE session.
61    pub fn new(agent_role: AgentRole, channels: usize) -> Self {
62        Self {
63            context: Arc::new(Mutex::new(SessionContext::new(agent_role, channels))),
64        }
65    }
66
67    /// Lock the session for exclusive access.
68    pub fn lock(&self) -> SessionGuard<'_> {
69        SessionGuard {
70            inner: self.context.lock().unwrap(),
71        }
72    }
73
74    /// Get the current agent role.
75    pub fn get_agent_role(&self) -> AgentRole {
76        self.lock().get_agent_role()
77    }
78
79    /// Set the agent role.
80    pub fn set_agent_role(&self, role: AgentRole) {
81        self.lock().set_agent_role(role)
82    }
83
84    /// Get local credentials.
85    pub fn get_local_credentials(&self, channel: usize) -> Credentials {
86        self.lock().get_local_credentials(channel).clone()
87    }
88
89    /// Get remote credentials.
90    pub fn get_remote_credentials(&self, channel: usize) -> Option<Credentials> {
91        self.lock().get_remote_credentials(channel).cloned()
92    }
93
94    /// Set remote credentials.
95    pub fn set_remote_credentials(&self, channel: usize, credentials: Credentials) {
96        self.lock().set_remote_credentials(channel, credentials)
97    }
98
99    /// Assign a session-wide foundation to a given local candidate.
100    pub fn assign_foundation(
101        &self,
102        candidate: &LocalCandidate,
103        source_addr: Option<IpAddr>,
104    ) -> u32 {
105        self.lock().assign_foundation(candidate, source_addr)
106    }
107}
108
109/// Session lock guard.
110pub struct SessionGuard<'a> {
111    inner: MutexGuard<'a, SessionContext>,
112}
113
114impl SessionGuard<'_> {
115    /// Get the current agent role.
116    pub fn get_agent_role(&self) -> AgentRole {
117        self.inner.agent_role
118    }
119
120    /// Set agent role.
121    pub fn set_agent_role(&mut self, role: AgentRole) {
122        self.inner.agent_role = role;
123    }
124
125    /// Get local credentials.
126    pub fn get_local_credentials(&self, channel: usize) -> &Credentials {
127        let channel = &self.inner.channels[channel];
128
129        channel.get_local_credentials()
130    }
131
132    /// Get remote credentials.
133    pub fn get_remote_credentials(&self, channel: usize) -> Option<&Credentials> {
134        let channel = &self.inner.channels[channel];
135
136        channel.get_remote_credentials()
137    }
138
139    /// Set remote credentials.
140    pub fn set_remote_credentials(&mut self, channel: usize, credentials: Credentials) {
141        let channel = &mut self.inner.channels[channel];
142
143        channel.set_remote_credentials(credentials);
144    }
145
146    /// Get the tie-breaker value.
147    pub fn get_tie_breaker(&self) -> u64 {
148        self.inner.tie_breaker
149    }
150
151    /// Assign a session-wide foundation to a given local candidate.
152    ///
153    /// NOTE: We expect that the transport protocol used for obtaining
154    /// reflexive/relayed candidates is always UDP.
155    pub fn assign_foundation(
156        &mut self,
157        candidate: &LocalCandidate,
158        source_addr: Option<IpAddr>,
159    ) -> u32 {
160        let kind = candidate.kind();
161        let base = candidate.base();
162
163        assert!(kind == CandidateKind::Host || source_addr.is_some());
164
165        let entry = FoundationEntry {
166            candidate_kind: kind,
167            candidate_base: base.ip(),
168            source_addr,
169        };
170
171        let foundation_idx = self.inner.foundations.iter().position(|e| e == &entry);
172
173        if let Some(index) = foundation_idx {
174            index as u32
175        } else {
176            let index = self.inner.foundations.len();
177
178            self.inner.foundations.push(entry);
179
180            index as u32
181        }
182    }
183}
184
185/// Shared session context.
186struct SessionContext {
187    agent_role: AgentRole,
188    tie_breaker: u64,
189    channels: Vec<ChannelContext>,
190    foundations: Vec<FoundationEntry>,
191}
192
193impl SessionContext {
194    /// Create a new session context.
195    fn new(agent_role: AgentRole, channels: usize) -> Self {
196        let channel_count = channels;
197
198        let mut channels = Vec::with_capacity(channel_count);
199
200        channels.resize_with(channel_count, ChannelContext::new);
201
202        Self {
203            agent_role,
204            tie_breaker: rand::random(),
205            channels,
206            foundations: Vec::new(),
207        }
208    }
209}
210
211/// Channel related session context.
212struct ChannelContext {
213    local_credentials: Credentials,
214    remote_credentials: Option<Credentials>,
215}
216
217impl ChannelContext {
218    /// Create a new channel context.
219    fn new() -> Self {
220        Self {
221            local_credentials: Credentials::random(),
222            remote_credentials: None,
223        }
224    }
225
226    /// Get local credentials.
227    fn get_local_credentials(&self) -> &Credentials {
228        &self.local_credentials
229    }
230
231    /// Get remote credentials.
232    fn get_remote_credentials(&self) -> Option<&Credentials> {
233        self.remote_credentials.as_ref()
234    }
235
236    /// Set remote credentials.
237    fn set_remote_credentials(&mut self, credentials: Credentials) {
238        self.remote_credentials = Some(credentials);
239    }
240}
241
242/// Foundation table entry.
243#[derive(Eq, PartialEq)]
244struct FoundationEntry {
245    candidate_kind: CandidateKind,
246    candidate_base: IpAddr,
247    source_addr: Option<IpAddr>,
248}