1use std::error;
5use std::fmt;
6
7use crate::AttributeType;
8
9#[derive(Debug, PartialEq, Eq)]
11pub enum StunErrorType {
12 InvalidParam,
14 ValidationFailed,
16 ValueTooLong,
18 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#[derive(Debug)]
35pub enum StunErrorInfo {
36 Text(String),
38 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#[derive(Debug)]
53pub struct StunError {
54 pub error_type: StunErrorType,
56 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 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#[derive(Debug)]
143pub struct StunAttributeError {
144 pub attr_type: Option<AttributeType>,
146 pub position: usize,
148 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#[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#[derive(Debug)]
176pub enum StunErrorLevel {
177 Message(StunMessageError),
179 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#[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#[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 let buffer = vec![0, 159, 146, 150];
285 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}