1use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
6use crate::error::StunError;
7use crate::DecoderContext;
8use std::fmt;
9
10mod address_port;
11mod integrity_attr;
12
13mod unknown;
14pub use unknown::Unknown;
15
16pub mod stun;
17
18#[cfg(feature = "ice")]
19pub mod ice;
20
21#[cfg(feature = "turn")]
22pub mod turn;
23
24#[cfg(feature = "mobility")]
25pub mod mobility;
26
27#[cfg(feature = "discovery")]
28pub mod discovery;
29
30pub(crate) trait Verifiable {
33 fn verify(&self, input: &[u8], cxt: &DecoderContext) -> bool;
40}
41
42pub(crate) trait AsVerifiable {
43 fn as_verifiable_ref(&self) -> Option<&dyn Verifiable> {
44 None
45 }
46}
47
48pub(crate) trait EncodeAttributeValue {
49 fn encode(&self, ctx: AttributeEncoderContext) -> Result<usize, StunError>;
50 fn post_encode(&self, _ctx: AttributeEncoderContext) -> Result<(), StunError> {
51 Ok(())
52 }
53}
54
55pub(crate) trait DecodeAttributeValue {
56 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError>
57 where
58 Self: Sized;
59}
60
61#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
76pub struct AttributeType(u16);
77impl AttributeType {
78 pub fn new(attr_type: u16) -> Self {
80 AttributeType(attr_type)
81 }
82
83 pub fn as_u16(&self) -> u16 {
85 self.0
86 }
87
88 pub fn is_comprehension_required(&self) -> bool {
90 self.0 < 0x8000
92 }
93
94 pub fn is_comprehension_optional(self) -> bool {
96 !self.is_comprehension_required()
98 }
99}
100
101impl From<u16> for AttributeType {
102 fn from(val: u16) -> Self {
103 Self::new(val)
104 }
105}
106
107impl From<AttributeType> for u16 {
108 fn from(val: AttributeType) -> Self {
109 val.0
110 }
111}
112
113impl fmt::Debug for AttributeType {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "AttributeType (0x{:04X})", self.0)?;
116 Ok(())
117 }
118}
119
120impl fmt::Display for AttributeType {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 write!(f, "attribute type (0x{:04X})", self.0)?;
123 Ok(())
124 }
125}
126
127pub trait StunAttributeType {
129 fn attribute_type(&self) -> AttributeType;
131
132 fn get_type() -> AttributeType
134 where
135 Self: Sized;
136}
137
138macro_rules! stunt_attribute (
139 ($attr_class:ident, $attr_type:ident) => {
140 impl crate::attributes::StunAttributeType for $attr_class {
141 fn get_type() -> crate::attributes::AttributeType where Self: Sized {
142 crate::attributes::AttributeType::from($attr_type)
143 }
144 fn attribute_type(&self) -> crate::attributes::AttributeType {
145 $attr_class::get_type()
146 }
147 }
148 impl From<$attr_class> for crate::attributes::StunAttribute {
149 fn from(value: $attr_class) -> Self {
150 crate::attributes::StunAttribute::$attr_class(value)
151 }
152 }
153 }
154);
155pub(crate) use stunt_attribute;
156
157macro_rules! stunt_attribute_impl (
158 ($(($class:ident, $mod:ident $(, $flag:literal)?)),*) => {
159 paste::paste! {
160 #[derive(Debug, Clone)]
162 pub enum StunAttribute {
163 $(
164 $(#[cfg(feature = $flag)])?
165 #[doc = "The `" $class "`atribute"]
166 $class($mod::$class),
167 )*
168 }
169 }
170
171 impl AsVerifiable for StunAttribute {
172 fn as_verifiable_ref(&self) -> Option<&dyn Verifiable> {
173 match self {
174 $(
175 $(#[cfg(feature = $flag)])?
176 StunAttribute::$class(attr) => attr.as_verifiable_ref(),
177 )*
178 }
179 }
180 }
181
182 impl EncodeAttributeValue for StunAttribute {
183 fn encode(&self, ctx: AttributeEncoderContext) -> Result<usize, StunError> {
184 match self {
185 $(
186 $(#[cfg(feature = $flag)])?
187 StunAttribute::$class(attr) => attr.encode(ctx),
188 )*
189 }
190 }
191
192 fn post_encode(&self, ctx: AttributeEncoderContext) -> Result<(), StunError> {
193 match self {
194 $(
195 $(#[cfg(feature = $flag)])?
196 StunAttribute::$class(attr) => attr.post_encode(ctx),
197 )*
198 }
199 }
200 }
201
202 impl StunAttribute {
203 pub fn attribute_type(&self) -> AttributeType {
205 match self {
206 $(
207 $(#[cfg(feature = $flag)])?
208 StunAttribute::$class(attr) => attr.attribute_type(),
209 )*
210 }
211 }
212
213 $(
214 paste::paste! {
215 $(#[cfg(feature = $flag)])?
216 #[doc = "Returns true if this `StunAttribute` is `" $class "`"]
217 pub fn [<is_ $class:snake>] (&self) -> bool {
218 matches!(self, StunAttribute::$class(_))
219 }
220
221 $(#[cfg(feature = $flag)])?
222 #[doc = "Returns a reference to the internal attribute value or an error if the type of the attribute is not `" $class "`"]
223 pub fn [<as_ $class:snake>] (&self) -> Result<&$mod::$class, crate::StunError> {
224 match self {
225 StunAttribute::$class(attr) => Ok(attr),
226 _ => Err(crate::error::StunError::new(
227 crate::error::StunErrorType::InvalidParam,
228 format!("Attribute is not of type {}", std::stringify!($class))
229 )),
230 }
231 }
232
233 $(#[cfg(feature = $flag)])?
234 #[doc = "Returns a reference to the `" $class "` attribute."]
235 #[doc = "# Panics"]
236 #[doc = "Panics if the attribute is not an `" $class "`"]
237 pub fn [<expect_ $class:snake>](&self) -> &$mod::$class {
238 self.[<as_ $class:snake>]().unwrap()
239 }
240 }
241 )*
242 }
243 }
244);
245pub(crate) use stunt_attribute_impl;
246
247stunt_attribute_impl!(
248 (Unknown, unknown),
249 (AlternateServer, stun),
251 (ErrorCode, stun),
252 (Fingerprint, stun),
253 (MappedAddress, stun),
254 (MessageIntegrity, stun),
255 (MessageIntegritySha256, stun),
256 (Nonce, stun),
257 (PasswordAlgorithm, stun),
258 (PasswordAlgorithms, stun),
259 (Realm, stun),
260 (Software, stun),
261 (UnknownAttributes, stun),
262 (UserHash, stun),
263 (UserName, stun),
264 (XorMappedAddress, stun),
265 (IceControlled, ice, "ice"),
267 (IceControlling, ice, "ice"),
268 (Priority, ice, "ice"),
269 (UseCandidate, ice, "ice"),
270 (ChannelNumber, turn, "turn"),
272 (LifeTime, turn, "turn"),
273 (XorPeerAddress, turn, "turn"),
274 (XorRelayedAddress, turn, "turn"),
275 (Data, turn, "turn"),
276 (RequestedAddressFamily, turn, "turn"),
277 (EvenPort, turn, "turn"),
278 (DontFragment, turn, "turn"),
279 (RequestedTrasport, turn, "turn"),
280 (AdditionalAddressFamily, turn, "turn"),
281 (ReservationToken, turn, "turn"),
282 (AddressErrorCode, turn, "turn"),
283 (Icmp, turn, "turn"),
284 (MobilityTicket, mobility, "mobility"),
286 (ChangeRequest, discovery, "discovery"),
288 (OtherAddress, discovery, "discovery"),
289 (Padding, discovery, "discovery"),
290 (ResponseOrigin, discovery, "discovery"),
291 (ResponsePort, discovery, "discovery")
292);
293
294#[cfg(test)]
295mod tests {
296 use super::AttributeType;
297 use crate::common::check_buffer_boundaries;
298 use crate::error::StunErrorType;
299
300 #[test]
301 fn buffer_boundaries() {
302 let buffer = [];
303 assert!(check_buffer_boundaries(&buffer, 0).is_ok());
304 assert!(check_buffer_boundaries(&buffer, 1).is_err());
305 assert_eq!(
306 check_buffer_boundaries(&buffer, 1).expect_err("Error expected"),
307 StunErrorType::SmallBuffer
308 );
309
310 let buffer: [u8; 1] = [0; 1];
311 assert!(check_buffer_boundaries(&buffer, 0).is_ok());
312 assert!(check_buffer_boundaries(&buffer, 1).is_ok());
313 assert!(check_buffer_boundaries(&buffer, 2).is_err());
314 assert_eq!(
315 check_buffer_boundaries(&buffer, 2).expect_err("Error expected"),
316 StunErrorType::SmallBuffer
317 );
318 }
319
320 #[test]
321 fn fmt_attribute_type() {
322 let attr_str = format!("{:?}", AttributeType::from(0x1234));
323 assert_eq!("AttributeType (0x1234)", attr_str);
324
325 let attr_str = format!("{}", AttributeType::from(0x1234));
326 assert_eq!("attribute type (0x1234)", attr_str);
327 }
328}