turn_server/turn/operations/
refresh.rs

1use super::{Observer, Requet, Response, ResponseMethod};
2
3use crate::stun::{
4    MessageEncoder, MessageRef,
5    attribute::{Error, ErrorCode, ErrorKind, Lifetime},
6    method::{REFRESH_ERROR, REFRESH_RESPONSE},
7};
8
9/// return refresh error response
10#[inline(always)]
11fn reject<'a, T: Observer>(req: Requet<'_, 'a, T, MessageRef<'_>>, err: ErrorKind) -> Option<Response<'a>> {
12    {
13        let mut message = MessageEncoder::extend(REFRESH_ERROR, &req.message, req.bytes);
14        message.append::<ErrorCode>(Error::from(err));
15        message.flush(None).ok()?;
16    }
17
18    Some(Response {
19        method: ResponseMethod::Stun(REFRESH_ERROR),
20        bytes: req.bytes,
21        endpoint: None,
22        relay: None,
23    })
24}
25
26/// return refresh ok response
27#[inline(always)]
28pub fn resolve<'a, T: Observer>(
29    req: Requet<'_, 'a, T, MessageRef<'_>>,
30    lifetime: u32,
31    integrity: &[u8; 16],
32) -> Option<Response<'a>> {
33    {
34        let mut message = MessageEncoder::extend(REFRESH_RESPONSE, &req.message, req.bytes);
35        message.append::<Lifetime>(lifetime);
36        message.flush(Some(integrity)).ok()?;
37    }
38
39    Some(Response {
40        method: ResponseMethod::Stun(REFRESH_RESPONSE),
41        bytes: req.bytes,
42        endpoint: None,
43        relay: None,
44    })
45}
46
47/// process refresh request
48///
49/// If the server receives a Refresh Request with a REQUESTED-ADDRESS-
50/// FAMILY attribute and the attribute value does not match the address
51/// family of the allocation, the server MUST reply with a 443 (Peer
52/// Address Family Mismatch) Refresh error response.
53///
54/// The server computes a value called the "desired lifetime" as follows:
55/// if the request contains a LIFETIME attribute and the attribute value
56/// is zero, then the "desired lifetime" is zero.  Otherwise, if the
57/// request contains a LIFETIME attribute, then the server computes the
58/// minimum of the client's requested lifetime and the server's maximum
59/// allowed lifetime.  If this computed value is greater than the default
60/// lifetime, then the "desired lifetime" is the computed value.
61/// Otherwise, the "desired lifetime" is the default lifetime.
62///
63/// Subsequent processing depends on the "desired lifetime" value:
64///
65/// * If the "desired lifetime" is zero, then the request succeeds and the
66///   allocation is deleted.
67///
68/// * If the "desired lifetime" is non-zero, then the request succeeds and the
69///   allocation's time-to-expiry is set to the "desired lifetime".
70///
71/// If the request succeeds, then the server sends a success response
72/// containing:
73///
74/// * A LIFETIME attribute containing the current value of the time-to-expiry
75///   timer.
76///
77/// NOTE: A server need not do anything special to implement
78/// idempotency of Refresh requests over UDP using the "stateless
79/// stack approach".  Retransmitted Refresh requests with a non-
80/// zero "desired lifetime" will simply refresh the allocation.  A
81/// retransmitted Refresh request with a zero "desired lifetime"
82/// will cause a 437 (Allocation Mismatch) response if the
83/// allocation has already been deleted, but the client will treat
84/// this as equivalent to a success response (see below).
85pub fn process<'a, T: Observer>(req: Requet<'_, 'a, T, MessageRef<'_>>) -> Option<Response<'a>> {
86    let (username, integrity) = match req.auth() {
87        None => return reject(req, ErrorKind::Unauthorized),
88        Some(it) => it,
89    };
90
91    let lifetime = req.message.get::<Lifetime>().unwrap_or(600);
92    if !req.service.sessions.refresh(&req.address, lifetime) {
93        return reject(req, ErrorKind::AllocationMismatch);
94    }
95
96    req.service.observer.refresh(&req.address, username, lifetime);
97    resolve(req, lifetime, &integrity)
98}