1use std::{
2 net::IpAddr,
3 sync::{Arc, Mutex, MutexGuard},
4};
5
6use crate::{
7 candidate::{CandidateKind, LocalCandidate},
8 AgentRole,
9};
10
11#[derive(Clone)]
13pub struct Credentials {
14 username: String,
15 password: String,
16}
17
18impl Credentials {
19 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 #[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 #[inline]
42 pub fn username(&self) -> &str {
43 &self.username
44 }
45
46 #[inline]
48 pub fn password(&self) -> &str {
49 &self.password
50 }
51}
52
53#[derive(Clone)]
55pub struct Session {
56 context: Arc<Mutex<SessionContext>>,
57}
58
59impl Session {
60 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 pub fn lock(&self) -> SessionGuard<'_> {
69 SessionGuard {
70 inner: self.context.lock().unwrap(),
71 }
72 }
73
74 pub fn get_agent_role(&self) -> AgentRole {
76 self.lock().get_agent_role()
77 }
78
79 pub fn set_agent_role(&self, role: AgentRole) {
81 self.lock().set_agent_role(role)
82 }
83
84 pub fn get_local_credentials(&self, channel: usize) -> Credentials {
86 self.lock().get_local_credentials(channel).clone()
87 }
88
89 pub fn get_remote_credentials(&self, channel: usize) -> Option<Credentials> {
91 self.lock().get_remote_credentials(channel).cloned()
92 }
93
94 pub fn set_remote_credentials(&self, channel: usize, credentials: Credentials) {
96 self.lock().set_remote_credentials(channel, credentials)
97 }
98
99 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
109pub struct SessionGuard<'a> {
111 inner: MutexGuard<'a, SessionContext>,
112}
113
114impl SessionGuard<'_> {
115 pub fn get_agent_role(&self) -> AgentRole {
117 self.inner.agent_role
118 }
119
120 pub fn set_agent_role(&mut self, role: AgentRole) {
122 self.inner.agent_role = role;
123 }
124
125 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 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 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 pub fn get_tie_breaker(&self) -> u64 {
148 self.inner.tie_breaker
149 }
150
151 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
185struct SessionContext {
187 agent_role: AgentRole,
188 tie_breaker: u64,
189 channels: Vec<ChannelContext>,
190 foundations: Vec<FoundationEntry>,
191}
192
193impl SessionContext {
194 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
211struct ChannelContext {
213 local_credentials: Credentials,
214 remote_credentials: Option<Credentials>,
215}
216
217impl ChannelContext {
218 fn new() -> Self {
220 Self {
221 local_credentials: Credentials::random(),
222 remote_credentials: None,
223 }
224 }
225
226 fn get_local_credentials(&self) -> &Credentials {
228 &self.local_credentials
229 }
230
231 fn get_remote_credentials(&self) -> Option<&Credentials> {
233 self.remote_credentials.as_ref()
234 }
235
236 fn set_remote_credentials(&mut self, credentials: Credentials) {
238 self.remote_credentials = Some(credentials);
239 }
240}
241
242#[derive(Eq, PartialEq)]
244struct FoundationEntry {
245 candidate_kind: CandidateKind,
246 candidate_base: IpAddr,
247 source_addr: Option<IpAddr>,
248}