stun_rs/
error.rs

1//! STUN Errors.
2//! This module contains all errors that can happen when dealing with stun.
3
4use std::error;
5use std::fmt;
6
7use crate::AttributeType;
8
9/// Defines the type of error
10#[derive(Debug, PartialEq, Eq)]
11pub enum StunErrorType {
12    /// Invalid parameter
13    InvalidParam,
14    /// Failure to perform validations
15    ValidationFailed,
16    /// Encoded or decoded value is bugger than the maximum allowed value
17    ValueTooLong,
18    /// Small buffer
19    SmallBuffer,
20}
21
22impl fmt::Display for StunErrorType {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        match *self {
25            StunErrorType::InvalidParam => write!(f, "invalid parameter"),
26            StunErrorType::ValidationFailed => write!(f, "validation failed"),
27            StunErrorType::ValueTooLong => write!(f, "value is too long"),
28            StunErrorType::SmallBuffer => write!(f, "small input buffer"),
29        }
30    }
31}
32
33/// Provides information about the error
34#[derive(Debug)]
35pub enum StunErrorInfo {
36    /// A [`String`] describing the error,
37    Text(String),
38    /// Source of error
39    Error(Box<dyn error::Error + Sync + Send>),
40}
41
42impl fmt::Display for StunErrorInfo {
43    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44        match &self {
45            StunErrorInfo::Text(msg) => write!(f, "{}", msg),
46            StunErrorInfo::Error(e) => write!(f, "{}", e),
47        }
48    }
49}
50
51/// Stun error
52#[derive(Debug)]
53pub struct StunError {
54    /// Error type
55    pub error_type: StunErrorType,
56    /// Information about the error
57    pub info: StunErrorInfo,
58}
59
60impl fmt::Display for StunError {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "{}. {}", self.error_type, self.info)
63    }
64}
65
66impl error::Error for StunError {
67    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
68        match &self.info {
69            StunErrorInfo::Text(_) => None,
70            StunErrorInfo::Error(e) => Some(e.as_ref()),
71        }
72    }
73}
74
75impl PartialEq<StunError> for StunErrorType {
76    fn eq(&self, other: &StunError) -> bool {
77        *self == other.error_type
78    }
79}
80
81impl PartialEq<StunErrorType> for StunError {
82    fn eq(&self, other: &StunErrorType) -> bool {
83        self.error_type == *other
84    }
85}
86
87impl PartialEq for StunError {
88    fn eq(&self, other: &Self) -> bool {
89        // Two erros are equal if they have the same type
90        self.error_type == other.error_type
91    }
92}
93
94impl Eq for StunError {}
95
96impl From<std::array::TryFromSliceError> for StunError {
97    fn from(e: std::array::TryFromSliceError) -> Self {
98        StunError::from_error(StunErrorType::InvalidParam, Box::new(e))
99    }
100}
101
102impl From<std::str::Utf8Error> for StunError {
103    fn from(e: std::str::Utf8Error) -> Self {
104        StunError::from_error(StunErrorType::InvalidParam, Box::new(e))
105    }
106}
107
108impl From<std::num::TryFromIntError> for StunError {
109    fn from(e: std::num::TryFromIntError) -> Self {
110        StunError::from_error(StunErrorType::InvalidParam, Box::new(e))
111    }
112}
113
114impl From<precis_core::Error> for StunError {
115    fn from(e: precis_core::Error) -> Self {
116        StunError::from_error(StunErrorType::InvalidParam, Box::new(e))
117    }
118}
119
120impl StunError {
121    pub(crate) fn new<S>(error_type: StunErrorType, msg: S) -> Self
122    where
123        S: Into<String>,
124    {
125        Self {
126            error_type,
127            info: StunErrorInfo::Text(msg.into()),
128        }
129    }
130
131    pub(crate) fn from_error(
132        error_type: StunErrorType,
133        e: Box<dyn error::Error + Sync + Send>,
134    ) -> Self {
135        Self {
136            error_type,
137            info: StunErrorInfo::Error(e),
138        }
139    }
140}
141/// Describes the error happened when parsing an [`StunAttribute`](crate::attributes::StunAttribute)
142#[derive(Debug)]
143pub struct StunAttributeError {
144    /// The attribute type, if it is known
145    pub attr_type: Option<AttributeType>,
146    /// The position of the attribute in the [`StunMessage`](crate::message::StunMessage)
147    pub position: usize,
148    /// The error
149    pub error: StunError,
150}
151
152impl fmt::Display for StunAttributeError {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        match &self.attr_type {
155            Some(attr_type) => write!(f, "{}", attr_type)?,
156            None => write!(f, "unknown attribute type")?,
157        }
158        write!(f, ", position: {}, error: {}", self.position, self.error)
159    }
160}
161
162/// Describes an error happening at message level
163#[derive(Debug)]
164pub struct StunMessageError(pub StunError);
165
166impl fmt::Display for StunMessageError {
167    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168        write!(f, "{}", self.0)
169    }
170}
171
172/// Indicates if the error happened when parsing the message, for example if the input buffer is
173/// shorter than the length indicated in the STUN header, or if the error happened parsing an
174/// attribute.
175#[derive(Debug)]
176pub enum StunErrorLevel {
177    /// Invalid parameter
178    Message(StunMessageError),
179    /// Small buffer
180    Attribute(StunAttributeError),
181}
182
183impl fmt::Display for StunErrorLevel {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        match self {
186            StunErrorLevel::Message(e) => write!(f, "message level: {}", e),
187            StunErrorLevel::Attribute(e) => write!(f, "attribute level: {}", e),
188        }
189    }
190}
191
192/// Describes an error decoding a [`StunMessage`](crate::message::StunMessage)
193#[derive(Debug)]
194pub struct StunDecodeError(pub StunErrorLevel);
195
196impl fmt::Display for StunDecodeError {
197    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
198        write!(f, "decode error: {}", self.0)
199    }
200}
201
202impl error::Error for StunDecodeError {}
203
204/// Describes an error encoding a message [`StunMessage`](crate::message::StunMessage)
205#[derive(Debug)]
206pub struct StunEncodeError(pub StunErrorLevel);
207
208impl fmt::Display for StunEncodeError {
209    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210        write!(f, "encode error: {}", self.0)
211    }
212}
213
214impl error::Error for StunEncodeError {}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219    use std::convert::{TryFrom, TryInto};
220    use std::error::Error;
221
222    #[test]
223    fn display_stun_error_type() {
224        assert_eq!(
225            "invalid parameter",
226            format!("{}", StunErrorType::InvalidParam)
227        );
228        assert_eq!(
229            "validation failed",
230            format!("{}", StunErrorType::ValidationFailed)
231        );
232        assert_eq!(
233            "value is too long",
234            format!("{}", StunErrorType::ValueTooLong)
235        );
236        assert_eq!(
237            "small input buffer",
238            format!("{}", StunErrorType::SmallBuffer)
239        );
240    }
241
242    #[test]
243    fn stun_error() {
244        let error = StunError::new(StunErrorType::InvalidParam, "Test message");
245        assert_eq!(error, StunErrorType::InvalidParam);
246        assert_eq!(StunErrorType::InvalidParam, error);
247        assert!(error.source().is_none());
248        assert_eq!(
249            "StunError { error_type: InvalidParam, info: Text(\"Test message\") }",
250            format!("{:?}", error)
251        );
252        assert_eq!("invalid parameter. Test message", format!("{}", error));
253
254        {
255            let error2 = StunError::new(StunErrorType::InvalidParam, "Test message 2");
256            assert_eq!(error, error2);
257        }
258
259        let precis_error = crate::strings::opaque_string_enforce("\u{0009}")
260            .expect_err("character TAB `U+0009` is disallowed");
261        let error = StunError::from(precis_error);
262        assert!(error.source().is_some());
263        println!("{}", error);
264        println!("{:?}", error);
265
266        let input: u16 = 256;
267        let result: Result<u8, std::num::TryFromIntError> = input.try_into();
268        let int_error = result.expect_err("Conversion from u16 to u8 did not fail");
269        let error = StunError::from(int_error);
270        assert!(error.source().is_some());
271        println!("{}", error);
272        println!("{:?}", error);
273
274        let buff = [0, 1, 2];
275        let result: Result<&[u8; 2], std::array::TryFromSliceError> =
276            <&[u8; 2]>::try_from(&buff[2..]);
277        let slice_error = result.expect_err("Expected slice error");
278        let error = StunError::from(slice_error);
279        assert!(error.source().is_some());
280        println!("{}", error);
281        println!("{:?}", error);
282
283        // some invalid bytes, in a vector
284        let buffer = vec![0, 159, 146, 150];
285        // std::str::from_utf8 returns a Utf8Error
286        let utf8_error = std::str::from_utf8(&buffer).expect_err("Expected utf8 error");
287        let error = StunError::from(utf8_error);
288        assert!(error.source().is_some());
289        println!("{}", error);
290        println!("{:?}", error);
291    }
292
293    #[test]
294    fn stun_attribute_error() {
295        let error = StunAttributeError {
296            attr_type: None,
297            position: 0,
298            error: StunError::new(StunErrorType::InvalidParam, "Test message"),
299        };
300        println!("{}", error);
301        println!("{:?}", error);
302
303        let error = StunAttributeError {
304            attr_type: Some(AttributeType::new(0x1234)),
305            position: 0,
306            error: StunError::new(StunErrorType::InvalidParam, "Test message"),
307        };
308        println!("{}", error);
309        println!("{:?}", error);
310    }
311
312    #[test]
313    fn stun_error_level() {
314        let error = StunErrorLevel::Message(StunMessageError(StunError::new(
315            StunErrorType::InvalidParam,
316            "Test message",
317        )));
318        println!("{}", error);
319        println!("{:?}", error);
320
321        let error = StunErrorLevel::Attribute(StunAttributeError {
322            attr_type: Some(AttributeType::new(0x1234)),
323            position: 0,
324            error: StunError::new(StunErrorType::InvalidParam, "Test message"),
325        });
326        println!("{}", error);
327        println!("{:?}", error);
328    }
329
330    #[test]
331    fn stun_encode_decode_error() {
332        let error = StunEncodeError(StunErrorLevel::Message(StunMessageError(StunError::new(
333            StunErrorType::InvalidParam,
334            "Test message",
335        ))));
336        println!("{}", error);
337        println!("{:?}", error);
338
339        let error = StunDecodeError(StunErrorLevel::Message(StunMessageError(StunError::new(
340            StunErrorType::InvalidParam,
341            "Test message",
342        ))));
343        println!("{}", error);
344        println!("{:?}", error);
345    }
346}