Skip to main content

rice_proto/
stream.rs

1// Copyright (C) 2024 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// SPDX-License-Identifier: MIT OR Apache-2.0
10
11//! A [`Stream`] in an ICE [`Agent`]
12
13use alloc::vec::Vec;
14use core::net::SocketAddr;
15
16use crate::gathering::GatherPoll;
17use stun_proto::Instant;
18use stun_proto::agent::{StunError, Transmit};
19use stun_proto::types::data::Data;
20
21use crate::agent::{Agent, AgentError};
22use crate::component::{Component, ComponentMut, ComponentState, GatherProgress};
23use crate::conncheck::{HandleRecvReply, PendingRecv, RequestRto};
24
25use crate::candidate::{Candidate, TransportType};
26//use crate::turn::agent::TurnCredentials;
27
28pub use crate::conncheck::Credentials;
29pub use crate::gathering::GatheredCandidate;
30
31use tracing::{info, trace};
32
33/// An ICE [`Stream`]
34#[derive(Debug, Clone)]
35#[repr(C)]
36pub struct Stream<'a> {
37    agent: &'a crate::agent::Agent,
38    id: usize,
39}
40
41impl<'a> Stream<'a> {
42    pub(crate) fn from_agent(agent: &'a Agent, id: usize) -> Self {
43        Self { agent, id }
44    }
45
46    /// The [`Agent`] that handles this [`Stream`].
47    pub fn agent(&self) -> &'a crate::agent::Agent {
48        self.agent
49    }
50
51    /// The stream identifier within a particular ICE [`Agent`]
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// # use rice_proto::agent::Agent;
57    /// # use rice_proto::stream::Stream;
58    /// let mut agent = Agent::default();
59    /// let stream_id = agent.add_stream();
60    /// let stream = agent.stream(stream_id).unwrap();
61    /// assert_eq!(stream.id(), stream_id);
62    /// ```
63    pub fn id(&self) -> usize {
64        self.id
65    }
66
67    /// Retrieve a `Component` from this stream.  If the index doesn't exist or a component is not
68    /// available at that index, `None` is returned
69    ///
70    /// # Examples
71    ///
72    /// Remove a `Component`
73    ///
74    /// ```
75    /// # use rice_proto::agent::Agent;
76    /// # use rice_proto::component;
77    /// # use rice_proto::component::Component;
78    /// let mut agent = Agent::default();
79    /// let stream_id = agent.add_stream();
80    /// let mut stream = agent.mut_stream(stream_id).unwrap();
81    /// let component_id = stream.add_component().unwrap();
82    /// let component = stream.component(component_id).unwrap();
83    /// assert_eq!(component.id(), component::RTP);
84    /// assert!(stream.component(component::RTP).is_some());
85    /// ```
86    ///
87    /// Retrieving a `Component` that doesn't exist will return `None`
88    ///
89    /// ```
90    /// # use rice_proto::agent::Agent;
91    /// # use rice_proto::component;
92    /// # use rice_proto::component::Component;
93    /// let mut agent = Agent::default();
94    /// let stream_id = agent.add_stream();
95    /// let stream = agent.stream(stream_id).unwrap();
96    /// assert!(stream.component(component::RTP).is_none());
97    /// ```
98    pub fn component(&self, index: usize) -> Option<Component<'_>> {
99        if index < 1 {
100            return None;
101        }
102        let stream_state = self.agent.stream_state(self.id)?;
103        if let Some(Some(_component)) = stream_state.components.get(index - 1) {
104            Some(Component::from_stream(self.agent, self.id, index))
105        } else {
106            None
107        }
108    }
109
110    /// Retreive the previouly set local ICE credentials for this `Stream`.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// # use rice_proto::agent::Agent;
116    /// # use rice_proto::stream::Credentials;
117    /// let mut agent = Agent::default();
118    /// let stream_id = agent.add_stream();
119    /// let mut stream = agent.mut_stream(stream_id).unwrap();
120    /// let credentials = Credentials {ufrag: "1".to_owned(), passwd: "2".to_owned()};
121    /// stream.set_local_credentials(credentials.clone());
122    /// assert_eq!(stream.local_credentials(), Some(credentials));
123    /// ```
124    pub fn local_credentials(&self) -> Option<Credentials> {
125        let stream_state = self.agent.stream_state(self.id)?;
126        stream_state.local_credentials()
127    }
128
129    /// Retreive the previouly set remote ICE credentials for this `Stream`.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// # use rice_proto::agent::Agent;
135    /// # use rice_proto::stream::Credentials;
136    /// let mut agent = Agent::default();
137    /// let stream_id = agent.add_stream();
138    /// let mut stream = agent.mut_stream(stream_id).unwrap();
139    /// let credentials = Credentials {ufrag: "1".to_owned(), passwd: "2".to_owned()};
140    /// stream.set_remote_credentials(credentials.clone());
141    /// assert_eq!(stream.remote_credentials(), Some(credentials));
142    /// ```
143    pub fn remote_credentials(&self) -> Option<Credentials> {
144        let stream_state = self.agent.stream_state(self.id)?;
145        stream_state.remote_credentials()
146    }
147
148    /// Retrieve previously gathered local candidates
149    pub fn local_candidates(&self) -> impl Iterator<Item = &'_ Candidate> + '_ {
150        let stream_state = self.agent.stream_state(self.id).unwrap();
151        let checklist = self
152            .agent
153            .checklistset
154            .list(stream_state.checklist_id)
155            .unwrap();
156        checklist.local_candidates()
157    }
158
159    /// Retrieve previously set remote candidates for connection checks from this stream
160    ///
161    /// # Examples
162    ///
163    /// ```
164    /// # use rice_proto::agent::Agent;
165    /// # use rice_proto::candidate::*;
166    /// let mut agent = Agent::default();
167    /// let stream_id = agent.add_stream();
168    /// let mut stream = agent.mut_stream(stream_id).unwrap();
169    /// let component_id = stream.add_component().unwrap();
170    /// let component = stream.component(component_id).unwrap();
171    /// let addr = "127.0.0.1:9999".parse().unwrap();
172    /// let candidate = Candidate::builder(
173    ///     0,
174    ///     CandidateType::Host,
175    ///     TransportType::Udp,
176    ///     "0",
177    ///     addr
178    /// )
179    /// .build();
180    /// stream.add_remote_candidate(candidate.clone());
181    /// let remote_cands = stream.remote_candidates();
182    /// assert_eq!(remote_cands.len(), 1);
183    /// assert_eq!(remote_cands[0], candidate);
184    /// ```
185    pub fn remote_candidates(&self) -> &[Candidate] {
186        let stream_state = self.agent.stream_state(self.id).unwrap();
187        let checklist_id = stream_state.checklist_id;
188        let checklist = self.agent.checklistset.list(checklist_id).unwrap();
189        checklist.remote_candidates()
190    }
191
192    /// Return an `Iterator` over all the component ids in this stream.
193    pub fn component_ids_iter(&self) -> impl Iterator<Item = usize> + '_ {
194        let stream = self.agent.stream_state(self.id).unwrap();
195        stream
196            .components
197            .iter()
198            .flatten()
199            .map(|component| component.id)
200    }
201}
202
203/// A (mutable) ICE stream
204#[derive(Debug)]
205#[repr(C)]
206pub struct StreamMut<'a> {
207    agent: &'a mut crate::agent::Agent,
208    id: usize,
209}
210
211impl<'a> core::ops::Deref for StreamMut<'a> {
212    type Target = Stream<'a>;
213
214    fn deref(&self) -> &Self::Target {
215        unsafe { core::mem::transmute(self) }
216    }
217}
218
219impl<'a> StreamMut<'a> {
220    pub(crate) fn from_agent(agent: &'a mut Agent, id: usize) -> Self {
221        Self { agent, id }
222    }
223
224    /// The [`Agent`] that handles this [`Stream`].
225    pub fn mut_agent(&'a mut self) -> &'a mut crate::agent::Agent {
226        self.agent
227    }
228
229    /// Add a `Component` to this stream.
230    ///
231    /// # Examples
232    ///
233    /// Add a `Component`
234    ///
235    /// ```
236    /// # use rice_proto::agent::Agent;
237    /// # use rice_proto::component;
238    /// # use rice_proto::component::Component;
239    /// let mut agent = Agent::default();
240    /// let stream_id = agent.add_stream();
241    /// let mut stream = agent.mut_stream(stream_id).unwrap();
242    /// let component_id = stream.add_component().unwrap();
243    /// let component = stream.component(component_id).unwrap();
244    /// assert_eq!(component.id(), component::RTP);
245    /// ```
246    pub fn add_component(&mut self) -> Result<usize, AgentError> {
247        let stream_state = self
248            .agent
249            .mut_stream_state(self.id)
250            .ok_or(AgentError::ResourceNotFound)?;
251        let component_id = stream_state.add_component()?;
252        let checklist_id = stream_state.checklist_id;
253        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
254        checklist.add_component(component_id);
255        Ok(component_id)
256    }
257
258    /// Retrieve mutable access to a component in this stream.  `None` will be returned if the
259    /// component does not exist
260    pub fn mut_component(&mut self, index: usize) -> Option<ComponentMut<'_>> {
261        if index < 1 {
262            return None;
263        }
264        let stream_state = self.agent.mut_stream_state(self.id)?;
265        if let Some(Some(_component)) = stream_state.components.get_mut(index - 1) {
266            Some(ComponentMut::from_stream(self.agent, self.id, index))
267        } else {
268            None
269        }
270    }
271
272    /// Set local ICE credentials for this `Stream`.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// # use rice_proto::agent::Agent;
278    /// # use rice_proto::stream::Credentials;
279    /// let mut agent = Agent::default();
280    /// let stream_id = agent.add_stream();
281    /// let mut stream = agent.mut_stream(stream_id).unwrap();
282    /// let credentials = Credentials {ufrag: "1".to_owned(), passwd: "2".to_owned()};
283    /// stream.set_local_credentials(credentials);
284    /// ```
285    pub fn set_local_credentials(&mut self, credentials: Credentials) {
286        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
287        stream_state.set_local_credentials(credentials.clone());
288        let checklist_id = stream_state.checklist_id;
289        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
290        checklist.set_local_credentials(credentials);
291    }
292
293    /// Set remote ICE credentials for this `Stream`.
294    ///
295    /// # Examples
296    ///
297    /// ```
298    /// # use rice_proto::agent::Agent;
299    /// # use rice_proto::stream::Credentials;
300    /// let mut agent = Agent::default();
301    /// let stream_id = agent.add_stream();
302    /// let mut stream = agent.mut_stream(stream_id).unwrap();
303    /// let credentials = Credentials {ufrag: "1".to_owned(), passwd: "2".to_owned()};
304    /// stream.set_remote_credentials(credentials);
305    /// ```
306    pub fn set_remote_credentials(&mut self, credentials: Credentials) {
307        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
308        stream_state.set_remote_credentials(credentials.clone());
309        let checklist_id = stream_state.checklist_id;
310        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
311        checklist.set_remote_credentials(credentials);
312    }
313
314    /// Add a remote candidate for connection checks for use with this stream
315    ///
316    /// # Examples
317    ///
318    /// ```
319    /// # use rice_proto::agent::Agent;
320    /// # use rice_proto::candidate::*;
321    /// let mut agent = Agent::default();
322    /// let stream_id = agent.add_stream();
323    /// let mut stream = agent.mut_stream(stream_id).unwrap();
324    /// let component_id = stream.add_component().unwrap();
325    /// let component = stream.component(component_id).unwrap();
326    /// let addr = "127.0.0.1:9999".parse().unwrap();
327    /// let candidate = Candidate::builder(
328    ///     0,
329    ///     CandidateType::Host,
330    ///     TransportType::Udp,
331    ///     "0",
332    ///     addr
333    /// )
334    /// .build();
335    /// stream.add_remote_candidate(candidate);
336    /// ```
337    #[tracing::instrument(
338        skip(self, cand),
339        fields(
340            stream.id = self.id
341        )
342    )]
343    pub fn add_remote_candidate(&mut self, cand: Candidate) {
344        info!("adding remote candidate {:?}", cand);
345        let Some(stream_state) = self.agent.mut_stream_state(self.id) else {
346            return;
347        };
348        let checklist_id = stream_state.checklist_id;
349        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
350        checklist.add_remote_candidate(cand);
351    }
352
353    /// Provide the stream with data that has been received on an external socket.  The returned
354    /// value indicates what has been done with the data and any application data that has been
355    /// received.
356    #[tracing::instrument(
357        name = "stream_handle_incoming_data",
358        skip(self, component_id, transmit),
359        fields(
360            stream.id = self.id,
361            component.id = component_id,
362        )
363    )]
364    pub fn handle_incoming_data<T: AsRef<[u8]> + core::fmt::Debug>(
365        &mut self,
366        component_id: usize,
367        transmit: Transmit<T>,
368        now: Instant,
369    ) -> HandleRecvReply<T> {
370        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
371        let checklist_id = stream_state.checklist_id;
372        // first try to provide the incoming data to the gathering process if it exist
373        let ret = stream_state.handle_incoming_data(component_id, &transmit, now);
374        if ret.handled {
375            return ret;
376        }
377        if stream_state.component_state(component_id).is_none() {
378            return ret;
379        };
380
381        // or, provide the data to the connection check component for further processing
382        self.agent
383            .checklistset
384            .incoming_data(checklist_id, component_id, transmit, now)
385    }
386
387    /// Poll for any received data.
388    ///
389    /// Must be called after `handle_incoming_data` if `have_more_data` is `true`.
390    pub fn poll_recv(&mut self) -> Option<PendingRecv> {
391        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
392        let checklist_id = stream_state.checklist_id;
393
394        self.agent
395            .checklistset
396            .mut_list(checklist_id)
397            .and_then(|s| s.poll_recv())
398    }
399
400    /// Indicate that no more candidates are expected from the peer.  This may allow the ICE
401    /// process to complete.
402    #[tracing::instrument(
403        skip(self),
404        fields(
405            component.id = self.id,
406        )
407    )]
408    pub fn end_of_remote_candidates(&mut self) {
409        // FIXME: how to deal with ice restarts?
410        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
411        let checklist_id = stream_state.checklist_id;
412        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
413        checklist.end_of_remote_candidates();
414    }
415
416    /// Provide a reply to the
417    /// [`AgentPoll::AllocateSocket`](crate::agent::AgentPoll::AllocateSocket) request.  The
418    /// `component_id`, `transport`, `from`, and `to` values must match exactly with the request.
419    pub fn allocated_socket(
420        &mut self,
421        component_id: usize,
422        transport: TransportType,
423        from: SocketAddr,
424        to: SocketAddr,
425        local_addr: Result<SocketAddr, StunError>,
426        now: Instant,
427    ) {
428        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
429        let checklist_id = stream_state.checklist_id;
430        let Some(component_state) = stream_state.mut_component_state(component_id) else {
431            return;
432        };
433        if component_state.gather_state != GatherProgress::InProgress {
434            return;
435        }
436        if let Some(gather) = component_state.gatherer.as_mut() {
437            gather.allocated_socket(transport, from, to, &local_addr)
438        }
439        self.agent.checklistset.allocated_socket(
440            checklist_id,
441            component_id,
442            transport,
443            from,
444            to,
445            local_addr,
446            now,
447        );
448    }
449
450    /// Add a local candidate for this stream.
451    ///
452    /// Returns whether the candidate was added internally.
453    pub fn add_local_candidate(&mut self, candidate: Candidate) -> bool {
454        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
455        let checklist_id = stream_state.checklist_id;
456        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
457        checklist.add_local_candidate(candidate)
458    }
459
460    /// Add a local candidate for this stream.
461    ///
462    /// Returns whether the candidate was added internally.
463    pub fn add_local_gathered_candidate(&mut self, candidate: GatheredCandidate) -> bool {
464        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
465        let checklist_id = stream_state.checklist_id;
466        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
467        checklist.add_local_gathered_candidate(candidate)
468    }
469
470    /// Signal the end of local candidates.  Calling this function may allow ICE processing to
471    /// complete.
472    pub fn end_of_local_candidates(&mut self) {
473        let stream_state = self.agent.mut_stream_state(self.id).unwrap();
474        let checklist_id = stream_state.checklist_id;
475        let checklist = self.agent.checklistset.mut_list(checklist_id).unwrap();
476        checklist.end_of_local_candidates()
477    }
478}
479
480#[derive(Debug, Default)]
481pub(crate) struct StreamState {
482    id: usize,
483    pub(crate) checklist_id: usize,
484    components: Vec<Option<ComponentState>>,
485    local_credentials: Option<Credentials>,
486    remote_credentials: Option<Credentials>,
487}
488
489impl StreamState {
490    pub(crate) fn new(id: usize, checklist_id: usize) -> Self {
491        Self {
492            id,
493            checklist_id,
494            components: Vec::new(),
495            local_credentials: None,
496            remote_credentials: None,
497        }
498    }
499
500    pub(crate) fn component_state(&self, component_id: usize) -> Option<&ComponentState> {
501        if component_id < 1 {
502            return None;
503        }
504        if let Some(Some(c)) = self.components.get(component_id - 1) {
505            Some(c)
506        } else {
507            None
508        }
509    }
510
511    pub(crate) fn mut_component_state(
512        &mut self,
513        component_id: usize,
514    ) -> Option<&mut ComponentState> {
515        if component_id < 1 {
516            return None;
517        }
518        if let Some(Some(c)) = self.components.get_mut(component_id - 1) {
519            Some(c)
520        } else {
521            None
522        }
523    }
524
525    /// The id of the [`Stream`]
526    pub(crate) fn id(&self) -> usize {
527        self.id
528    }
529
530    #[tracing::instrument(
531        name = "stream_add_component",
532        skip(self),
533        fields(
534            stream.id = self.id
535        )
536    )]
537    fn add_component(&mut self) -> Result<usize, AgentError> {
538        let index = self
539            .components
540            .iter()
541            .enumerate()
542            .find(|c| c.1.is_none())
543            .unwrap_or((self.components.len(), &None))
544            .0;
545        info!("adding component {}", index + 1);
546        if self.components.get(index).is_some() {
547            return Err(AgentError::AlreadyExists);
548        }
549        while self.components.len() <= index {
550            self.components.push(None);
551        }
552        let component = ComponentState::new(index + 1);
553        self.components[index] = Some(component);
554        trace!("Added component at index {}", index);
555        Ok(index + 1)
556    }
557
558    #[tracing::instrument(
559        skip(self),
560        fields(
561            stream.id = self.id
562        )
563    )]
564    fn set_local_credentials(&mut self, credentials: Credentials) {
565        info!("setting");
566        self.local_credentials = Some(credentials.clone());
567    }
568
569    fn local_credentials(&self) -> Option<Credentials> {
570        self.local_credentials.clone()
571    }
572
573    #[tracing::instrument(
574        skip(self),
575        fields(
576            stream.id = self.id()
577        )
578    )]
579    fn set_remote_credentials(&mut self, credentials: Credentials) {
580        info!("setting");
581        self.remote_credentials = Some(credentials.clone());
582    }
583
584    fn remote_credentials(&self) -> Option<Credentials> {
585        self.remote_credentials.clone()
586    }
587
588    pub(crate) fn handle_incoming_data<T: AsRef<[u8]> + core::fmt::Debug>(
589        &mut self,
590        component_id: usize,
591        transmit: &Transmit<T>,
592        now: Instant,
593    ) -> HandleRecvReply<T> {
594        let Some(component) = self.mut_component_state(component_id) else {
595            return HandleRecvReply::default();
596        };
597        if component.gather_state != GatherProgress::InProgress {
598            return HandleRecvReply::default();
599        }
600        let Some(gather) = component.gatherer.as_mut() else {
601            return HandleRecvReply::default();
602        };
603        // XXX: is this enough to successfully route to the gatherer over the
604        // connection check or component received handling?
605        if gather.handle_data(transmit, now) {
606            HandleRecvReply {
607                handled: true,
608                ..Default::default()
609            }
610        } else {
611            HandleRecvReply::default()
612        }
613    }
614
615    #[tracing::instrument(ret, level = "trace", skip(self))]
616    pub(crate) fn poll_gather(&mut self, now: Instant) -> GatherPoll {
617        let mut lowest_wait = None;
618        for component in self.components.iter_mut() {
619            let Some(component) = component else {
620                continue;
621            };
622            let Some(gatherer) = component.gatherer.as_mut() else {
623                continue;
624            };
625            if component.gather_state != GatherProgress::InProgress {
626                continue;
627            }
628
629            match gatherer.poll(now) {
630                GatherPoll::WaitUntil(wait) => {
631                    if let Some(check_wait) = lowest_wait {
632                        if wait < check_wait {
633                            lowest_wait = Some(wait);
634                        }
635                    } else {
636                        lowest_wait = Some(wait);
637                    }
638                }
639                GatherPoll::Complete(component_id) => {
640                    component.gather_state = GatherProgress::Completed;
641                    return GatherPoll::Complete(component_id);
642                }
643                GatherPoll::Finished => (),
644                other => return other,
645            }
646        }
647        if let Some(lowest_wait) = lowest_wait {
648            GatherPoll::WaitUntil(lowest_wait)
649        } else {
650            GatherPoll::Finished
651        }
652    }
653
654    pub(crate) fn poll_gather_transmit(
655        &mut self,
656        now: Instant,
657    ) -> Option<(usize, Transmit<Data<'_>>)> {
658        for component in self.components.iter_mut() {
659            let Some(component) = component else {
660                continue;
661            };
662            let Some(gatherer) = component.gatherer.as_mut() else {
663                continue;
664            };
665            if component.gather_state != GatherProgress::InProgress {
666                continue;
667            }
668
669            if let Some(transmit) = gatherer.poll_transmit(now) {
670                return Some((component.id, transmit));
671            }
672        }
673        None
674    }
675
676    pub(crate) fn set_request_retransmits(&mut self, rto: RequestRto) {
677        for component in self.components.iter_mut() {
678            let Some(component) = component else {
679                continue;
680            };
681            let Some(gatherer) = component.gatherer.as_mut() else {
682                continue;
683            };
684
685            gatherer.set_request_retransmits(rto.clone());
686        }
687    }
688}
689
690#[cfg(test)]
691mod tests {
692    use super::*;
693
694    #[test]
695    fn getters_setters() {
696        let _log = crate::tests::test_init_log();
697        let lcreds = Credentials::new("luser".into(), "lpass".into());
698        let rcreds = Credentials::new("ruser".into(), "rpass".into());
699
700        let mut agent = Agent::default();
701        let stream_id = agent.add_stream();
702        let mut stream = agent.mut_stream(stream_id).unwrap();
703        assert!(stream.component(0).is_none());
704        let comp_id = stream.add_component().unwrap();
705        assert_eq!(comp_id, stream.component(comp_id).unwrap().id());
706
707        stream.set_local_credentials(lcreds.clone());
708        assert_eq!(stream.local_credentials().unwrap(), lcreds);
709        stream.set_remote_credentials(rcreds.clone());
710        assert_eq!(stream.remote_credentials().unwrap(), rcreds);
711    }
712}