xref: /webrtc/ice/src/agent/mod.rs (revision e32feda5)
1 #[cfg(test)]
2 mod agent_gather_test;
3 #[cfg(test)]
4 mod agent_test;
5 #[cfg(test)]
6 mod agent_transport_test;
7 #[cfg(test)]
8 pub(crate) mod agent_vnet_test;
9 
10 pub mod agent_config;
11 pub mod agent_gather;
12 pub(crate) mod agent_internal;
13 pub mod agent_selector;
14 pub mod agent_stats;
15 pub mod agent_transport;
16 
17 use crate::candidate::*;
18 use crate::error::*;
19 use crate::external_ip_mapper::*;
20 use crate::mdns::*;
21 use crate::network_type::*;
22 use crate::state::*;
23 use crate::udp_mux::UDPMux;
24 use crate::udp_network::UDPNetwork;
25 use crate::url::*;
26 use agent_config::*;
27 use agent_internal::*;
28 use agent_stats::*;
29 
30 use mdns::conn::*;
31 use std::collections::HashMap;
32 use std::net::{Ipv4Addr, SocketAddr};
33 use stun::{agent::*, attributes::*, fingerprint::*, integrity::*, message::*, xoraddr::*};
34 use util::{vnet::net::*, Buffer};
35 
36 use crate::agent::agent_gather::GatherCandidatesInternalParams;
37 use crate::rand::*;
38 use crate::tcp_type::TcpType;
39 use std::future::Future;
40 use std::pin::Pin;
41 use std::sync::atomic::{AtomicU8, AtomicUsize, Ordering};
42 use std::sync::Arc;
43 use std::time::SystemTime;
44 use tokio::sync::{broadcast, mpsc, Mutex};
45 use tokio::time::{Duration, Instant};
46 
47 #[derive(Debug, Clone)]
48 pub(crate) struct BindingRequest {
49     pub(crate) timestamp: Instant,
50     pub(crate) transaction_id: TransactionId,
51     pub(crate) destination: SocketAddr,
52     pub(crate) is_use_candidate: bool,
53 }
54 
55 impl Default for BindingRequest {
56     fn default() -> Self {
57         Self {
58             timestamp: Instant::now(),
59             transaction_id: TransactionId::default(),
60             destination: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0),
61             is_use_candidate: false,
62         }
63     }
64 }
65 
66 pub type OnConnectionStateChangeHdlrFn = Box<
67     dyn (FnMut(ConnectionState) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>)
68         + Send
69         + Sync,
70 >;
71 pub type OnSelectedCandidatePairChangeHdlrFn = Box<
72     dyn (FnMut(
73             &Arc<dyn Candidate + Send + Sync>,
74             &Arc<dyn Candidate + Send + Sync>,
75         ) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>)
76         + Send
77         + Sync,
78 >;
79 pub type OnCandidateHdlrFn = Box<
80     dyn (FnMut(
81             Option<Arc<dyn Candidate + Send + Sync>>,
82         ) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>)
83         + Send
84         + Sync,
85 >;
86 pub type GatherCandidateCancelFn = Box<dyn Fn() + Send + Sync>;
87 
88 struct ChanReceivers {
89     chan_state_rx: mpsc::Receiver<ConnectionState>,
90     chan_candidate_rx: mpsc::Receiver<Option<Arc<dyn Candidate + Send + Sync>>>,
91     chan_candidate_pair_rx: mpsc::Receiver<()>,
92 }
93 
94 /// Represents the ICE agent.
95 pub struct Agent {
96     pub(crate) internal: Arc<AgentInternal>,
97 
98     pub(crate) udp_network: UDPNetwork,
99     pub(crate) interface_filter: Arc<Option<InterfaceFilterFn>>,
100     pub(crate) ip_filter: Arc<Option<IpFilterFn>>,
101     pub(crate) mdns_mode: MulticastDnsMode,
102     pub(crate) mdns_name: String,
103     pub(crate) mdns_conn: Option<Arc<DnsConn>>,
104     pub(crate) net: Arc<Net>,
105 
106     // 1:1 D-NAT IP address mapping
107     pub(crate) ext_ip_mapper: Arc<Option<ExternalIpMapper>>,
108     pub(crate) gathering_state: Arc<AtomicU8>, //GatheringState,
109     pub(crate) candidate_types: Vec<CandidateType>,
110     pub(crate) urls: Vec<Url>,
111     pub(crate) network_types: Vec<NetworkType>,
112 
113     pub(crate) gather_candidate_cancel: Option<GatherCandidateCancelFn>,
114 }
115 
116 impl Agent {
117     /// Creates a new Agent.
118     pub async fn new(config: AgentConfig) -> Result<Self> {
119         let mut mdns_name = config.multicast_dns_host_name.clone();
120         if mdns_name.is_empty() {
121             mdns_name = generate_multicast_dns_name();
122         }
123 
124         if !mdns_name.ends_with(".local") || mdns_name.split('.').count() != 2 {
125             return Err(Error::ErrInvalidMulticastDnshostName);
126         }
127 
128         let mut mdns_mode = config.multicast_dns_mode;
129         if mdns_mode == MulticastDnsMode::Unspecified {
130             mdns_mode = MulticastDnsMode::QueryOnly;
131         }
132 
133         let mdns_conn =
134             match create_multicast_dns(mdns_mode, &mdns_name, &config.multicast_dns_dest_addr) {
135                 Ok(c) => c,
136                 Err(err) => {
137                     // Opportunistic mDNS: If we can't open the connection, that's ok: we
138                     // can continue without it.
139                     log::warn!("Failed to initialize mDNS {}: {}", mdns_name, err);
140                     None
141                 }
142             };
143 
144         let (mut ai, chan_receivers) = AgentInternal::new(&config);
145         let (chan_state_rx, chan_candidate_rx, chan_candidate_pair_rx) = (
146             chan_receivers.chan_state_rx,
147             chan_receivers.chan_candidate_rx,
148             chan_receivers.chan_candidate_pair_rx,
149         );
150 
151         config.init_with_defaults(&mut ai);
152 
153         let candidate_types = if config.candidate_types.is_empty() {
154             default_candidate_types()
155         } else {
156             config.candidate_types.clone()
157         };
158 
159         if ai.lite.load(Ordering::SeqCst)
160             && (candidate_types.len() != 1 || candidate_types[0] != CandidateType::Host)
161         {
162             Self::close_multicast_conn(&mdns_conn).await;
163             return Err(Error::ErrLiteUsingNonHostCandidates);
164         }
165 
166         if !config.urls.is_empty()
167             && !contains_candidate_type(CandidateType::ServerReflexive, &candidate_types)
168             && !contains_candidate_type(CandidateType::Relay, &candidate_types)
169         {
170             Self::close_multicast_conn(&mdns_conn).await;
171             return Err(Error::ErrUselessUrlsProvided);
172         }
173 
174         let ext_ip_mapper = match config.init_ext_ip_mapping(mdns_mode, &candidate_types) {
175             Ok(ext_ip_mapper) => ext_ip_mapper,
176             Err(err) => {
177                 Self::close_multicast_conn(&mdns_conn).await;
178                 return Err(err);
179             }
180         };
181 
182         let net = if let Some(net) = config.net {
183             if net.is_virtual() {
184                 log::warn!("vnet is enabled");
185                 if mdns_mode != MulticastDnsMode::Disabled {
186                     log::warn!("vnet does not support mDNS yet");
187                 }
188             }
189 
190             net
191         } else {
192             Arc::new(Net::new(None))
193         };
194 
195         let agent = Self {
196             udp_network: config.udp_network,
197             internal: Arc::new(ai),
198             interface_filter: Arc::clone(&config.interface_filter),
199             ip_filter: Arc::clone(&config.ip_filter),
200             mdns_mode,
201             mdns_name,
202             mdns_conn,
203             net,
204             ext_ip_mapper: Arc::new(ext_ip_mapper),
205             gathering_state: Arc::new(AtomicU8::new(0)), //GatheringState::New,
206             candidate_types,
207             urls: config.urls.clone(),
208             network_types: config.network_types.clone(),
209 
210             gather_candidate_cancel: None, //TODO: add cancel
211         };
212 
213         agent.internal.start_on_connection_state_change_routine(
214             chan_state_rx,
215             chan_candidate_rx,
216             chan_candidate_pair_rx,
217         );
218 
219         // Restart is also used to initialize the agent for the first time
220         if let Err(err) = agent.restart(config.local_ufrag, config.local_pwd).await {
221             Self::close_multicast_conn(&agent.mdns_conn).await;
222             let _ = agent.close().await;
223             return Err(err);
224         }
225 
226         Ok(agent)
227     }
228 
229     pub fn get_bytes_received(&self) -> usize {
230         self.internal.agent_conn.bytes_received()
231     }
232 
233     pub fn get_bytes_sent(&self) -> usize {
234         self.internal.agent_conn.bytes_sent()
235     }
236 
237     /// Sets a handler that is fired when the connection state changes.
238     pub fn on_connection_state_change(&self, f: OnConnectionStateChangeHdlrFn) {
239         self.internal
240             .on_connection_state_change_hdlr
241             .store(Some(Arc::new(Mutex::new(f))))
242     }
243 
244     /// Sets a handler that is fired when the final candidate pair is selected.
245     pub fn on_selected_candidate_pair_change(&self, f: OnSelectedCandidatePairChangeHdlrFn) {
246         self.internal
247             .on_selected_candidate_pair_change_hdlr
248             .store(Some(Arc::new(Mutex::new(f))))
249     }
250 
251     /// Sets a handler that is fired when new candidates gathered. When the gathering process
252     /// complete the last candidate is nil.
253     pub fn on_candidate(&self, f: OnCandidateHdlrFn) {
254         self.internal
255             .on_candidate_hdlr
256             .store(Some(Arc::new(Mutex::new(f))));
257     }
258 
259     /// Adds a new remote candidate.
260     pub fn add_remote_candidate(&self, c: &Arc<dyn Candidate + Send + Sync>) -> Result<()> {
261         // cannot check for network yet because it might not be applied
262         // when mDNS hostame is used.
263         if c.tcp_type() == TcpType::Active {
264             // TCP Candidates with tcptype active will probe server passive ones, so
265             // no need to do anything with them.
266             log::info!("Ignoring remote candidate with tcpType active: {}", c);
267             return Ok(());
268         }
269 
270         // If we have a mDNS Candidate lets fully resolve it before adding it locally
271         if c.candidate_type() == CandidateType::Host && c.address().ends_with(".local") {
272             if self.mdns_mode == MulticastDnsMode::Disabled {
273                 log::warn!(
274                     "remote mDNS candidate added, but mDNS is disabled: ({})",
275                     c.address()
276                 );
277                 return Ok(());
278             }
279 
280             if c.candidate_type() != CandidateType::Host {
281                 return Err(Error::ErrAddressParseFailed);
282             }
283 
284             let ai = Arc::clone(&self.internal);
285             let host_candidate = Arc::clone(c);
286             let mdns_conn = self.mdns_conn.clone();
287             tokio::spawn(async move {
288                 if let Some(mdns_conn) = mdns_conn {
289                     if let Ok(candidate) =
290                         Self::resolve_and_add_multicast_candidate(mdns_conn, host_candidate).await
291                     {
292                         ai.add_remote_candidate(&candidate).await;
293                     }
294                 }
295             });
296         } else {
297             let ai = Arc::clone(&self.internal);
298             let candidate = Arc::clone(c);
299             tokio::spawn(async move {
300                 ai.add_remote_candidate(&candidate).await;
301             });
302         }
303 
304         Ok(())
305     }
306 
307     /// Returns the local candidates.
308     pub async fn get_local_candidates(&self) -> Result<Vec<Arc<dyn Candidate + Send + Sync>>> {
309         let mut res = vec![];
310 
311         {
312             let local_candidates = self.internal.local_candidates.lock().await;
313             for candidates in local_candidates.values() {
314                 for candidate in candidates {
315                     res.push(Arc::clone(candidate));
316                 }
317             }
318         }
319 
320         Ok(res)
321     }
322 
323     /// Returns the local user credentials.
324     pub async fn get_local_user_credentials(&self) -> (String, String) {
325         let ufrag_pwd = self.internal.ufrag_pwd.lock().await;
326         (ufrag_pwd.local_ufrag.clone(), ufrag_pwd.local_pwd.clone())
327     }
328 
329     /// Returns the remote user credentials.
330     pub async fn get_remote_user_credentials(&self) -> (String, String) {
331         let ufrag_pwd = self.internal.ufrag_pwd.lock().await;
332         (ufrag_pwd.remote_ufrag.clone(), ufrag_pwd.remote_pwd.clone())
333     }
334 
335     /// Cleans up the Agent.
336     pub async fn close(&self) -> Result<()> {
337         if let Some(gather_candidate_cancel) = &self.gather_candidate_cancel {
338             gather_candidate_cancel();
339         }
340 
341         if let UDPNetwork::Muxed(ref udp_mux) = self.udp_network {
342             let (ufrag, _) = self.get_local_user_credentials().await;
343             udp_mux.remove_conn_by_ufrag(&ufrag).await;
344         }
345 
346         //FIXME: deadlock here
347         self.internal.close().await
348     }
349 
350     /// Returns the selected pair or nil if there is none
351     pub fn get_selected_candidate_pair(&self) -> Option<Arc<CandidatePair>> {
352         self.internal.agent_conn.get_selected_pair()
353     }
354 
355     /// Sets the credentials of the remote agent.
356     pub async fn set_remote_credentials(
357         &self,
358         remote_ufrag: String,
359         remote_pwd: String,
360     ) -> Result<()> {
361         self.internal
362             .set_remote_credentials(remote_ufrag, remote_pwd)
363             .await
364     }
365 
366     /// Restarts the ICE Agent with the provided ufrag/pwd
367     /// If no ufrag/pwd is provided the Agent will generate one itself.
368     ///
369     /// Restart must only be called when `GatheringState` is `GatheringStateComplete`
370     /// a user must then call `GatherCandidates` explicitly to start generating new ones.
371     pub async fn restart(&self, mut ufrag: String, mut pwd: String) -> Result<()> {
372         if ufrag.is_empty() {
373             ufrag = generate_ufrag();
374         }
375         if pwd.is_empty() {
376             pwd = generate_pwd();
377         }
378 
379         if ufrag.len() * 8 < 24 {
380             return Err(Error::ErrLocalUfragInsufficientBits);
381         }
382         if pwd.len() * 8 < 128 {
383             return Err(Error::ErrLocalPwdInsufficientBits);
384         }
385 
386         if GatheringState::from(self.gathering_state.load(Ordering::SeqCst))
387             == GatheringState::Gathering
388         {
389             return Err(Error::ErrRestartWhenGathering);
390         }
391         self.gathering_state
392             .store(GatheringState::New as u8, Ordering::SeqCst);
393 
394         {
395             let done_tx = self.internal.done_tx.lock().await;
396             if done_tx.is_none() {
397                 return Err(Error::ErrClosed);
398             }
399         }
400 
401         // Clear all agent needed to take back to fresh state
402         {
403             let mut ufrag_pwd = self.internal.ufrag_pwd.lock().await;
404             ufrag_pwd.local_ufrag = ufrag;
405             ufrag_pwd.local_pwd = pwd;
406             ufrag_pwd.remote_ufrag = String::new();
407             ufrag_pwd.remote_pwd = String::new();
408         }
409         {
410             let mut pending_binding_requests = self.internal.pending_binding_requests.lock().await;
411             *pending_binding_requests = vec![];
412         }
413 
414         {
415             let mut checklist = self.internal.agent_conn.checklist.lock().await;
416             *checklist = vec![];
417         }
418 
419         self.internal.set_selected_pair(None).await;
420         self.internal.delete_all_candidates().await;
421         self.internal.start().await;
422 
423         // Restart is used by NewAgent. Accept/Connect should be used to move to checking
424         // for new Agents
425         if self.internal.connection_state.load(Ordering::SeqCst) != ConnectionState::New as u8 {
426             self.internal
427                 .update_connection_state(ConnectionState::Checking)
428                 .await;
429         }
430 
431         Ok(())
432     }
433 
434     /// Initiates the trickle based gathering process.
435     pub fn gather_candidates(&self) -> Result<()> {
436         if self.gathering_state.load(Ordering::SeqCst) != GatheringState::New as u8 {
437             return Err(Error::ErrMultipleGatherAttempted);
438         }
439 
440         if self.internal.on_candidate_hdlr.load().is_none() {
441             return Err(Error::ErrNoOnCandidateHandler);
442         }
443 
444         if let Some(gather_candidate_cancel) = &self.gather_candidate_cancel {
445             gather_candidate_cancel(); // Cancel previous gathering routine
446         }
447 
448         //TODO: a.gatherCandidateCancel = cancel
449 
450         let params = GatherCandidatesInternalParams {
451             udp_network: self.udp_network.clone(),
452             candidate_types: self.candidate_types.clone(),
453             urls: self.urls.clone(),
454             network_types: self.network_types.clone(),
455             mdns_mode: self.mdns_mode,
456             mdns_name: self.mdns_name.clone(),
457             net: Arc::clone(&self.net),
458             interface_filter: self.interface_filter.clone(),
459             ip_filter: self.ip_filter.clone(),
460             ext_ip_mapper: Arc::clone(&self.ext_ip_mapper),
461             agent_internal: Arc::clone(&self.internal),
462             gathering_state: Arc::clone(&self.gathering_state),
463             chan_candidate_tx: Arc::clone(&self.internal.chan_candidate_tx),
464         };
465         tokio::spawn(async move {
466             Self::gather_candidates_internal(params).await;
467         });
468 
469         Ok(())
470     }
471 
472     /// Returns a list of candidate pair stats.
473     pub async fn get_candidate_pairs_stats(&self) -> Vec<CandidatePairStats> {
474         self.internal.get_candidate_pairs_stats().await
475     }
476 
477     /// Returns a list of local candidates stats.
478     pub async fn get_local_candidates_stats(&self) -> Vec<CandidateStats> {
479         self.internal.get_local_candidates_stats().await
480     }
481 
482     /// Returns a list of remote candidates stats.
483     pub async fn get_remote_candidates_stats(&self) -> Vec<CandidateStats> {
484         self.internal.get_remote_candidates_stats().await
485     }
486 
487     async fn resolve_and_add_multicast_candidate(
488         mdns_conn: Arc<DnsConn>,
489         c: Arc<dyn Candidate + Send + Sync>,
490     ) -> Result<Arc<dyn Candidate + Send + Sync>> {
491         //TODO: hook up _close_query_signal_tx to Agent or Candidate's Close signal?
492         let (_close_query_signal_tx, close_query_signal_rx) = mpsc::channel(1);
493         let src = match mdns_conn.query(&c.address(), close_query_signal_rx).await {
494             Ok((_, src)) => src,
495             Err(err) => {
496                 log::warn!("Failed to discover mDNS candidate {}: {}", c.address(), err);
497                 return Err(err.into());
498             }
499         };
500 
501         c.set_ip(&src.ip())?;
502 
503         Ok(c)
504     }
505 
506     async fn close_multicast_conn(mdns_conn: &Option<Arc<DnsConn>>) {
507         if let Some(conn) = mdns_conn {
508             if let Err(err) = conn.close().await {
509                 log::warn!("failed to close mDNS Conn: {}", err);
510             }
511         }
512     }
513 }
514