Skip to main content

rtc_turn/client/
relay.rs

1use log::{debug, warn};
2use std::collections::HashMap;
3use std::net::SocketAddr;
4use std::ops::Add;
5use std::time::{Duration, Instant};
6
7use stun::attributes::*;
8use stun::error_code::*;
9use stun::fingerprint::*;
10use stun::integrity::*;
11use stun::message::*;
12use stun::textattrs::*;
13
14use super::permission::*;
15use super::transaction::*;
16use crate::proto;
17
18use crate::client::binding::BindingState;
19use crate::client::{Client, Event, RelayedAddr};
20use shared::error::{Error, Result};
21
22const PERM_REFRESH_INTERVAL: Duration = Duration::from_secs(120);
23// https://datatracker.ietf.org/doc/html/rfc8656#name-permissions-2
24// The Permission Lifetime MUST be 300 seconds (= 5 minutes).
25const PERM_LIFETIME: Duration = Duration::from_secs(300);
26const MAX_RETRY_ATTEMPTS: u16 = 3;
27/// Smallest step the allocation-refresh timer may advance by.
28///
29/// The timer advances by a fixed cadence from its own previous value, which keeps the refresh
30/// schedule drift-free. That only works while the step is positive. `lifetime` is assigned
31/// straight from the server's LIFETIME attribute, and a refresh carrying `LIFETIME=0` — how
32/// RFC 5766 deallocates, and what [`Relay::close`] sends — makes `lifetime / 2` zero. The timer
33/// then freezes on an already-expired instant and `poll_timeout` reports that same instant
34/// forever. A caller that treats an expired deadline as "handle it and go round again" spins
35/// on it without ever reaching its socket reads, which is
36/// [webrtc#862](https://github.com/webrtc-rs/webrtc/issues/862).
37const MIN_ALLOC_REFRESH_INTERVAL: Duration = Duration::from_secs(1);
38
39// RelayState is a set of params use by Relay
40pub(crate) struct RelayState {
41    pub(crate) relayed_addr: RelayedAddr,
42    pub(crate) integrity: MessageIntegrity,
43    pub(crate) nonce: Nonce,
44    pub(crate) lifetime: Duration,
45    perm_map: HashMap<SocketAddr, Permission>,
46    refresh_alloc_timer: Instant,
47    refresh_perms_timer: Instant,
48}
49
50impl RelayState {
51    pub(super) fn new(
52        relayed_addr: RelayedAddr,
53        integrity: MessageIntegrity,
54        nonce: Nonce,
55        lifetime: Duration,
56    ) -> Self {
57        debug!("initial lifetime: {} seconds", lifetime.as_secs());
58
59        Self {
60            relayed_addr,
61            integrity,
62            nonce,
63            lifetime,
64            perm_map: HashMap::new(),
65            refresh_alloc_timer: Instant::now().add(lifetime / 2),
66            refresh_perms_timer: Instant::now().add(PERM_REFRESH_INTERVAL),
67        }
68    }
69
70    pub(super) fn set_nonce_from_msg(&mut self, msg: &Message) {
71        // Update nonce
72        match Nonce::get_from_as(msg, ATTR_NONCE) {
73            Ok(nonce) => {
74                self.nonce = nonce;
75                debug!("refresh allocation: 438, got new nonce.");
76            }
77            Err(_) => warn!("refresh allocation: 438 but no nonce."),
78        }
79    }
80}
81
82/// A borrowed handle to one live allocation on the TURN server.
83///
84/// Obtained from [`Client::relay`](crate::client::Client::relay). Sending to a peer requires
85/// a permission for it first — see [`Self::create_permission`].
86pub struct Relay<'a> {
87    pub(crate) relayed_addr: RelayedAddr,
88    pub(crate) client: &'a mut Client,
89}
90
91impl Relay<'_> {
92    /// Asks the server to permit traffic to and from `peer_addr`.
93    ///
94    /// The relay silently drops data for peers with no permission, and permissions expire after
95    /// five minutes unless refreshed. Returns the transaction id to match against the resulting
96    /// [`Event`], or `None` if a permission is already in place.
97    ///
98    /// # Errors
99    ///
100    /// Fails if the allocation no longer exists or the request cannot be encoded.
101    pub fn create_permission(&mut self, peer_addr: SocketAddr) -> Result<Option<TransactionId>> {
102        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
103            relay
104                .perm_map
105                .entry(peer_addr)
106                .or_insert_with(Permission::default);
107            if let Some(perm) = relay.perm_map.get(&peer_addr)
108                && perm.state() == PermState::Idle
109            {
110                return Ok(Some(
111                    self.create_permissions(&[peer_addr], Some(peer_addr))?,
112                ));
113            }
114            Ok(None)
115        } else {
116            Err(Error::ErrConnClosed)
117        }
118    }
119
120    pub(crate) fn poll_timeout(&self) -> Option<Instant> {
121        if let Some(relay) = self.client.relays.get(&self.relayed_addr) {
122            if relay.refresh_alloc_timer < relay.refresh_perms_timer {
123                Some(relay.refresh_alloc_timer)
124            } else {
125                Some(relay.refresh_perms_timer)
126            }
127        } else {
128            None
129        }
130    }
131
132    pub(crate) fn handle_timeout(&mut self, now: Instant) {
133        let (refresh_alloc_timer, refresh_perms_timer) = if let Some(relay) =
134            self.client.relays.get_mut(&self.relayed_addr)
135        {
136            let refresh_alloc_timer = if relay.refresh_alloc_timer <= now {
137                // Floored so the timer always moves. A zero step would leave it pinned to an
138                // instant already in the past — see `MIN_ALLOC_REFRESH_INTERVAL`.
139                let step = (relay.lifetime / 2).max(MIN_ALLOC_REFRESH_INTERVAL);
140                relay.refresh_alloc_timer = relay.refresh_alloc_timer.add(step);
141                Some(relay.lifetime)
142            } else {
143                None
144            };
145
146            let refresh_perms_timer = if relay.refresh_perms_timer <= now {
147                relay.refresh_perms_timer = relay.refresh_perms_timer.add(PERM_REFRESH_INTERVAL);
148                true
149            } else {
150                false
151            };
152
153            (refresh_alloc_timer, refresh_perms_timer)
154        } else {
155            (None, false)
156        };
157
158        if let Some(lifetime) = refresh_alloc_timer {
159            let _ = self.refresh_allocation(lifetime);
160        }
161        if refresh_perms_timer {
162            let _ = self.refresh_permissions();
163        }
164    }
165
166    /// Sends `p` to `peer_addr` through the relay.
167    ///
168    /// Uses ChannelData framing if a channel is bound for that peer, otherwise a Data indication.
169    ///
170    /// # Errors
171    ///
172    /// Fails if the allocation is gone, or if no permission exists for `peer_addr`.
173    pub fn send_to(&mut self, p: &[u8], peer_addr: SocketAddr) -> Result<()> {
174        // check if we have a permission for the destination IP addr
175        let result = if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
176            if let Some(perm) = relay.perm_map.get_mut(&peer_addr) {
177                if perm.state() != PermState::Permitted {
178                    Err(Error::ErrNoPermission)
179                } else {
180                    Ok((relay.integrity.clone(), relay.nonce.clone()))
181                }
182            } else {
183                Err(Error::ErrNoPermission)
184            }
185        } else {
186            Err(Error::ErrConnClosed)
187        };
188
189        let (integrity, nonce) = result?;
190
191        self.send(p, peer_addr, integrity, nonce)
192    }
193
194    fn send(
195        &mut self,
196        p: &[u8],
197        peer_addr: SocketAddr,
198        integrity: MessageIntegrity,
199        nonce: Nonce,
200    ) -> Result<()> {
201        let channel_number = {
202            let (bind_st, bind_at, bind_number, bind_addr) = {
203                let b = if let Some(b) = self.client.binding_mgr.find_by_addr(&peer_addr) {
204                    b
205                } else {
206                    self.client
207                        .binding_mgr
208                        .create(peer_addr)
209                        .ok_or_else(|| Error::Other("Addr not found".to_owned()))?
210                };
211                (b.state(), b.refreshed_at(), b.number, b.addr)
212            };
213
214            if bind_st == BindingState::Idle
215                || bind_st == BindingState::Request
216                || bind_st == BindingState::Failed
217            {
218                // block only callers with the same binding until
219                // the binding transaction has been complete
220                // binding state may have been changed while waiting. check again.
221                if bind_st == BindingState::Idle {
222                    if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
223                        b.set_state(BindingState::Request);
224                    }
225                    self.channel_bind(self.relayed_addr, bind_addr, bind_number, nonce, integrity)?;
226                }
227
228                // send data using SendIndication
229                let mut msg = Message::new();
230                msg.build(&[
231                    Box::new(TransactionId::new()),
232                    Box::new(MessageType::new(METHOD_SEND, CLASS_INDICATION)),
233                    Box::new(proto::data::Data(p.to_vec())),
234                    Box::new(proto::peeraddr::PeerAddress {
235                        ip: peer_addr.ip(),
236                        port: peer_addr.port(),
237                    }),
238                    Box::new(FINGERPRINT),
239                ])?;
240
241                // indication has no transaction (fire-and-forget)
242                self.client
243                    .write_to(&msg.raw, self.client.turn_server_addr()?);
244                return Ok(());
245            }
246
247            // binding is ready
248            // check if the binding needs a refresh
249            if bind_st == BindingState::Ready
250                && Instant::now()
251                    .checked_duration_since(bind_at)
252                    .unwrap_or_else(|| Duration::from_secs(0))
253                    > PERM_LIFETIME
254            {
255                if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
256                    b.set_state(BindingState::Refresh);
257                }
258                self.channel_bind(self.relayed_addr, bind_addr, bind_number, nonce, integrity)?;
259            }
260
261            bind_number
262        };
263
264        // send via ChannelData
265        self.send_channel_data(p, channel_number)
266    }
267
268    // Close closes the connection.
269    // Any blocked ReadFrom or write_to operations will be unblocked and return errors.
270    /// Releases the allocation by refreshing it with a zero lifetime.
271    ///
272    /// # Errors
273    ///
274    /// Fails if the refresh request cannot be sent.
275    pub fn close(&mut self) -> Result<()> {
276        self.refresh_allocation(Duration::from_secs(0))
277    }
278
279    fn create_permissions(
280        &mut self,
281        peer_addrs: &[SocketAddr],
282        peer_addr_opt: Option<SocketAddr>,
283    ) -> Result<TransactionId> {
284        let (username, realm) = (self.client.username(), self.client.realm());
285        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
286            let msg = {
287                let mut setters: Vec<Box<dyn Setter>> = vec![
288                    Box::new(TransactionId::new()),
289                    Box::new(MessageType::new(METHOD_CREATE_PERMISSION, CLASS_REQUEST)),
290                ];
291
292                for addr in peer_addrs {
293                    setters.push(Box::new(proto::peeraddr::PeerAddress {
294                        ip: addr.ip(),
295                        port: addr.port(),
296                    }));
297                }
298
299                setters.push(Box::new(username));
300                setters.push(Box::new(realm));
301                setters.push(Box::new(relay.nonce.clone()));
302                setters.push(Box::new(relay.integrity.clone()));
303                setters.push(Box::new(FINGERPRINT));
304
305                let mut msg = Message::new();
306                msg.build(&setters)?;
307                msg
308            };
309
310            Ok(self.client.perform_transaction(
311                &msg,
312                self.client.turn_server_addr()?,
313                TransactionType::CreatePermissionRequest(self.relayed_addr, peer_addr_opt),
314            ))
315        } else {
316            Err(Error::ErrConnClosed)
317        }
318    }
319
320    pub(super) fn handle_create_permission_response(
321        &mut self,
322        res: Message,
323        peer_addr_opt: Option<SocketAddr>,
324    ) -> Result<()> {
325        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
326            if res.typ.class == CLASS_ERROR_RESPONSE {
327                let mut code = ErrorCodeAttribute::default();
328                let result = code.get_from(&res);
329                let err = if result.is_err() {
330                    Error::Other(format!("{}", res.typ))
331                } else if code.code == CODE_STALE_NONCE {
332                    relay.set_nonce_from_msg(&res);
333                    Error::ErrTryAgain
334                } else {
335                    Error::Other(format!("{} (error {})", res.typ, code))
336                };
337                if let Some(peer_addr) = peer_addr_opt {
338                    self.client
339                        .events
340                        .push_back(Event::CreatePermissionError(res.transaction_id, err));
341                    relay.perm_map.remove(&peer_addr);
342                }
343            } else if let Some(peer_addr) = peer_addr_opt
344                && let Some(perm) = relay.perm_map.get_mut(&peer_addr)
345            {
346                perm.set_state(PermState::Permitted);
347                self.client
348                    .events
349                    .push_back(Event::CreatePermissionResponse(
350                        res.transaction_id,
351                        peer_addr,
352                    ));
353            }
354
355            Ok(())
356        } else {
357            Err(Error::ErrConnClosed)
358        }
359    }
360
361    pub(super) fn refresh_allocation(&mut self, lifetime: Duration) -> Result<()> {
362        let (username, realm) = (self.client.username(), self.client.realm());
363        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
364            let mut msg = Message::new();
365            msg.build(&[
366                Box::new(TransactionId::new()),
367                Box::new(MessageType::new(METHOD_REFRESH, CLASS_REQUEST)),
368                Box::new(proto::lifetime::Lifetime(lifetime)),
369                Box::new(username),
370                Box::new(realm),
371                Box::new(relay.nonce.clone()),
372                Box::new(relay.integrity.clone()),
373                Box::new(FINGERPRINT),
374            ])?;
375
376            let _ = self.client.perform_transaction(
377                &msg,
378                self.client.turn_server_addr()?,
379                TransactionType::RefreshRequest(self.relayed_addr),
380            );
381
382            Ok(())
383        } else {
384            Err(Error::ErrConnClosed)
385        }
386    }
387
388    pub(super) fn handle_refresh_allocation_response(&mut self, res: Message) -> Result<()> {
389        let mut released = false;
390        let result = if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
391            if res.typ.class == CLASS_ERROR_RESPONSE {
392                let mut code = ErrorCodeAttribute::default();
393                let result = code.get_from(&res);
394                if result.is_err() {
395                    Err(Error::Other(format!("{}", res.typ)))
396                } else if code.code == CODE_STALE_NONCE {
397                    relay.set_nonce_from_msg(&res);
398                    //Error::ErrTryAgain
399                    Ok(())
400                } else {
401                    Err(Error::Other(format!("{} (error {})", res.typ, code)))
402                }
403            } else {
404                // Getting lifetime from response
405                let mut updated_lifetime = proto::lifetime::Lifetime::default();
406                updated_lifetime.get_from(&res)?;
407
408                relay.lifetime = updated_lifetime.0;
409                debug!("updated lifetime: {} seconds", relay.lifetime.as_secs());
410
411                // A zero lifetime is the server confirming deallocation — the reply to the
412                // refresh `close()` sends. The allocation no longer exists, so neither should
413                // the relay: leaving it in the map means it keeps reporting refresh deadlines
414                // for something that is gone, and keeps trying to refresh it.
415                released = relay.lifetime.is_zero();
416
417                Ok(())
418            }
419        } else {
420            Err(Error::ErrConnClosed)
421        };
422
423        if released {
424            self.client.relays.remove(&self.relayed_addr);
425            debug!("allocation released; relay {} dropped", self.relayed_addr);
426        }
427
428        result
429    }
430
431    pub(super) fn refresh_permissions(&mut self) -> Result<()> {
432        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
433            #[allow(clippy::map_clone)]
434            let addrs: Vec<SocketAddr> = relay.perm_map.keys().map(|addr| *addr).collect();
435            if addrs.is_empty() {
436                debug!("no permission to refresh");
437                return Ok(());
438            }
439            let _ = self.create_permissions(&addrs, None)?;
440            Ok(())
441        } else {
442            Err(Error::ErrConnClosed)
443        }
444    }
445
446    fn channel_bind(
447        &mut self,
448        relayed_addr: RelayedAddr,
449        bind_addr: SocketAddr,
450        bind_number: u16,
451        nonce: Nonce,
452        integrity: MessageIntegrity,
453    ) -> Result<()> {
454        let (msg, turn_server_addr) = {
455            let setters: Vec<Box<dyn Setter>> = vec![
456                Box::new(TransactionId::new()),
457                Box::new(MessageType::new(METHOD_CHANNEL_BIND, CLASS_REQUEST)),
458                Box::new(proto::peeraddr::PeerAddress {
459                    ip: bind_addr.ip(),
460                    port: bind_addr.port(),
461                }),
462                Box::new(proto::channum::ChannelNumber(bind_number)),
463                Box::new(self.client.username()),
464                Box::new(self.client.realm()),
465                Box::new(nonce),
466                Box::new(integrity),
467                Box::new(FINGERPRINT),
468            ];
469
470            let mut msg = Message::new();
471            msg.build(&setters)?;
472
473            (msg, self.client.turn_server_addr()?)
474        };
475
476        debug!("UDPConn.bind call PerformTransaction 1");
477        let _ = self.client.perform_transaction(
478            &msg,
479            turn_server_addr,
480            TransactionType::ChannelBindRequest(relayed_addr, bind_addr),
481        );
482
483        Ok(())
484    }
485
486    pub(super) fn handle_channel_bind_response(
487        &mut self,
488        res: Message,
489        bind_addr: SocketAddr,
490    ) -> Result<()> {
491        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
492            let result = if res.typ.class == CLASS_ERROR_RESPONSE {
493                let mut code = ErrorCodeAttribute::default();
494                let result = code.get_from(&res);
495                if result.is_err() {
496                    Err(Error::Other(format!("{}", res.typ)))
497                } else if code.code == CODE_STALE_NONCE {
498                    relay.set_nonce_from_msg(&res);
499                    Err(Error::ErrTryAgain)
500                } else {
501                    Err(Error::Other(format!("{} (error {})", res.typ, code)))
502                }
503            } else if res.typ != MessageType::new(METHOD_CHANNEL_BIND, CLASS_SUCCESS_RESPONSE) {
504                Err(Error::ErrUnexpectedResponse)
505            } else {
506                Ok(())
507            };
508
509            if let Err(err) = result {
510                if Error::ErrUnexpectedResponse != err {
511                    self.client.binding_mgr.delete_by_addr(&bind_addr);
512                } else if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
513                    b.set_state(BindingState::Failed);
514                }
515
516                // keep going...
517                warn!("bind() failed: {}", err);
518            } else if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
519                b.set_refreshed_at(Instant::now());
520                b.set_state(BindingState::Ready);
521                debug!("channel binding successful: {}", bind_addr);
522            }
523            Ok(())
524        } else {
525            Err(Error::ErrConnClosed)
526        }
527    }
528
529    fn send_channel_data(&mut self, data: &[u8], channel_number: u16) -> Result<()> {
530        let mut ch_data = proto::chandata::ChannelData {
531            data: data.to_vec(),
532            number: proto::channum::ChannelNumber(channel_number),
533            ..Default::default()
534        };
535        ch_data.encode();
536
537        self.client
538            .write_to(&ch_data.raw, self.client.turn_server_addr()?);
539
540        Ok(())
541    }
542}