webrtc_ice/candidate/
mod.rs

1#[cfg(test)]
2mod candidate_pair_test;
3#[cfg(test)]
4mod candidate_relay_test;
5#[cfg(test)]
6mod candidate_server_reflexive_test;
7#[cfg(test)]
8mod candidate_test;
9
10pub mod candidate_base;
11pub mod candidate_host;
12pub mod candidate_peer_reflexive;
13pub mod candidate_relay;
14pub mod candidate_server_reflexive;
15
16use std::fmt;
17use std::net::{IpAddr, SocketAddr};
18use std::sync::atomic::Ordering;
19use std::sync::Arc;
20use std::time::SystemTime;
21
22use async_trait::async_trait;
23use candidate_base::*;
24use portable_atomic::{AtomicBool, AtomicU16, AtomicU8};
25use serde::{Deserialize, Serialize};
26use tokio::sync::{broadcast, Mutex};
27
28use crate::error::Result;
29use crate::network_type::*;
30use crate::tcp_type::*;
31
32pub(crate) const RECEIVE_MTU: usize = 8192;
33pub(crate) const DEFAULT_LOCAL_PREFERENCE: u16 = 65535;
34
35/// Indicates that the candidate is used for RTP.
36pub(crate) const COMPONENT_RTP: u16 = 1;
37/// Indicates that the candidate is used for RTCP.
38pub(crate) const COMPONENT_RTCP: u16 = 0;
39
40/// Candidate represents an ICE candidate
41#[async_trait]
42pub trait Candidate: fmt::Display {
43    /// An arbitrary string used in the freezing algorithm to
44    /// group similar candidates.  It is the same for two candidates that
45    /// have the same type, base IP address, protocol (UDP, TCP, etc.),
46    /// and STUN or TURN server.
47    fn foundation(&self) -> String;
48
49    /// A unique identifier for just this candidate
50    /// Unlike the foundation this is different for each candidate.
51    fn id(&self) -> String;
52
53    /// A component is a piece of a data stream.
54    /// An example is one for RTP, and one for RTCP
55    fn component(&self) -> u16;
56    fn set_component(&self, c: u16);
57
58    /// The last time this candidate received traffic
59    fn last_received(&self) -> SystemTime;
60
61    /// The last time this candidate sent traffic
62    fn last_sent(&self) -> SystemTime;
63
64    fn network_type(&self) -> NetworkType;
65    fn address(&self) -> String;
66    fn port(&self) -> u16;
67
68    fn priority(&self) -> u32;
69
70    /// A transport address related to candidate,
71    /// which is useful for diagnostics and other purposes.
72    fn related_address(&self) -> Option<CandidateRelatedAddress>;
73
74    fn candidate_type(&self) -> CandidateType;
75    fn tcp_type(&self) -> TcpType;
76
77    fn marshal(&self) -> String;
78
79    fn addr(&self) -> SocketAddr;
80
81    async fn close(&self) -> Result<()>;
82    fn seen(&self, outbound: bool);
83
84    async fn write_to(&self, raw: &[u8], dst: &(dyn Candidate + Send + Sync)) -> Result<usize>;
85    fn equal(&self, other: &dyn Candidate) -> bool;
86    fn set_ip(&self, ip: &IpAddr) -> Result<()>;
87    fn get_conn(&self) -> Option<&Arc<dyn util::Conn + Send + Sync>>;
88    fn get_closed_ch(&self) -> Arc<Mutex<Option<broadcast::Sender<()>>>>;
89}
90
91/// Represents the type of candidate `CandidateType` enum.
92#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
93pub enum CandidateType {
94    #[serde(rename = "unspecified")]
95    Unspecified,
96    #[serde(rename = "host")]
97    Host,
98    #[serde(rename = "srflx")]
99    ServerReflexive,
100    #[serde(rename = "prflx")]
101    PeerReflexive,
102    #[serde(rename = "relay")]
103    Relay,
104}
105
106// String makes CandidateType printable
107impl fmt::Display for CandidateType {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        let s = match *self {
110            CandidateType::Host => "host",
111            CandidateType::ServerReflexive => "srflx",
112            CandidateType::PeerReflexive => "prflx",
113            CandidateType::Relay => "relay",
114            CandidateType::Unspecified => "Unknown candidate type",
115        };
116        write!(f, "{s}")
117    }
118}
119
120impl Default for CandidateType {
121    fn default() -> Self {
122        Self::Unspecified
123    }
124}
125
126impl CandidateType {
127    /// Returns the preference weight of a `CandidateType`.
128    ///
129    /// 4.1.2.2.  Guidelines for Choosing Type and Local Preferences
130    /// The RECOMMENDED values are 126 for host candidates, 100
131    /// for server reflexive candidates, 110 for peer reflexive candidates,
132    /// and 0 for relayed candidates.
133    #[must_use]
134    pub const fn preference(self) -> u16 {
135        match self {
136            Self::Host => 126,
137            Self::PeerReflexive => 110,
138            Self::ServerReflexive => 100,
139            Self::Relay | CandidateType::Unspecified => 0,
140        }
141    }
142}
143
144pub(crate) fn contains_candidate_type(
145    candidate_type: CandidateType,
146    candidate_type_list: &[CandidateType],
147) -> bool {
148    if candidate_type_list.is_empty() {
149        return false;
150    }
151    for ct in candidate_type_list {
152        if *ct == candidate_type {
153            return true;
154        }
155    }
156    false
157}
158
159/// Convey transport addresses related to the candidate, useful for diagnostics and other purposes.
160#[derive(PartialEq, Eq, Debug, Clone)]
161pub struct CandidateRelatedAddress {
162    pub address: String,
163    pub port: u16,
164}
165
166// String makes CandidateRelatedAddress printable
167impl fmt::Display for CandidateRelatedAddress {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        write!(f, " related {}:{}", self.address, self.port)
170    }
171}
172
173/// Represent the ICE candidate pair state.
174#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
175pub enum CandidatePairState {
176    #[serde(rename = "unspecified")]
177    Unspecified = 0,
178
179    /// Means a check has not been performed for this pair.
180    #[serde(rename = "waiting")]
181    Waiting = 1,
182
183    /// Means a check has been sent for this pair, but the transaction is in progress.
184    #[serde(rename = "in-progress")]
185    InProgress = 2,
186
187    /// Means a check for this pair was already done and failed, either never producing any response
188    /// or producing an unrecoverable failure response.
189    #[serde(rename = "failed")]
190    Failed = 3,
191
192    /// Means a check for this pair was already done and produced a successful result.
193    #[serde(rename = "succeeded")]
194    Succeeded = 4,
195}
196
197impl From<u8> for CandidatePairState {
198    fn from(v: u8) -> Self {
199        match v {
200            1 => Self::Waiting,
201            2 => Self::InProgress,
202            3 => Self::Failed,
203            4 => Self::Succeeded,
204            _ => Self::Unspecified,
205        }
206    }
207}
208
209impl Default for CandidatePairState {
210    fn default() -> Self {
211        Self::Unspecified
212    }
213}
214
215impl fmt::Display for CandidatePairState {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        let s = match *self {
218            Self::Waiting => "waiting",
219            Self::InProgress => "in-progress",
220            Self::Failed => "failed",
221            Self::Succeeded => "succeeded",
222            Self::Unspecified => "unspecified",
223        };
224
225        write!(f, "{s}")
226    }
227}
228
229/// Represents a combination of a local and remote candidate.
230pub struct CandidatePair {
231    pub(crate) ice_role_controlling: AtomicBool,
232    pub remote: Arc<dyn Candidate + Send + Sync>,
233    pub local: Arc<dyn Candidate + Send + Sync>,
234    pub(crate) binding_request_count: AtomicU16,
235    pub(crate) state: AtomicU8, // convert it to CandidatePairState,
236    pub(crate) nominated: AtomicBool,
237    pub(crate) nominate_on_binding_success: AtomicBool,
238}
239
240impl Default for CandidatePair {
241    fn default() -> Self {
242        Self {
243            ice_role_controlling: AtomicBool::new(false),
244            remote: Arc::new(CandidateBase::default()),
245            local: Arc::new(CandidateBase::default()),
246            state: AtomicU8::new(CandidatePairState::Waiting as u8),
247            binding_request_count: AtomicU16::new(0),
248            nominated: AtomicBool::new(false),
249            nominate_on_binding_success: AtomicBool::new(false),
250        }
251    }
252}
253
254impl fmt::Debug for CandidatePair {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        write!(
257            f,
258            "prio {} (local, prio {}) {} <-> {} (remote, prio {})",
259            self.priority(),
260            self.local.priority(),
261            self.local,
262            self.remote,
263            self.remote.priority()
264        )
265    }
266}
267
268impl fmt::Display for CandidatePair {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        write!(
271            f,
272            "prio {} (local, prio {}) {} <-> {} (remote, prio {})",
273            self.priority(),
274            self.local.priority(),
275            self.local,
276            self.remote,
277            self.remote.priority()
278        )
279    }
280}
281
282impl PartialEq for CandidatePair {
283    fn eq(&self, other: &Self) -> bool {
284        self.local.equal(&*other.local) && self.remote.equal(&*other.remote)
285    }
286}
287
288impl CandidatePair {
289    #[must_use]
290    pub fn new(
291        local: Arc<dyn Candidate + Send + Sync>,
292        remote: Arc<dyn Candidate + Send + Sync>,
293        controlling: bool,
294    ) -> Self {
295        Self {
296            ice_role_controlling: AtomicBool::new(controlling),
297            remote,
298            local,
299            state: AtomicU8::new(CandidatePairState::Waiting as u8),
300            binding_request_count: AtomicU16::new(0),
301            nominated: AtomicBool::new(false),
302            nominate_on_binding_success: AtomicBool::new(false),
303        }
304    }
305
306    /// RFC 5245 - 5.7.2.  Computing Pair Priority and Ordering Pairs
307    /// Let G be the priority for the candidate provided by the controlling
308    /// agent.  Let D be the priority for the candidate provided by the
309    /// controlled agent.
310    /// pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
311    pub fn priority(&self) -> u64 {
312        let (g, d) = if self.ice_role_controlling.load(Ordering::SeqCst) {
313            (self.local.priority(), self.remote.priority())
314        } else {
315            (self.remote.priority(), self.local.priority())
316        };
317
318        // 1<<32 overflows uint32; and if both g && d are
319        // maxUint32, this result would overflow uint64
320        ((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
321            + 2 * u64::from(std::cmp::max(g, d))
322            + u64::from(g > d)
323    }
324
325    pub async fn write(&self, b: &[u8]) -> Result<usize> {
326        self.local.write_to(b, &*self.remote).await
327    }
328}