1use std::{
2 error::Error,
3 fmt::{self, Display, Formatter},
4 net::SocketAddr,
5};
6
7use crate::AgentRole;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum CandidateKind {
12 Host,
13 ServerReflexive,
14 PeerReflexive,
15 Relayed,
16}
17
18#[derive(Copy, Clone)]
20pub struct LocalCandidate {
21 channel: usize,
22 component: u8,
23 kind: CandidateKind,
24 base: SocketAddr,
25 addr: SocketAddr,
26 foundation: u32,
27 priority: u32,
28}
29
30impl LocalCandidate {
31 #[inline]
34 pub const fn calculate_priority(component: u8, kind: CandidateKind, base: SocketAddr) -> u32 {
35 let type_preference = match kind {
36 CandidateKind::Host => 126,
37 CandidateKind::PeerReflexive => 110,
38 CandidateKind::ServerReflexive => 100,
39 CandidateKind::Relayed => 0,
40 };
41
42 let local_preference = if matches!(base, SocketAddr::V6(_)) {
43 65_535
44 } else {
45 65_534
46 };
47
48 type_preference << 24 | local_preference << 8 | (255 - component as u32)
49 }
50
51 #[inline]
53 pub const fn host(channel: usize, component: u8, addr: SocketAddr) -> Self {
54 Self {
55 channel,
56 component,
57 kind: CandidateKind::Host,
58 base: addr,
59 addr,
60 foundation: 0,
61 priority: Self::calculate_priority(component, CandidateKind::Host, addr),
62 }
63 }
64
65 #[inline]
67 pub const fn server_reflexive(
68 channel: usize,
69 component: u8,
70 base: SocketAddr,
71 addr: SocketAddr,
72 ) -> Self {
73 Self {
74 channel,
75 component,
76 kind: CandidateKind::ServerReflexive,
77 base,
78 addr,
79 foundation: 0,
80 priority: Self::calculate_priority(component, CandidateKind::ServerReflexive, base),
81 }
82 }
83
84 #[inline]
86 pub const fn peer_reflexive(
87 channel: usize,
88 component: u8,
89 base: SocketAddr,
90 addr: SocketAddr,
91 ) -> Self {
92 Self {
93 channel,
94 component,
95 kind: CandidateKind::PeerReflexive,
96 base,
97 addr,
98 foundation: 0,
99 priority: Self::calculate_priority(component, CandidateKind::PeerReflexive, base),
100 }
101 }
102
103 #[inline]
105 pub const fn relayed(channel: usize, component: u8, addr: SocketAddr) -> Self {
106 Self {
110 channel,
111 component,
112 kind: CandidateKind::Relayed,
113 base: addr,
114 addr,
115 foundation: 0,
116 priority: Self::calculate_priority(component, CandidateKind::Relayed, addr),
117 }
118 }
119
120 #[inline]
122 pub fn with_foundation(mut self, foundation: u32) -> Self {
123 self.foundation = foundation;
124 self
125 }
126
127 #[inline]
129 pub fn channel(&self) -> usize {
130 self.channel
131 }
132
133 #[inline]
140 pub fn component(&self) -> u8 {
141 self.component
142 }
143
144 #[inline]
146 pub fn kind(&self) -> CandidateKind {
147 self.kind
148 }
149
150 #[inline]
152 pub fn base(&self) -> SocketAddr {
153 self.base
154 }
155
156 #[inline]
158 pub fn addr(&self) -> SocketAddr {
159 self.addr
160 }
161
162 #[inline]
164 pub fn priority(&self) -> u32 {
165 self.priority
166 }
167
168 #[inline]
170 pub fn foundation(&self) -> u32 {
171 self.foundation
172 }
173}
174
175#[derive(Clone)]
177pub struct RemoteCandidate {
178 channel: usize,
179 component: u8,
180 kind: CandidateKind,
181 addr: SocketAddr,
182 foundation: String,
183 priority: u32,
184}
185
186impl RemoteCandidate {
187 #[inline]
195 pub fn new<T>(
196 channel: usize,
197 component: u8,
198 kind: CandidateKind,
199 addr: SocketAddr,
200 foundation: T,
201 priority: u32,
202 ) -> Self
203 where
204 T: ToString,
205 {
206 Self {
207 channel,
208 component,
209 kind,
210 addr,
211 foundation: foundation.to_string(),
212 priority,
213 }
214 }
215
216 #[inline]
218 pub fn peer_reflexive(channel: usize, component: u8, addr: SocketAddr, priority: u32) -> Self {
219 Self {
220 channel,
221 component,
222 kind: CandidateKind::PeerReflexive,
223 addr,
224 foundation: addr.to_string(),
225 priority,
226 }
227 }
228
229 #[inline]
231 pub fn channel(&self) -> usize {
232 self.channel
233 }
234
235 #[inline]
237 pub fn component(&self) -> u8 {
238 self.component
239 }
240
241 #[inline]
243 pub fn kind(&self) -> CandidateKind {
244 self.kind
245 }
246
247 #[inline]
249 pub fn addr(&self) -> SocketAddr {
250 self.addr
251 }
252
253 #[inline]
255 pub fn priority(&self) -> u32 {
256 self.priority
257 }
258
259 #[inline]
261 pub fn foundation(&self) -> &str {
262 &self.foundation
263 }
264}
265
266#[derive(Clone)]
268pub struct CandidatePair {
269 local: LocalCandidate,
270 remote: RemoteCandidate,
271 foundation: String,
272}
273
274impl CandidatePair {
275 pub fn new(
277 local: LocalCandidate,
278 remote: RemoteCandidate,
279 ) -> Result<Self, InvalidCandidatePair> {
280 if local.channel != remote.channel || local.component != remote.component {
281 return Err(InvalidCandidatePair);
282 }
283
284 let local_addr = local.addr();
285
286 match remote.addr() {
287 SocketAddr::V4(_) if local_addr.is_ipv4() => (),
288 SocketAddr::V6(_) if local_addr.is_ipv6() => (),
289 _ => return Err(InvalidCandidatePair),
290 }
291
292 let foundation = format!("{}:{}", local.foundation(), remote.foundation());
293
294 let res = Self {
295 local,
296 remote,
297 foundation,
298 };
299
300 Ok(res)
301 }
302
303 pub fn local(&self) -> &LocalCandidate {
305 &self.local
306 }
307
308 pub fn remote(&self) -> &RemoteCandidate {
310 &self.remote
311 }
312
313 pub fn priority(&self, local_role: AgentRole) -> u64 {
315 let (g, d) = match local_role {
316 AgentRole::Controlling => (self.local.priority(), self.remote.priority()),
317 AgentRole::Controlled => (self.remote.priority(), self.local.priority()),
318 };
319
320 let min = g.min(d) as u64;
321 let max = g.max(d) as u64;
322
323 (min << 32) + (max << 1) + u64::from(g > d)
324 }
325
326 pub fn component(&self) -> u8 {
328 self.remote.component()
329 }
330
331 pub fn foundation(&self) -> &str {
333 &self.foundation
334 }
335}
336
337#[derive(Debug, Copy, Clone)]
339pub struct InvalidCandidatePair;
340
341impl Display for InvalidCandidatePair {
342 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
343 f.write_str("the given local and remote candidates do not form a pair")
344 }
345}
346
347impl Error for InvalidCandidatePair {}