Skip to main content

rtc_turn/client/
mod.rs

1//! The Sans-I/O TURN client.
2//!
3//! Using a relay takes three steps: Allocate to obtain a public address, CreatePermission for
4//! each peer you intend to exchange data with, and then Send/Data indications (or a bound channel)
5//! to move bytes. Each step is a STUN transaction, so every [`Event`] carries the
6//! transaction id of the request it answers.
7//!
8//! The three address kinds are easy to confuse: [`RelayedAddr`] is what peers send to,
9//! [`ReflexiveAddr`] is how the server sees this client, and [`PeerAddr`] is the far end.
10#[cfg(test)]
11mod client_test;
12
13/// Channel bindings, which replace the 36-byte Data indication header with a 4-byte one.
14pub mod binding;
15/// Per-peer send permissions, which a relay requires before it will forward to an address.
16pub mod permission;
17mod proto;
18/// A live allocation on the server, and sending or receiving through it.
19pub mod relay;
20/// Outstanding request tracking, with the RFC's retransmission schedule.
21pub mod transaction;
22
23use bytes::BytesMut;
24use crypto::RTCCryptoProvider;
25use log::{debug, trace};
26use std::collections::{HashMap, VecDeque};
27use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
28use std::sync::Arc;
29use std::time::{Duration, Instant};
30
31use stun::attributes::*;
32use stun::integrity::*;
33use stun::message::*;
34use stun::textattrs::*;
35use stun::xoraddr::*;
36
37use binding::*;
38use transaction::*;
39
40use crate::client::relay::{Relay, RelayState};
41use crate::proto::chandata::*;
42use crate::proto::channum::ChannelNumber;
43use crate::proto::data::*;
44use crate::proto::lifetime::Lifetime;
45use crate::proto::peeraddr::*;
46use crate::proto::relayaddr::RelayedAddress;
47use crate::proto::reqtrans::RequestedTransport;
48use crate::proto::{PROTO_TCP, PROTO_UDP};
49use shared::error::{Error, Result};
50use shared::util::lookup_host;
51use shared::{TransportContext, TransportMessage, TransportProtocol};
52use stun::error_code::ErrorCodeAttribute;
53use stun::fingerprint::FINGERPRINT;
54
55const DEFAULT_RTO_IN_MS: u64 = 200;
56const MAX_DATA_BUFFER_SIZE: usize = u16::MAX as usize; // message size limit for Chromium
57const MAX_READ_QUEUE_SIZE: usize = 1024;
58
59/// The public address the TURN server allocated on this client's behalf.
60///
61/// Peers send here; the server forwards to the client.
62pub type RelayedAddr = SocketAddr;
63/// The client's own address as seen by the server — its server-reflexive address.
64pub type ReflexiveAddr = SocketAddr;
65/// The address of a remote peer the client exchanges data with through the relay.
66pub type PeerAddr = SocketAddr;
67
68#[derive(Debug)]
69/// What the client produces in response to inbound datagrams and elapsed time.
70///
71/// Every variant carries the [`TransactionId`] of the request it answers, so a caller can
72/// match responses to the requests it issued.
73#[non_exhaustive]
74pub enum Event {
75    /// A request exhausted its retransmissions without a response.
76    TransactionTimeout(TransactionId),
77
78    /// A STUN Binding succeeded, reporting this client's server-reflexive address.
79    BindingResponse(TransactionId, ReflexiveAddr),
80    /// A STUN Binding failed.
81    BindingError(TransactionId, Error),
82
83    /// An Allocate succeeded; the relayed address is now usable.
84    AllocateResponse(TransactionId, RelayedAddr),
85    /// An Allocate failed — commonly authentication, or the server being out of ports.
86    AllocateError(TransactionId, Error),
87
88    /// A CreatePermission succeeded; the relay will now forward to and from this peer.
89    CreatePermissionResponse(TransactionId, PeerAddr),
90    /// A CreatePermission failed.
91    CreatePermissionError(TransactionId, Error),
92
93    /// Data arrived from a peer through the relay.
94    ///
95    /// The channel number is `Some` when it came as ChannelData and `None` when it came as a
96    /// Data indication.
97    DataIndicationOrChannelData(Option<ChannelNumber>, PeerAddr, BytesMut),
98}
99
100enum AllocateState {
101    Attempting,
102    Requesting(TextAttribute),
103}
104
105//              interval [msec]
106// 0: 0 ms      +500
107// 1: 500 ms	+1000
108// 2: 1500 ms   +2000
109// 3: 3500 ms   +4000
110// 4: 7500 ms   +8000
111// 5: 15500 ms  +16000
112// 6: 31500 ms  +32000
113// -: 63500 ms  failed
114
115/// ClientConfig is a bag of config parameters for Client.
116pub struct ClientConfig {
117    /// The STUN server to use for Binding requests, as `host:port`. May be empty.
118    pub stun_serv_addr: String, // STUN server address (e.g. "stun.abc.com:3478")
119    /// The TURN server to allocate from, as `host:port`.
120    pub turn_serv_addr: String, // TURN server address (e.g. "turn.abc.com:3478")
121    /// The local address the client sends from.
122    pub local_addr: SocketAddr,
123    /// Whether to reach the server over UDP or TCP.
124    pub transport_protocol: TransportProtocol,
125    /// The long-term credential username for the TURN server.
126    pub username: String,
127    /// The long-term credential password.
128    pub password: String,
129    /// The authentication realm, used in the `MESSAGE-INTEGRITY` computation.
130    pub realm: String,
131    /// An optional `SOFTWARE` attribute value, sent for diagnostics.
132    pub software: String,
133    /// The initial retransmission timeout in milliseconds; each retry doubles it.
134    pub rto_in_ms: u64,
135    /// Optional upper bound for the interval between allocation Refresh requests.
136    ///
137    /// By default, allocations are refreshed at half the lifetime advertised by the server.
138    /// A shorter cap can also keep the client-to-server NAT mapping active when an allocation
139    /// waits without carrying application traffic. Values below one second are rounded up.
140    pub allocation_refresh_interval_cap: Option<Duration>,
141}
142
143impl Default for ClientConfig {
144    fn default() -> Self {
145        Self {
146            stun_serv_addr: "".to_string(),
147            turn_serv_addr: "".to_string(),
148            local_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)),
149            transport_protocol: Default::default(),
150            username: "".to_string(),
151            password: "".to_string(),
152            realm: "".to_string(),
153            software: "".to_string(),
154            rto_in_ms: 0,
155            allocation_refresh_interval_cap: None,
156        }
157    }
158}
159
160/// Client is a STUN client
161pub struct Client {
162    crypto_provider: Arc<dyn RTCCryptoProvider>,
163    stun_serv_addr: Option<SocketAddr>,
164    turn_serv_addr: Option<SocketAddr>,
165    local_addr: SocketAddr,
166    transport_protocol: TransportProtocol,
167    username: Username,
168    password: String,
169    realm: Realm,
170    software: Software,
171    tr_map: TransactionMap,
172    binding_mgr: BindingManager,
173    rto_in_ms: u64,
174    allocation_refresh_interval_cap: Option<Duration>,
175
176    relays: HashMap<RelayedAddr, RelayState>,
177    transmits: VecDeque<TransportMessage<BytesMut>>,
178    events: VecDeque<Event>,
179}
180
181impl Client {
182    /// Returns a new TURN client.
183    ///
184    /// The crypto provider is supplied by the caller; this crate never resolves a default.
185    pub fn new(config: ClientConfig, crypto_provider: Arc<dyn RTCCryptoProvider>) -> Result<Self> {
186        let stun_serv_addr = if config.stun_serv_addr.is_empty() {
187            None
188        } else {
189            Some(lookup_host(
190                config.local_addr.is_ipv4(),
191                config.stun_serv_addr.as_str(),
192            )?)
193        };
194
195        let turn_serv_addr = if config.turn_serv_addr.is_empty() {
196            None
197        } else {
198            Some(lookup_host(
199                config.local_addr.is_ipv4(),
200                config.turn_serv_addr.as_str(),
201            )?)
202        };
203
204        Ok(Client {
205            crypto_provider: crypto_provider.clone(),
206            stun_serv_addr,
207            turn_serv_addr,
208            local_addr: config.local_addr,
209            transport_protocol: config.transport_protocol,
210            username: Username::new(ATTR_USERNAME, config.username),
211            password: config.password,
212            realm: Realm::new(ATTR_REALM, config.realm),
213            software: Software::new(ATTR_SOFTWARE, config.software),
214            tr_map: TransactionMap::new(),
215            binding_mgr: BindingManager::new(),
216            rto_in_ms: if config.rto_in_ms != 0 {
217                config.rto_in_ms
218            } else {
219                DEFAULT_RTO_IN_MS
220            },
221            allocation_refresh_interval_cap: config.allocation_refresh_interval_cap,
222            relays: HashMap::new(),
223            transmits: VecDeque::new(),
224            events: VecDeque::new(),
225        })
226    }
227
228    // handle_inbound handles data received.
229    // This method handles incoming packet demultiplex it by the source address
230    // and the types of the message.
231    // This return Ok(handled or not) and if there was an error.
232    // Caller should check if the packet was handled by this client or not.
233    // If not handled, it is assumed that the packet is application data.
234    // If an error is returned, the caller should discard the packet regardless.
235    fn handle_inbound(&mut self, now: Instant, data: &[u8], from: SocketAddr) -> Result<()> {
236        // +-------------------+-------------------------------+
237        // |   Return Values   |                               |
238        // +-------------------+       Meaning / Action        |
239        // | handled |  error  |                               |
240        // |=========+=========+===============================+
241        // |  false  |   nil   | Handle the packet as app data |
242        // |---------+---------+-------------------------------+
243        // |  true   |   nil   |        Nothing to do          |
244        // |---------+---------+-------------------------------+
245        // |  false  |  error  |     (shouldn't happen)        |
246        // |---------+---------+-------------------------------+
247        // |  true   |  error  | Error occurred while handling |
248        // +---------+---------+-------------------------------+
249        // Possible causes of the error:
250        //  - Malformed packet (parse error)
251        //  - STUN message was a request
252        //  - Non-STUN message from the STUN server
253
254        if is_stun_message(data) {
255            self.handle_stun_message(now, data)
256        } else if ChannelData::is_channel_data(data) {
257            self.handle_channel_data(data)
258        } else if self.stun_serv_addr.is_some() && &from == self.stun_serv_addr.as_ref().unwrap() {
259            // received from STUN server, but it is not a STUN message
260            Err(Error::ErrNonStunmessage)
261        } else {
262            // assume, this is an application data
263            trace!("non-STUN/TURN packet, unhandled");
264            Ok(())
265        }
266    }
267
268    fn handle_stun_message(&mut self, now: Instant, data: &[u8]) -> Result<()> {
269        let mut msg = Message::new();
270        msg.raw = data.to_vec();
271        msg.decode()?;
272
273        if msg.typ.class == CLASS_REQUEST {
274            return Err(Error::Other(format!(
275                "{:?} : {}",
276                Error::ErrUnexpectedStunrequestMessage,
277                msg
278            )));
279        }
280
281        if msg.typ.class == CLASS_INDICATION {
282            if msg.typ.method == METHOD_DATA {
283                let mut peer_addr = PeerAddress::default();
284                peer_addr.get_from(&msg)?;
285                let from = SocketAddr::new(peer_addr.ip, peer_addr.port);
286
287                let mut data = Data::default();
288                data.get_from(&msg)?;
289
290                debug!("data indication received from {}", from);
291
292                self.events.push_back(Event::DataIndicationOrChannelData(
293                    None,
294                    from,
295                    BytesMut::from(&data.0[..]),
296                ))
297            }
298
299            return Ok(());
300        }
301
302        // This is a STUN response message (transactional)
303        // The type is either:
304        // - stun.ClassSuccessResponse
305        // - stun.ClassErrorResponse
306
307        if self.tr_map.find(&msg.transaction_id).is_none() {
308            // silently discard
309            debug!("no transaction for {}", msg);
310            return Ok(());
311        }
312
313        if let Some(tr) = self.tr_map.delete(&msg.transaction_id) {
314            match msg.typ.method {
315                METHOD_BINDING => {
316                    if msg.typ.class == CLASS_ERROR_RESPONSE {
317                        let mut code = ErrorCodeAttribute::default();
318                        let err = if code.get_from(&msg).is_err() {
319                            Error::Other(format!("{}", msg.typ))
320                        } else {
321                            Error::Other(format!("{} (error {})", msg.typ, code))
322                        };
323                        self.events
324                            .push_back(Event::BindingError(tr.transaction_id, err));
325                    } else {
326                        let mut refl_addr = XorMappedAddress::default();
327                        match refl_addr.get_from(&msg) {
328                            Ok(_) => {
329                                self.events.push_back(Event::BindingResponse(
330                                    tr.transaction_id,
331                                    ReflexiveAddr::new(refl_addr.ip, refl_addr.port),
332                                ));
333                            }
334                            Err(err) => {
335                                self.events
336                                    .push_back(Event::BindingError(tr.transaction_id, err));
337                            }
338                        }
339                    }
340                }
341                METHOD_ALLOCATE => {
342                    self.handle_allocate_response(now, msg, tr.transaction_type)?;
343                }
344                METHOD_CREATE_PERMISSION => {
345                    if let TransactionType::CreatePermissionRequest(relayed_addr, peer_addr) =
346                        tr.transaction_type
347                    {
348                        let mut relay = Relay {
349                            relayed_addr,
350                            client: self,
351                        };
352                        relay.handle_create_permission_response(msg, peer_addr)?;
353                    }
354                }
355                METHOD_REFRESH => {
356                    if let TransactionType::RefreshRequest(relayed_addr) = tr.transaction_type {
357                        let mut relay = Relay {
358                            relayed_addr,
359                            client: self,
360                        };
361                        relay.handle_refresh_allocation_response(msg)?;
362                    }
363                }
364                METHOD_CHANNEL_BIND => {
365                    if let TransactionType::ChannelBindRequest(relayed_addr, bind_addr) =
366                        tr.transaction_type
367                    {
368                        let mut relay = Relay {
369                            relayed_addr,
370                            client: self,
371                        };
372                        relay.handle_channel_bind_response(now, msg, bind_addr)?;
373                    }
374                }
375                _ => {}
376            }
377        }
378
379        Ok(())
380    }
381
382    fn handle_channel_data(&mut self, data: &[u8]) -> Result<()> {
383        let mut ch_data = ChannelData {
384            raw: data.to_vec(),
385            ..Default::default()
386        };
387        ch_data.decode()?;
388
389        let addr = self
390            .find_addr_by_channel_number(ch_data.number.0)
391            .ok_or(Error::ErrChannelBindNotFound)?;
392
393        trace!(
394            "channel data received from {} (ch={})",
395            addr, ch_data.number.0
396        );
397
398        self.events.push_back(Event::DataIndicationOrChannelData(
399            Some(ch_data.number),
400            addr,
401            BytesMut::from(&ch_data.data[..]),
402        ));
403
404        Ok(())
405    }
406
407    /// Borrows the allocation for `relayed_addr` so data can be sent or permissions created.
408    ///
409    /// # Errors
410    ///
411    /// Fails if this client has no allocation for that address — it was never allocated, or has
412    /// already been closed.
413    pub fn relay(&mut self, relayed_addr: SocketAddr) -> Result<Relay<'_>> {
414        if !self.relays.contains_key(&relayed_addr) {
415            Err(Error::ErrStreamNotExisted)
416        } else {
417            Ok(Relay {
418                relayed_addr,
419                client: self,
420            })
421        }
422    }
423
424    /// send_binding_request_to sends a new STUN request to the given transport address
425    /// return key to find out corresponding Event either BindingResponse or BindingRequestTimeout
426    pub fn send_binding_request_to(
427        &mut self,
428        now: Instant,
429        to: SocketAddr,
430    ) -> Result<TransactionId> {
431        let msg = {
432            let attrs: Vec<Box<dyn Setter + '_>> = if !self.software.text.is_empty() {
433                vec![
434                    Box::new(TransactionId::new()),
435                    Box::new(BINDING_REQUEST),
436                    Box::new(self.software.clone()),
437                ]
438            } else {
439                vec![Box::new(TransactionId::new()), Box::new(BINDING_REQUEST)]
440            };
441
442            let mut msg = Message::new();
443            msg.build(&attrs)?;
444            msg
445        };
446
447        debug!("client.SendBindingRequestTo call PerformTransaction 1");
448        Ok(self.perform_transaction(now, &msg, to, TransactionType::BindingRequest))
449    }
450
451    /// send_binding_request sends a new STUN request to the STUN server
452    /// return key to find out corresponding Event either BindingResponse or BindingRequestTimeout
453    pub fn send_binding_request(&mut self, now: Instant) -> Result<TransactionId> {
454        if let Some(stun_serv_addr) = &self.stun_serv_addr {
455            self.send_binding_request_to(now, *stun_serv_addr)
456        } else {
457            Err(Error::ErrStunserverAddressNotSet)
458        }
459    }
460
461    // find_addr_by_channel_number returns a peer address associated with the
462    // channel number on this UDPConn
463    fn find_addr_by_channel_number(&self, ch_num: u16) -> Option<SocketAddr> {
464        self.binding_mgr.find_by_number(ch_num).map(|b| b.addr)
465    }
466
467    // stun_server_addr return the STUN server address
468    fn stun_server_addr(&self) -> Option<SocketAddr> {
469        self.stun_serv_addr
470    }
471
472    /* https://datatracker.ietf.org/doc/html/rfc8656#section-20
473    TURN                                 TURN          Peer         Peer
474    client                               server         A            B
475      |                                    |            |            |
476      |--- Allocate request -------------->|            |            |
477      |    Transaction-Id=0xA56250D3F17ABE679422DE85    |            |
478      |    SOFTWARE="Example client, version 1.03"      |            |
479      |    LIFETIME=3600 (1 hour)          |            |            |
480      |    REQUESTED-TRANSPORT=17 (UDP)    |            |            |
481      |    DONT-FRAGMENT                   |            |            |
482      |                                    |            |            |
483      |<-- Allocate error response --------|            |            |
484      |    Transaction-Id=0xA56250D3F17ABE679422DE85    |            |
485      |    SOFTWARE="Example server, version 1.17"      |            |
486      |    ERROR-CODE=401 (Unauthorized)   |            |            |
487      |    REALM="example.com"             |            |            |
488      |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
489      |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
490      |                                    |            |            |
491      |--- Allocate request -------------->|            |            |
492      |    Transaction-Id=0xC271E932AD7446A32C234492    |            |
493      |    SOFTWARE="Example client 1.03"  |            |            |
494      |    LIFETIME=3600 (1 hour)          |            |            |
495      |    REQUESTED-TRANSPORT=17 (UDP)    |            |            |
496      |    DONT-FRAGMENT                   |            |            |
497      |    USERNAME="George"               |            |            |
498      |    REALM="example.com"             |            |            |
499      |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
500      |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
501      |    PASSWORD-ALGORITHM=SHA256       |            |            |
502      |    MESSAGE-INTEGRITY=...           |            |            |
503      |    MESSAGE-INTEGRITY-SHA256=...    |            |            |
504      |                                    |            |            |
505      |<-- Allocate success response ------|            |            |
506      |    Transaction-Id=0xC271E932AD7446A32C234492    |            |
507      |    SOFTWARE="Example server, version 1.17"      |            |
508      |    LIFETIME=1200 (20 minutes)      |            |            |
509      |    XOR-RELAYED-ADDRESS=192.0.2.15:50000         |            |
510      |    XOR-MAPPED-ADDRESS=192.0.2.1:7000            |            |
511      |    MESSAGE-INTEGRITY-SHA256=...    |            |            |
512    */
513    /// Replaces the long-term credential used to sign subsequent requests, **keeping any
514    /// existing allocation**.
515    ///
516    /// A TURN allocation is a property of the 5-tuple, not of the credential that created
517    /// it: [RFC 5766 §6.2] identifies an allocation by 5-tuple, and a server's
518    /// `Refresh` handling looks it up the same way. So when credentials are rotated on the
519    /// same server there is no need to give up the allocation and re-`Allocate` — which
520    /// would in fact be rejected with **437 (Allocation Mismatch)**, since the server still
521    /// holds the previous allocation for that 5-tuple. Re-signing the existing allocation is
522    /// both correct and seamless: permissions and channel bindings survive.
523    ///
524    /// The realm is *not* re-negotiated. It was learned from the server's 401 during the
525    /// first `Allocate`, and a credential rotation keeps the same server, so it still
526    /// applies. Follow this with [`Self::refresh_allocations`] so the server sees the new
527    /// credential before the allocation would otherwise expire.
528    ///
529    /// [RFC 5766 §6.2]: https://datatracker.ietf.org/doc/html/rfc5766#section-6.2
530    pub fn update_credentials(&mut self, username: String, password: String) -> Result<()> {
531        let username = Username::new(ATTR_USERNAME, username);
532        let long_term_integrity_key = MessageIntegrity::long_term_integrity_key(
533            username.text.clone(),
534            self.realm.text.clone(),
535            password.clone(),
536            self.crypto_provider.crypto(),
537        )?;
538        self.username = username;
539        self.password = password;
540
541        // Each allocation carries the integrity it will sign its own Refresh /
542        // CreatePermission / ChannelBind with, so they have to be re-signed too — otherwise
543        // the next refresh would still present the retired credential.
544        for relay in self.relays.values_mut() {
545            relay.long_term_integrity_key = long_term_integrity_key.clone();
546        }
547
548        Ok(())
549    }
550
551    /// Refreshes every live allocation, re-signing each with the current credential.
552    ///
553    /// Each allocation is refreshed with its own current lifetime, so this extends rather
554    /// than changes it. Intended to follow [`update_credentials`](Self::update_credentials).
555    pub fn refresh_allocations(&mut self, now: Instant) -> Result<()> {
556        let relays: Vec<(RelayedAddr, Duration)> = self
557            .relays
558            .iter()
559            .map(|(addr, relay)| (*addr, relay.lifetime))
560            .collect();
561
562        for (relayed_addr, lifetime) in relays {
563            self.relay(relayed_addr)?
564                .refresh_allocation(now, lifetime)?;
565        }
566
567        Ok(())
568    }
569
570    /// Allocate sends a TURN allocation request to the given transport address
571    pub fn allocate(&mut self, now: Instant) -> Result<TransactionId> {
572        let mut msg = Message::new();
573        msg.build(&[
574            Box::new(TransactionId::new()),
575            Box::new(MessageType::new(METHOD_ALLOCATE, CLASS_REQUEST)),
576            Box::new(RequestedTransport {
577                protocol: if self.transport_protocol == TransportProtocol::UDP {
578                    PROTO_UDP
579                } else {
580                    PROTO_TCP
581                },
582            }),
583            Box::new(FINGERPRINT),
584        ])?;
585
586        debug!("client.Allocate call PerformTransaction 1");
587        let mut tid = self.perform_transaction(
588            now,
589            &msg,
590            self.turn_server_addr()?,
591            TransactionType::AllocateAttempt,
592        );
593        tid.0[TRANSACTION_ID_SIZE - 1] = tid.0[TRANSACTION_ID_SIZE - 1].wrapping_add(1);
594        Ok(tid)
595    }
596
597    fn handle_allocate_response(
598        &mut self,
599        now: Instant,
600        response: Message,
601        allocate_state: TransactionType,
602    ) -> Result<()> {
603        match allocate_state {
604            TransactionType::AllocateAttempt => {
605                // Anonymous allocate failed, trying to authenticate.
606                let nonce = match Nonce::get_from_as(&response, ATTR_NONCE) {
607                    Ok(nonce) => nonce,
608                    Err(err) => {
609                        self.events
610                            .push_back(Event::AllocateError(response.transaction_id, err));
611                        return Ok(());
612                    }
613                };
614                self.realm = match Realm::get_from_as(&response, ATTR_REALM) {
615                    Ok(realm) => realm,
616                    Err(err) => {
617                        self.events
618                            .push_back(Event::AllocateError(response.transaction_id, err));
619                        return Ok(());
620                    }
621                };
622
623                let integrity = MessageIntegrity::new_long_term_integrity_with_provider(
624                    self.username.text.clone(),
625                    self.realm.text.clone(),
626                    self.password.clone(),
627                    self.crypto_provider.crypto(),
628                )?;
629
630                let mut msg = Message::new();
631
632                // make it same as allocate() return value so that client can retrieve it
633                // from Event::AllocateResponse
634                let mut tid = response.transaction_id;
635                tid.0[TRANSACTION_ID_SIZE - 1] = tid.0[TRANSACTION_ID_SIZE - 1].wrapping_add(1);
636
637                // Trying to authorize.
638                msg.build(&[
639                    Box::new(tid),
640                    Box::new(MessageType::new(METHOD_ALLOCATE, CLASS_REQUEST)),
641                    Box::new(RequestedTransport {
642                        protocol: if self.transport_protocol == TransportProtocol::UDP {
643                            PROTO_UDP
644                        } else {
645                            PROTO_TCP
646                        },
647                    }),
648                    Box::new(self.username.clone()),
649                    Box::new(self.realm.clone()),
650                    Box::new(nonce.clone()),
651                    Box::new(integrity),
652                    Box::new(FINGERPRINT),
653                ])?;
654
655                debug!("client.Allocate call PerformTransaction 2");
656                self.perform_transaction(
657                    now,
658                    &msg,
659                    self.turn_server_addr()?,
660                    TransactionType::AllocateRequest(nonce),
661                );
662            }
663            TransactionType::AllocateRequest(nonce) => {
664                if response.typ.class == CLASS_ERROR_RESPONSE {
665                    let mut code = ErrorCodeAttribute::default();
666                    let err = if code.get_from(&response).is_err() {
667                        Error::Other(format!("{}", response.typ))
668                    } else {
669                        Error::Other(format!("{} (error {})", response.typ, code))
670                    };
671                    self.events
672                        .push_back(Event::AllocateError(response.transaction_id, err));
673                    return Ok(());
674                }
675
676                // Getting relayed addresses from response.
677                let mut relayed = RelayedAddress::default();
678                relayed.get_from(&response)?;
679                let relayed_addr = RelayedAddr::new(relayed.ip, relayed.port);
680
681                // Getting lifetime from response
682                let mut lifetime = Lifetime::default();
683                lifetime.get_from(&response)?;
684
685                // A zero lifetime here is a protocol violation, not a degenerate allocation.
686                // RFC 5766 §6.2 has the server take `min(client proposed, server maximum)` and
687                // fall back to the *default* lifetime (600 s) whenever that computation does
688                // not exceed it — so the value returned by a successful Allocate is never
689                // below the default, and certainly never zero. Zero is meaningful only on the
690                // Refresh path (§7), where it means "allocation deleted".
691                //
692                // Accepting it would build a `RelayState` whose `refresh_alloc_timer` is
693                // `now.add(0)` — expired the instant it is created — for an allocation that is
694                // already gone. That relay then reports an expired refresh deadline forever,
695                // which is what a caller polling deadlines hot-loops on. See
696                // [webrtc#862](https://github.com/webrtc-rs/webrtc/issues/862).
697                if lifetime.0.is_zero() {
698                    self.events.push_back(Event::AllocateError(
699                        response.transaction_id,
700                        Error::Other(
701                            "Allocate success response carried LIFETIME=0; RFC 5766 §6.2 \
702                             requires at least the default lifetime"
703                                .to_owned(),
704                        ),
705                    ));
706                    return Ok(());
707                }
708
709                self.relays.insert(
710                    relayed_addr,
711                    RelayState::new(
712                        now,
713                        relayed_addr,
714                        MessageIntegrity::long_term_integrity_key(
715                            self.username.text.clone(),
716                            self.realm.text.clone(),
717                            self.password.clone(),
718                            self.crypto_provider.crypto(),
719                        )?,
720                        nonce,
721                        lifetime.0,
722                        self.allocation_refresh_interval_cap,
723                    ),
724                );
725                self.events.push_back(Event::AllocateResponse(
726                    response.transaction_id,
727                    relayed_addr,
728                ));
729            }
730            _ => {}
731        }
732        Ok(())
733    }
734
735    /// turn_server_addr return the TURN server address
736    fn turn_server_addr(&self) -> Result<SocketAddr> {
737        self.turn_serv_addr.ok_or(Error::ErrNilTurnSocket)
738    }
739
740    /// username returns username
741    fn username(&self) -> Username {
742        self.username.clone()
743    }
744
745    /// realm return realm
746    fn realm(&self) -> Realm {
747        self.realm.clone()
748    }
749
750    /// WriteTo sends data to the specified destination using the base socket.
751    fn write_to(&mut self, now: Instant, data: &[u8], remote: SocketAddr) {
752        self.transmits.push_back(TransportMessage {
753            now,
754            transport: TransportContext {
755                local_addr: self.local_addr,
756                peer_addr: remote,
757                transport_protocol: self.transport_protocol,
758                ecn: None,
759            },
760            message: BytesMut::from(data),
761        });
762    }
763
764    // PerformTransaction performs STUN transaction
765    fn perform_transaction(
766        &mut self,
767        now: Instant,
768        msg: &Message,
769        to: SocketAddr,
770        transaction_type: TransactionType,
771    ) -> TransactionId {
772        let tr = Transaction::new(TransactionConfig {
773            now,
774            transaction_id: msg.transaction_id,
775            transaction_type,
776            raw: BytesMut::from(&msg.raw[..]),
777            local_addr: self.local_addr,
778            peer_addr: to,
779            transport_protocol: self.transport_protocol,
780            interval: self.rto_in_ms,
781        });
782
783        trace!(
784            "start {} transaction {:?} to {}",
785            msg.typ, msg.transaction_id, tr.peer_addr
786        );
787        self.tr_map.insert(msg.transaction_id, tr);
788
789        self.write_to(now, &msg.raw, to);
790
791        msg.transaction_id
792    }
793}