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