turn_server/codec/message/
methods.rs

1use super::Error;
2
3/// STUN Methods Registry
4///
5/// [RFC5389]: https://datatracker.ietf.org/doc/html/rfc5389
6/// [RFC8489]: https://datatracker.ietf.org/doc/html/rfc8489
7/// [RFC8126]: https://datatracker.ietf.org/doc/html/rfc8126
8/// [Section 5]: https://datatracker.ietf.org/doc/html/rfc8489#section-5
9///
10/// A STUN method is a hex number in the range 0x000-0x0FF.  The encoding
11/// of a STUN method into a STUN message is described in [Section 5].
12///
13/// STUN methods in the range 0x000-0x07F are assigned by IETF Review
14/// [RFC8126].  STUN methods in the range 0x080-0x0FF are assigned by
15/// Expert Review [RFC8126].  The responsibility of the expert is to
16/// verify that the selected codepoint(s) is not in use and that the
17/// request is not for an abnormally large number of codepoints.
18/// Technical review of the extension itself is outside the scope of the
19/// designated expert responsibility.
20///
21/// IANA has updated the name for method 0x002 as described below as well
22/// as updated the reference from [RFC5389] to [RFC8489] for the following
23/// STUN methods:
24///
25/// 0x000: Reserved
26/// 0x001: Binding
27/// 0x002: Reserved; was SharedSecret prior to [RFC5389]
28/// 0x003: Allocate
29/// 0x004: Refresh
30/// 0x006: Send
31/// 0x007: Data
32/// 0x008: CreatePermission
33/// 0x009: ChannelBind
34#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
35pub enum MethodType {
36    Request,
37    Response,
38    Error,
39}
40
41#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
42pub enum Method {
43    Binding(MethodType),
44    Allocate(MethodType),
45    CreatePermission(MethodType),
46    ChannelBind(MethodType),
47    Refresh(MethodType),
48    SendIndication,
49    DataIndication,
50}
51
52pub const BINDING_REQUEST: Method = Method::Binding(MethodType::Request);
53pub const BINDING_RESPONSE: Method = Method::Binding(MethodType::Response);
54pub const BINDING_ERROR: Method = Method::Binding(MethodType::Error);
55pub const ALLOCATE_REQUEST: Method = Method::Allocate(MethodType::Request);
56pub const ALLOCATE_RESPONSE: Method = Method::Allocate(MethodType::Response);
57pub const ALLOCATE_ERROR: Method = Method::Allocate(MethodType::Error);
58pub const CREATE_PERMISSION_REQUEST: Method = Method::CreatePermission(MethodType::Request);
59pub const CREATE_PERMISSION_RESPONSE: Method = Method::CreatePermission(MethodType::Response);
60pub const CREATE_PERMISSION_ERROR: Method = Method::CreatePermission(MethodType::Error);
61pub const CHANNEL_BIND_REQUEST: Method = Method::ChannelBind(MethodType::Request);
62pub const CHANNEL_BIND_RESPONSE: Method = Method::ChannelBind(MethodType::Response);
63pub const CHANNEL_BIND_ERROR: Method = Method::ChannelBind(MethodType::Error);
64pub const REFRESH_REQUEST: Method = Method::Refresh(MethodType::Request);
65pub const REFRESH_RESPONSE: Method = Method::Refresh(MethodType::Response);
66pub const REFRESH_ERROR: Method = Method::Refresh(MethodType::Error);
67pub const SEND_INDICATION: Method = Method::SendIndication;
68pub const DATA_INDICATION: Method = Method::DataIndication;
69
70impl Method {
71    pub fn is_error(&self) -> bool {
72        matches!(
73            self,
74            Method::Binding(MethodType::Error)
75                | Method::Refresh(MethodType::Error)
76                | Method::Allocate(MethodType::Error)
77                | Method::CreatePermission(MethodType::Error)
78                | Method::ChannelBind(MethodType::Error)
79        )
80    }
81
82    pub fn error(&self) -> Option<Method> {
83        match self {
84            Method::Binding(_) => Some(BINDING_ERROR),
85            Method::Allocate(_) => Some(ALLOCATE_ERROR),
86            Method::CreatePermission(_) => Some(CREATE_PERMISSION_ERROR),
87            Method::ChannelBind(_) => Some(CHANNEL_BIND_ERROR),
88            Method::Refresh(_) => Some(REFRESH_ERROR),
89            _ => None,
90        }
91    }
92}
93
94impl TryFrom<u16> for Method {
95    type Error = Error;
96
97    /// # Test
98    ///
99    /// ```
100    /// use turn_server::codec::message::methods::*;
101    /// use std::convert::TryFrom;
102    ///
103    /// assert_eq!(Method::try_from(0x0001).unwrap(), BINDING_REQUEST);
104    /// assert_eq!(Method::try_from(0x0101).unwrap(), BINDING_RESPONSE);
105    /// assert_eq!(Method::try_from(0x0111).unwrap(), BINDING_ERROR);
106    /// assert_eq!(Method::try_from(0x0003).unwrap(), ALLOCATE_REQUEST);
107    /// assert_eq!(Method::try_from(0x0103).unwrap(), ALLOCATE_RESPONSE);
108    /// assert_eq!(Method::try_from(0x0113).unwrap(), ALLOCATE_ERROR);
109    /// assert_eq!(Method::try_from(0x0008).unwrap(), CREATE_PERMISSION_REQUEST);
110    /// assert_eq!(Method::try_from(0x0108).unwrap(), CREATE_PERMISSION_RESPONSE);
111    /// assert_eq!(Method::try_from(0x0118).unwrap(), CREATE_PERMISSION_ERROR);
112    /// assert_eq!(Method::try_from(0x0009).unwrap(), CHANNEL_BIND_REQUEST);
113    /// assert_eq!(Method::try_from(0x0109).unwrap(), CHANNEL_BIND_RESPONSE);
114    /// assert_eq!(Method::try_from(0x0119).unwrap(), CHANNEL_BIND_ERROR);
115    /// assert_eq!(Method::try_from(0x0004).unwrap(), REFRESH_REQUEST);
116    /// assert_eq!(Method::try_from(0x0104).unwrap(), REFRESH_RESPONSE);
117    /// assert_eq!(Method::try_from(0x0114).unwrap(), REFRESH_ERROR);
118    /// assert_eq!(Method::try_from(0x0016).unwrap(), SEND_INDICATION);
119    /// assert_eq!(Method::try_from(0x0017).unwrap(), DATA_INDICATION);
120    /// ```
121    fn try_from(value: u16) -> Result<Self, Self::Error> {
122        Ok(match value {
123            0x0001 => Self::Binding(MethodType::Request),
124            0x0101 => Self::Binding(MethodType::Response),
125            0x0111 => Self::Binding(MethodType::Error),
126            0x0003 => Self::Allocate(MethodType::Request),
127            0x0103 => Self::Allocate(MethodType::Response),
128            0x0113 => Self::Allocate(MethodType::Error),
129            0x0008 => Self::CreatePermission(MethodType::Request),
130            0x0108 => Self::CreatePermission(MethodType::Response),
131            0x0118 => Self::CreatePermission(MethodType::Error),
132            0x0009 => Self::ChannelBind(MethodType::Request),
133            0x0109 => Self::ChannelBind(MethodType::Response),
134            0x0119 => Self::ChannelBind(MethodType::Error),
135            0x0004 => Self::Refresh(MethodType::Request),
136            0x0104 => Self::Refresh(MethodType::Response),
137            0x0114 => Self::Refresh(MethodType::Error),
138            0x0016 => Self::SendIndication,
139            0x0017 => Self::DataIndication,
140            _ => return Err(Error::UnknownMethod),
141        })
142    }
143}
144
145impl From<Method> for u16 {
146    /// # Test
147    ///
148    /// ```
149    /// use turn_server::codec::message::methods::*;
150    /// use std::convert::From;
151    ///
152    /// assert_eq!(0x0001u16, u16::from(BINDING_REQUEST));
153    /// assert_eq!(0x0101u16, u16::from(BINDING_RESPONSE));
154    /// assert_eq!(0x0111u16, u16::from(BINDING_ERROR));
155    /// assert_eq!(0x0003u16, u16::from(ALLOCATE_REQUEST));
156    /// assert_eq!(0x0103u16, u16::from(ALLOCATE_RESPONSE));
157    /// assert_eq!(0x0113u16, u16::from(ALLOCATE_ERROR));
158    /// assert_eq!(0x0008u16, u16::from(CREATE_PERMISSION_REQUEST));
159    /// assert_eq!(0x0108u16, u16::from(CREATE_PERMISSION_RESPONSE));
160    /// assert_eq!(0x0118u16, u16::from(CREATE_PERMISSION_ERROR));
161    /// assert_eq!(0x0009u16, u16::from(CHANNEL_BIND_REQUEST));
162    /// assert_eq!(0x0109u16, u16::from(CHANNEL_BIND_RESPONSE));
163    /// assert_eq!(0x0119u16, u16::from(CHANNEL_BIND_ERROR));
164    /// assert_eq!(0x0004u16, u16::from(REFRESH_REQUEST));
165    /// assert_eq!(0x0104u16, u16::from(REFRESH_RESPONSE));
166    /// assert_eq!(0x0114u16, u16::from(REFRESH_ERROR));
167    /// assert_eq!(0x0016u16, u16::from(SEND_INDICATION));
168    /// assert_eq!(0x0017u16, u16::from(DATA_INDICATION));
169    /// ```
170    fn from(val: Method) -> Self {
171        match val {
172            Method::Binding(MethodType::Request) => 0x0001,
173            Method::Binding(MethodType::Response) => 0x0101,
174            Method::Binding(MethodType::Error) => 0x0111,
175            Method::Allocate(MethodType::Request) => 0x0003,
176            Method::Allocate(MethodType::Response) => 0x0103,
177            Method::Allocate(MethodType::Error) => 0x0113,
178            Method::CreatePermission(MethodType::Request) => 0x0008,
179            Method::CreatePermission(MethodType::Response) => 0x0108,
180            Method::CreatePermission(MethodType::Error) => 0x0118,
181            Method::ChannelBind(MethodType::Request) => 0x0009,
182            Method::ChannelBind(MethodType::Response) => 0x0109,
183            Method::ChannelBind(MethodType::Error) => 0x0119,
184            Method::Refresh(MethodType::Request) => 0x0004,
185            Method::Refresh(MethodType::Response) => 0x0104,
186            Method::Refresh(MethodType::Error) => 0x0114,
187            Method::SendIndication => 0x0016,
188            Method::DataIndication => 0x0017,
189        }
190    }
191}