Skip to main content

turn_server/service/
mod.rs

1pub mod routing;
2pub mod session;
3
4use std::{net::SocketAddr, sync::Arc};
5
6use crate::codec::{crypto::Password, message::attributes::PasswordAlgorithm};
7
8use self::{
9    routing::Router,
10    session::{Identifier, SessionManager, SessionManagerOptions, ports::PortRange},
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum Transport {
15    Udp,
16    Tcp,
17}
18
19impl ToString for Transport {
20    fn to_string(&self) -> String {
21        match self {
22            Transport::Udp => "UDP".to_string(),
23            Transport::Tcp => "TCP".to_string(),
24        }
25    }
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub struct InterfaceAddr {
30    pub addr: SocketAddr,
31    pub external: SocketAddr,
32    pub transport: Transport,
33}
34
35pub trait ServiceHandler: Send + Sync + 'static {
36    fn get_password(
37        &self,
38        id: &Identifier,
39        username: &str,
40        algorithm: PasswordAlgorithm,
41    ) -> impl Future<Output = Option<Password>> + Send;
42
43    /// allocate request
44    ///
45    /// [rfc8489](https://tools.ietf.org/html/rfc8489)
46    ///
47    /// In all cases, the server SHOULD only allocate ports from the range
48    /// 49152 - 65535 (the Dynamic and/or Private Port range [PORT-NUMBERS]),
49    /// unless the TURN server application knows, through some means not
50    /// specified here, that other applications running on the same host as
51    /// the TURN server application will not be impacted by allocating ports
52    /// outside this range.  This condition can often be satisfied by running
53    /// the TURN server application on a dedicated machine and/or by
54    /// arranging that any other applications on the machine allocate ports
55    /// before the TURN server application starts.  In any case, the TURN
56    /// server SHOULD NOT allocate ports in the range 0 - 1023 (the Well-
57    /// Known Port range) to discourage clients from using TURN to run
58    /// standard services.
59    #[allow(unused_variables)]
60    fn on_allocated(&self, id: &Identifier, username: &str, port: u16) {}
61
62    /// channel binding request
63    ///
64    /// The server MAY impose restrictions on the IP address and port values
65    /// allowed in the XOR-PEER-ADDRESS attribute; if a value is not allowed,
66    /// the server rejects the request with a 403 (Forbidden) error.
67    ///
68    /// If the request is valid, but the server is unable to fulfill the
69    /// request due to some capacity limit or similar, the server replies
70    /// with a 508 (Insufficient Capacity) error.
71    ///
72    /// Otherwise, the server replies with a ChannelBind success response.
73    /// There are no required attributes in a successful ChannelBind
74    /// response.
75    ///
76    /// If the server can satisfy the request, then the server creates or
77    /// refreshes the channel binding using the channel number in the
78    /// CHANNEL-NUMBER attribute and the transport address in the XOR-PEER-
79    /// ADDRESS attribute.  The server also installs or refreshes a
80    /// permission for the IP address in the XOR-PEER-ADDRESS attribute as
81    /// described in Section 9.
82    ///
83    /// NOTE: A server need not do anything special to implement
84    /// idempotency of ChannelBind requests over UDP using the
85    /// "stateless stack approach".  Retransmitted ChannelBind requests
86    /// will simply refresh the channel binding and the corresponding
87    /// permission.  Furthermore, the client must wait 5 minutes before
88    /// binding a previously bound channel number or peer address to a
89    /// different channel, eliminating the possibility that the
90    /// transaction would initially fail but succeed on a
91    /// retransmission.
92    #[allow(unused_variables)]
93    fn on_channel_bind(&self, id: &Identifier, username: &str, channel: u16) {}
94
95    /// create permission request
96    ///
97    /// [rfc8489](https://tools.ietf.org/html/rfc8489)
98    ///
99    /// When the server receives the CreatePermission request, it processes
100    /// as per [Section 5](https://tools.ietf.org/html/rfc8656#section-5)
101    /// plus the specific rules mentioned here.
102    ///
103    /// The message is checked for validity.  The CreatePermission request
104    /// MUST contain at least one XOR-PEER-ADDRESS attribute and MAY contain
105    /// multiple such attributes.  If no such attribute exists, or if any of
106    /// these attributes are invalid, then a 400 (Bad Request) error is
107    /// returned.  If the request is valid, but the server is unable to
108    /// satisfy the request due to some capacity limit or similar, then a 508
109    /// (Insufficient Capacity) error is returned.
110    ///
111    /// If an XOR-PEER-ADDRESS attribute contains an address of an address
112    /// family that is not the same as that of a relayed transport address
113    /// for the allocation, the server MUST generate an error response with
114    /// the 443 (Peer Address Family Mismatch) response code.
115    ///
116    /// The server MAY impose restrictions on the IP address allowed in the
117    /// XOR-PEER-ADDRESS attribute; if a value is not allowed, the server
118    /// rejects the request with a 403 (Forbidden) error.
119    ///
120    /// If the message is valid and the server is capable of carrying out the
121    /// request, then the server installs or refreshes a permission for the
122    /// IP address contained in each XOR-PEER-ADDRESS attribute as described
123    /// in [Section 9](https://tools.ietf.org/html/rfc8656#section-9).  
124    /// The port portion of each attribute is ignored and may be any arbitrary
125    /// value.
126    ///
127    /// The server then responds with a CreatePermission success response.
128    /// There are no mandatory attributes in the success response.
129    ///
130    /// NOTE: A server need not do anything special to implement
131    /// idempotency of CreatePermission requests over UDP using the
132    /// "stateless stack approach".  Retransmitted CreatePermission
133    /// requests will simply refresh the permissions.
134    #[allow(unused_variables)]
135    fn on_create_permission(&self, id: &Identifier, username: &str, ports: &[u16]) {}
136
137    /// refresh request
138    ///
139    /// If the server receives a Refresh Request with a REQUESTED-ADDRESS-
140    /// FAMILY attribute and the attribute value does not match the address
141    /// family of the allocation, the server MUST reply with a 443 (Peer
142    /// Address Family Mismatch) Refresh error response.
143    ///
144    /// The server computes a value called the "desired lifetime" as follows:
145    /// if the request contains a LIFETIME attribute and the attribute value
146    /// is zero, then the "desired lifetime" is zero.  Otherwise, if the
147    /// request contains a LIFETIME attribute, then the server computes the
148    /// minimum of the client's requested lifetime and the server's maximum
149    /// allowed lifetime.  If this computed value is greater than the default
150    /// lifetime, then the "desired lifetime" is the computed value.
151    /// Otherwise, the "desired lifetime" is the default lifetime.
152    ///
153    /// Subsequent processing depends on the "desired lifetime" value:
154    ///
155    /// * If the "desired lifetime" is zero, then the request succeeds and
156    ///   the allocation is deleted.
157    ///
158    /// * If the "desired lifetime" is non-zero, then the request succeeds
159    ///   and the allocation's time-to-expiry is set to the "desired
160    ///   lifetime".
161    ///
162    /// If the request succeeds, then the server sends a success response
163    /// containing:
164    ///
165    /// * A LIFETIME attribute containing the current value of the time-to-
166    ///   expiry timer.
167    ///
168    /// NOTE: A server need not do anything special to implement
169    /// idempotency of Refresh requests over UDP using the "stateless
170    /// stack approach".  Retransmitted Refresh requests with a non-
171    /// zero "desired lifetime" will simply refresh the allocation.  A
172    /// retransmitted Refresh request with a zero "desired lifetime"
173    /// will cause a 437 (Allocation Mismatch) response if the
174    /// allocation has already been deleted, but the client will treat
175    /// this as equivalent to a success response (see below).
176    #[allow(unused_variables)]
177    fn on_refresh(&self, id: &Identifier, username: &str, lifetime: u32) {}
178
179    /// session destroy
180    ///
181    /// Triggered when the session leaves from the turn. Possible reasons: the
182    /// session life cycle has expired, external active deletion, or active
183    /// exit of the session.
184    #[allow(unused_variables)]
185    fn on_destroy(&self, id: &Identifier, username: &str) {}
186}
187
188pub struct ServiceOptions<T> {
189    pub port_range: PortRange,
190    pub realm: String,
191    pub interfaces: Vec<InterfaceAddr>,
192    pub handler: T,
193}
194
195/// Turn service.
196#[derive(Clone)]
197pub struct Service<T> {
198    interfaces: Arc<Vec<InterfaceAddr>>,
199    manager: Arc<SessionManager<T>>,
200    software: String,
201    realm: String,
202    handler: T,
203}
204
205impl<T> Service<T>
206where
207    T: ServiceHandler + Clone,
208{
209    /// Create turn service.
210    pub fn new(options: ServiceOptions<T>) -> Self {
211        Self {
212            manager: SessionManager::new(SessionManagerOptions {
213                port_range: options.port_range,
214                handler: options.handler.clone(),
215            }),
216            interfaces: Arc::new(options.interfaces),
217            software: crate::SOFTWARE.to_string(),
218            handler: options.handler,
219            realm: options.realm,
220        }
221    }
222
223    /// create a router.
224    pub fn make_router(&self, id: Identifier) -> Router<T> {
225        Router::new(self, id)
226    }
227
228    pub fn get_session_manager(&self) -> &SessionManager<T> {
229        &self.manager
230    }
231}