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}