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) =
134            if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
135                let refresh_alloc_timer = if relay.refresh_alloc_timer <= now {
136                    // Floored so the timer always moves. A zero step would leave it pinned to an
137                    // instant already in the past — see `MIN_ALLOC_REFRESH_INTERVAL`.
138                    let step = (relay.lifetime / 2).max(MIN_ALLOC_REFRESH_INTERVAL);
139                    relay.refresh_alloc_timer = now.add(step);
140                    Some(relay.lifetime)
141                } else {
142                    None
143                };
144
145                let refresh_perms_timer = if relay.refresh_perms_timer <= now {
146                    relay.refresh_perms_timer = now.add(PERM_REFRESH_INTERVAL);
147                    true
148                } else {
149                    false
150                };
151
152                (refresh_alloc_timer, refresh_perms_timer)
153            } else {
154                (None, false)
155            };
156
157        if let Some(lifetime) = refresh_alloc_timer {
158            let _ = self.refresh_allocation(lifetime);
159        }
160        if refresh_perms_timer {
161            let _ = self.refresh_permissions();
162        }
163    }
164
165    /// Sends `p` to `peer_addr` through the relay.
166    ///
167    /// Uses ChannelData framing if a channel is bound for that peer, otherwise a Data indication.
168    ///
169    /// # Errors
170    ///
171    /// Fails if the allocation is gone, or if no permission exists for `peer_addr`.
172    pub fn send_to(&mut self, p: &[u8], peer_addr: SocketAddr) -> Result<()> {
173        // check if we have a permission for the destination IP addr
174        let result = if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
175            if let Some(perm) = relay.perm_map.get_mut(&peer_addr) {
176                if perm.state() != PermState::Permitted {
177                    Err(Error::ErrNoPermission)
178                } else {
179                    Ok((relay.integrity.clone(), relay.nonce.clone()))
180                }
181            } else {
182                Err(Error::ErrNoPermission)
183            }
184        } else {
185            Err(Error::ErrConnClosed)
186        };
187
188        let (integrity, nonce) = result?;
189
190        self.send(p, peer_addr, integrity, nonce)
191    }
192
193    fn send(
194        &mut self,
195        p: &[u8],
196        peer_addr: SocketAddr,
197        integrity: MessageIntegrity,
198        nonce: Nonce,
199    ) -> Result<()> {
200        let channel_number = {
201            let (bind_st, bind_at, bind_number, bind_addr) = {
202                let b = if let Some(b) = self.client.binding_mgr.find_by_addr(&peer_addr) {
203                    b
204                } else {
205                    self.client
206                        .binding_mgr
207                        .create(peer_addr)
208                        .ok_or_else(|| Error::Other("Addr not found".to_owned()))?
209                };
210                (b.state(), b.refreshed_at(), b.number, b.addr)
211            };
212
213            if bind_st == BindingState::Idle
214                || bind_st == BindingState::Request
215                || bind_st == BindingState::Failed
216            {
217                // block only callers with the same binding until
218                // the binding transaction has been complete
219                // binding state may have been changed while waiting. check again.
220                if bind_st == BindingState::Idle {
221                    if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
222                        b.set_state(BindingState::Request);
223                    }
224                    self.channel_bind(self.relayed_addr, bind_addr, bind_number, nonce, integrity)?;
225                }
226
227                // send data using SendIndication
228                let mut msg = Message::new();
229                msg.build(&[
230                    Box::new(TransactionId::new()),
231                    Box::new(MessageType::new(METHOD_SEND, CLASS_INDICATION)),
232                    Box::new(proto::data::Data(p.to_vec())),
233                    Box::new(proto::peeraddr::PeerAddress {
234                        ip: peer_addr.ip(),
235                        port: peer_addr.port(),
236                    }),
237                    Box::new(FINGERPRINT),
238                ])?;
239
240                // indication has no transaction (fire-and-forget)
241                self.client
242                    .write_to(&msg.raw, self.client.turn_server_addr()?);
243                return Ok(());
244            }
245
246            // binding is ready
247            // check if the binding needs a refresh
248            if bind_st == BindingState::Ready
249                && Instant::now()
250                    .checked_duration_since(bind_at)
251                    .unwrap_or_else(|| Duration::from_secs(0))
252                    > PERM_LIFETIME
253            {
254                if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
255                    b.set_state(BindingState::Refresh);
256                }
257                self.channel_bind(self.relayed_addr, bind_addr, bind_number, nonce, integrity)?;
258            }
259
260            bind_number
261        };
262
263        // send via ChannelData
264        self.send_channel_data(p, channel_number)
265    }
266
267    // Close closes the connection.
268    // Any blocked ReadFrom or write_to operations will be unblocked and return errors.
269    /// Releases the allocation by refreshing it with a zero lifetime.
270    ///
271    /// # Errors
272    ///
273    /// Fails if the refresh request cannot be sent.
274    pub fn close(&mut self) -> Result<()> {
275        self.refresh_allocation(Duration::from_secs(0))
276    }
277
278    fn create_permissions(
279        &mut self,
280        peer_addrs: &[SocketAddr],
281        peer_addr_opt: Option<SocketAddr>,
282    ) -> Result<TransactionId> {
283        let (username, realm) = (self.client.username(), self.client.realm());
284        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
285            let msg = {
286                let mut setters: Vec<Box<dyn Setter>> = vec![
287                    Box::new(TransactionId::new()),
288                    Box::new(MessageType::new(METHOD_CREATE_PERMISSION, CLASS_REQUEST)),
289                ];
290
291                for addr in peer_addrs {
292                    setters.push(Box::new(proto::peeraddr::PeerAddress {
293                        ip: addr.ip(),
294                        port: addr.port(),
295                    }));
296                }
297
298                setters.push(Box::new(username));
299                setters.push(Box::new(realm));
300                setters.push(Box::new(relay.nonce.clone()));
301                setters.push(Box::new(relay.integrity.clone()));
302                setters.push(Box::new(FINGERPRINT));
303
304                let mut msg = Message::new();
305                msg.build(&setters)?;
306                msg
307            };
308
309            Ok(self.client.perform_transaction(
310                &msg,
311                self.client.turn_server_addr()?,
312                TransactionType::CreatePermissionRequest(self.relayed_addr, peer_addr_opt),
313            ))
314        } else {
315            Err(Error::ErrConnClosed)
316        }
317    }
318
319    pub(super) fn handle_create_permission_response(
320        &mut self,
321        res: Message,
322        peer_addr_opt: Option<SocketAddr>,
323    ) -> Result<()> {
324        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
325            if res.typ.class == CLASS_ERROR_RESPONSE {
326                let mut code = ErrorCodeAttribute::default();
327                let result = code.get_from(&res);
328                let err = if result.is_err() {
329                    Error::Other(format!("{}", res.typ))
330                } else if code.code == CODE_STALE_NONCE {
331                    relay.set_nonce_from_msg(&res);
332                    Error::ErrTryAgain
333                } else {
334                    Error::Other(format!("{} (error {})", res.typ, code))
335                };
336                if let Some(peer_addr) = peer_addr_opt {
337                    self.client
338                        .events
339                        .push_back(Event::CreatePermissionError(res.transaction_id, err));
340                    relay.perm_map.remove(&peer_addr);
341                }
342            } else if let Some(peer_addr) = peer_addr_opt
343                && let Some(perm) = relay.perm_map.get_mut(&peer_addr)
344            {
345                perm.set_state(PermState::Permitted);
346                self.client
347                    .events
348                    .push_back(Event::CreatePermissionResponse(
349                        res.transaction_id,
350                        peer_addr,
351                    ));
352            }
353
354            Ok(())
355        } else {
356            Err(Error::ErrConnClosed)
357        }
358    }
359
360    pub(super) fn refresh_allocation(&mut self, lifetime: Duration) -> Result<()> {
361        let (username, realm) = (self.client.username(), self.client.realm());
362        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
363            let mut msg = Message::new();
364            msg.build(&[
365                Box::new(TransactionId::new()),
366                Box::new(MessageType::new(METHOD_REFRESH, CLASS_REQUEST)),
367                Box::new(proto::lifetime::Lifetime(lifetime)),
368                Box::new(username),
369                Box::new(realm),
370                Box::new(relay.nonce.clone()),
371                Box::new(relay.integrity.clone()),
372                Box::new(FINGERPRINT),
373            ])?;
374
375            let _ = self.client.perform_transaction(
376                &msg,
377                self.client.turn_server_addr()?,
378                TransactionType::RefreshRequest(self.relayed_addr),
379            );
380
381            Ok(())
382        } else {
383            Err(Error::ErrConnClosed)
384        }
385    }
386
387    pub(super) fn handle_refresh_allocation_response(&mut self, res: Message) -> Result<()> {
388        let mut released = false;
389        let result = if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
390            if res.typ.class == CLASS_ERROR_RESPONSE {
391                let mut code = ErrorCodeAttribute::default();
392                let result = code.get_from(&res);
393                if result.is_err() {
394                    Err(Error::Other(format!("{}", res.typ)))
395                } else if code.code == CODE_STALE_NONCE {
396                    relay.set_nonce_from_msg(&res);
397                    //Error::ErrTryAgain
398                    Ok(())
399                } else {
400                    Err(Error::Other(format!("{} (error {})", res.typ, code)))
401                }
402            } else {
403                // Getting lifetime from response
404                let mut updated_lifetime = proto::lifetime::Lifetime::default();
405                updated_lifetime.get_from(&res)?;
406
407                relay.lifetime = updated_lifetime.0;
408                debug!("updated lifetime: {} seconds", relay.lifetime.as_secs());
409
410                // A zero lifetime is the server confirming deallocation — the reply to the
411                // refresh `close()` sends. The allocation no longer exists, so neither should
412                // the relay: leaving it in the map means it keeps reporting refresh deadlines
413                // for something that is gone, and keeps trying to refresh it.
414                released = relay.lifetime.is_zero();
415
416                Ok(())
417            }
418        } else {
419            Err(Error::ErrConnClosed)
420        };
421
422        if released {
423            self.client.relays.remove(&self.relayed_addr);
424            debug!("allocation released; relay {} dropped", self.relayed_addr);
425        }
426
427        result
428    }
429
430    pub(super) fn refresh_permissions(&mut self) -> Result<()> {
431        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
432            #[allow(clippy::map_clone)]
433            let addrs: Vec<SocketAddr> = relay.perm_map.keys().map(|addr| *addr).collect();
434            if addrs.is_empty() {
435                debug!("no permission to refresh");
436                return Ok(());
437            }
438            let _ = self.create_permissions(&addrs, None)?;
439            Ok(())
440        } else {
441            Err(Error::ErrConnClosed)
442        }
443    }
444
445    fn channel_bind(
446        &mut self,
447        relayed_addr: RelayedAddr,
448        bind_addr: SocketAddr,
449        bind_number: u16,
450        nonce: Nonce,
451        integrity: MessageIntegrity,
452    ) -> Result<()> {
453        let (msg, turn_server_addr) = {
454            let setters: Vec<Box<dyn Setter>> = vec![
455                Box::new(TransactionId::new()),
456                Box::new(MessageType::new(METHOD_CHANNEL_BIND, CLASS_REQUEST)),
457                Box::new(proto::peeraddr::PeerAddress {
458                    ip: bind_addr.ip(),
459                    port: bind_addr.port(),
460                }),
461                Box::new(proto::channum::ChannelNumber(bind_number)),
462                Box::new(self.client.username()),
463                Box::new(self.client.realm()),
464                Box::new(nonce),
465                Box::new(integrity),
466                Box::new(FINGERPRINT),
467            ];
468
469            let mut msg = Message::new();
470            msg.build(&setters)?;
471
472            (msg, self.client.turn_server_addr()?)
473        };
474
475        debug!("UDPConn.bind call PerformTransaction 1");
476        let _ = self.client.perform_transaction(
477            &msg,
478            turn_server_addr,
479            TransactionType::ChannelBindRequest(relayed_addr, bind_addr),
480        );
481
482        Ok(())
483    }
484
485    pub(super) fn handle_channel_bind_response(
486        &mut self,
487        res: Message,
488        bind_addr: SocketAddr,
489    ) -> Result<()> {
490        if let Some(relay) = self.client.relays.get_mut(&self.relayed_addr) {
491            let result = if res.typ.class == CLASS_ERROR_RESPONSE {
492                let mut code = ErrorCodeAttribute::default();
493                let result = code.get_from(&res);
494                if result.is_err() {
495                    Err(Error::Other(format!("{}", res.typ)))
496                } else if code.code == CODE_STALE_NONCE {
497                    relay.set_nonce_from_msg(&res);
498                    Err(Error::ErrTryAgain)
499                } else {
500                    Err(Error::Other(format!("{} (error {})", res.typ, code)))
501                }
502            } else if res.typ != MessageType::new(METHOD_CHANNEL_BIND, CLASS_SUCCESS_RESPONSE) {
503                Err(Error::ErrUnexpectedResponse)
504            } else {
505                Ok(())
506            };
507
508            if let Err(err) = result {
509                if Error::ErrUnexpectedResponse != err {
510                    self.client.binding_mgr.delete_by_addr(&bind_addr);
511                } else if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
512                    b.set_state(BindingState::Failed);
513                }
514
515                // keep going...
516                warn!("bind() failed: {}", err);
517            } else if let Some(b) = self.client.binding_mgr.get_by_addr(&bind_addr) {
518                b.set_refreshed_at(Instant::now());
519                b.set_state(BindingState::Ready);
520                debug!("channel binding successful: {}", bind_addr);
521            }
522            Ok(())
523        } else {
524            Err(Error::ErrConnClosed)
525        }
526    }
527
528    fn send_channel_data(&mut self, data: &[u8], channel_number: u16) -> Result<()> {
529        let mut ch_data = proto::chandata::ChannelData {
530            data: data.to_vec(),
531            number: proto::channum::ChannelNumber(channel_number),
532            ..Default::default()
533        };
534        ch_data.encode();
535
536        self.client
537            .write_to(&ch_data.raw, self.client.turn_server_addr()?);
538
539        Ok(())
540    }
541}