stun_rs/attributes/stun/
error_code.rs

1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
3use crate::Decode;
4use crate::Encode;
5use crate::ErrorCode as ErrorCodeType;
6use crate::StunError;
7
8const ERROR_CODE: u16 = 0x0009;
9
10// Format of Error-Code Attribute:
11//  0                   1                   2                   3
12//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
13// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14// |           Reserved, should be 0         |  C  |     Number    |
15// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16// |      Reason Phrase (variable)                                ..
17// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
19/// The ERROR-CODE attribute is used in error response messages.
20/// # Examples
21///```rust
22/// # use stun_rs::attributes::stun::ErrorCode;
23/// # use std::error::Error;
24/// #
25/// # fn main() -> Result<(), Box<dyn Error>> {
26/// let error = stun_rs::ErrorCode::new(420, "Unknown Attribute")?;
27/// let attr = ErrorCode::from(error);
28/// assert_eq!(attr.error_code().class(), 4);
29/// assert_eq!(attr.error_code().number(), 20);
30/// assert_eq!(attr.error_code().reason(), "Unknown Attribute");
31/// #  Ok(())
32/// # }
33///```
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct ErrorCode(ErrorCodeType);
36
37impl ErrorCode {
38    /// Creates a new [`ErrorCode`] attribute.
39    /// # Arguments:
40    /// * `error_code` - The error code.
41    pub fn new(error_code: ErrorCodeType) -> Self {
42        Self(error_code)
43    }
44
45    /// Returns the error code value .
46    pub fn error_code(&self) -> &ErrorCodeType {
47        &self.0
48    }
49}
50
51impl From<ErrorCodeType> for ErrorCode {
52    fn from(error: ErrorCodeType) -> Self {
53        ErrorCode::new(error)
54    }
55}
56
57impl DecodeAttributeValue for ErrorCode {
58    fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
59        let (error, size) = ErrorCodeType::decode(ctx.raw_value())?;
60        Ok((ErrorCode::new(error), size))
61    }
62}
63
64impl EncodeAttributeValue for ErrorCode {
65    fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
66        self.0.encode(ctx.raw_value_mut())
67    }
68}
69
70impl crate::attributes::AsVerifiable for ErrorCode {}
71
72stunt_attribute!(ErrorCode, ERROR_CODE);
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::attributes::{DecodeAttributeValue, EncodeAttributeValue};
78    use crate::error::StunErrorType;
79    use crate::StunAttribute;
80
81    #[test]
82    fn error_code() {
83        let error = ErrorCodeType::new(318, "test reason").expect("Can not create error code type");
84        let attr = ErrorCode::from(error);
85        assert_eq!(attr.error_code().class(), 3);
86        assert_eq!(attr.error_code().number(), 18);
87        assert_eq!(attr.error_code().reason(), "test reason");
88        assert_eq!(attr.error_code().error_code(), 318);
89    }
90
91    #[test]
92    fn decode_error_code() {
93        let dummy_msg: [u8; 0] = [0x0; 0];
94        let buffer = [
95            0x00, 0x00, 0x03, 0x12, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f,
96            0x6e,
97        ];
98        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
99        let (error_code, size) = ErrorCode::decode(ctx).expect("Can not decode ERROR-CODE");
100        assert_eq!(size, 15);
101        let error = error_code.error_code();
102        assert_eq!(error.error_code(), 318);
103        assert_eq!(error.class(), 3);
104        assert_eq!(error.number(), 18);
105        assert_eq!(error.reason(), "test reason");
106
107        let buffer = [0x00, 0x00, 0x03, 0x12];
108        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
109        let (error_code, size) = ErrorCode::decode(ctx).expect("Can not decode ERROR-CODE");
110        assert_eq!(size, 4);
111        let error = error_code.error_code();
112        assert_eq!(error.error_code(), 318);
113        assert_eq!(error.class(), 3);
114        assert_eq!(error.number(), 18);
115        assert!(error.reason().is_empty());
116    }
117
118    #[test]
119    fn decode_error_code_fail() {
120        let dummy_msg: [u8; 0] = [0x0; 0];
121        // short buffer
122        let buffer = [0x00, 0x00, 0x03];
123        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
124        let result = ErrorCode::decode(ctx);
125        assert_eq!(
126            result.expect_err("Error expected"),
127            StunErrorType::SmallBuffer
128        );
129
130        // Wrong class: 2
131        let buffer = [
132            0x00, 0x00, 0x02, 0x12, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f,
133            0x6e,
134        ];
135        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
136        let result = ErrorCode::decode(ctx);
137        assert_eq!(
138            result.expect_err("Error expected"),
139            StunErrorType::InvalidParam
140        );
141
142        // Wrong number: 112
143        let buffer = [
144            0x00, 0x00, 0x03, 0x70, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f,
145            0x6e,
146        ];
147        let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
148        let result = ErrorCode::decode(ctx);
149        assert_eq!(
150            result.expect_err("Error expected"),
151            StunErrorType::InvalidParam
152        );
153    }
154
155    #[test]
156    fn encode_error_code() {
157        let dummy_msg: [u8; 0] = [0x0; 0];
158        let result = ErrorCodeType::new(318, "test reason");
159        assert!(result.is_ok());
160        let error_code = ErrorCode::new(result.unwrap());
161
162        let mut buffer: [u8; 15] = [0x0; 15];
163        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
164        let result = error_code.encode(ctx);
165        assert_eq!(result, Ok(15));
166
167        let cmp_buffer = [
168            0x00, 0x00, 0x03, 0x12, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f,
169            0x6e,
170        ];
171        assert_eq!(&buffer[..], &cmp_buffer[..]);
172    }
173
174    #[test]
175    fn error_code_stunt_attribute() {
176        let error = ErrorCodeType::new(318, "test reason").expect("Can not create error code type");
177        let attr = StunAttribute::ErrorCode(ErrorCode::new(error));
178        assert!(attr.is_error_code());
179        assert!(attr.as_error_code().is_ok());
180        assert!(attr.as_unknown().is_err());
181
182        assert!(attr.attribute_type().is_comprehension_required());
183        assert!(!attr.attribute_type().is_comprehension_optional());
184
185        let dbg_fmt = format!("{:?}", attr);
186        assert_eq!(
187            "ErrorCode(ErrorCode(ErrorCode { error_code: 318, reason: \"test reason\" }))",
188            dbg_fmt
189        );
190    }
191}