• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(feature = "std")]
2 use crate::err::{ipv4_exts, ipv6_exts, ValueTooBigError};
3 
4 /// Error while writing packet
5 #[cfg(feature = "std")]
6 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
7 #[derive(Debug)]
8 pub enum BuildWriteError {
9     /// IO error while writing packet.
10     Io(std::io::Error),
11 
12     /// Error if the length of the payload is too
13     /// big to be representable by the length fields.
14     PayloadLen(ValueTooBigError<usize>),
15 
16     /// Error if the IPv4 extensions can not be serialized
17     /// because of internal consistency errors (i.e. a header
18     /// is never).
19     Ipv4Exts(ipv4_exts::ExtsWalkError),
20 
21     /// Error if the IPv6 extensions can not be serialized
22     /// because of internal consistency errors.
23     Ipv6Exts(ipv6_exts::ExtsWalkError),
24 
25     /// Error if ICMPv6 is packaged in an IPv4 packet (it is undefined
26     /// how to calculate the checksum).
27     Icmpv6InIpv4,
28 
29     /// address size defined in the ARP header does not match the actual size
30     ArpHeaderNotMatch,
31 }
32 
33 #[cfg(feature = "std")]
34 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
35 impl BuildWriteError {
36     /// Returns the [`std::io::Error`] value if the `BuildWriteError` is an `Io`.
37     /// Otherwise `None` is returned.
io(&self) -> Option<&std::io::Error>38     pub fn io(&self) -> Option<&std::io::Error> {
39         match self {
40             BuildWriteError::Io(err) => Some(err),
41             _ => None,
42         }
43     }
44 
45     /// Returns the [`crate::err::ValueTooBigError`] value if the
46     /// `BuildWriteError` is a `PayloadLen`. Otherwise `None` is returned.
payload_len(&self) -> Option<&ValueTooBigError<usize>>47     pub fn payload_len(&self) -> Option<&ValueTooBigError<usize>> {
48         match self {
49             BuildWriteError::PayloadLen(err) => Some(err),
50             _ => None,
51         }
52     }
53 
54     /// Returns the [`crate::err::ipv4_exts::ExtsWalkError`] value if the
55     /// `BuildWriteError` is a `Ipv4Exts`. Otherwise `None` is returned.
ipv4_exts(&self) -> Option<&ipv4_exts::ExtsWalkError>56     pub fn ipv4_exts(&self) -> Option<&ipv4_exts::ExtsWalkError> {
57         match self {
58             BuildWriteError::Ipv4Exts(err) => Some(err),
59             _ => None,
60         }
61     }
62 
63     /// Returns the [`crate::err::ipv6_exts::ExtsWalkError`] value if the
64     /// `BuildWriteError` is a `Ipv6Exts`. Otherwise `None` is returned.
ipv6_exts(&self) -> Option<&ipv6_exts::ExtsWalkError>65     pub fn ipv6_exts(&self) -> Option<&ipv6_exts::ExtsWalkError> {
66         match self {
67             BuildWriteError::Ipv6Exts(err) => Some(err),
68             _ => None,
69         }
70     }
71 
72     /// Returns true if the `BuildWriteError` is a `Icmpv6InIpv4`.
is_icmpv6_in_ipv4(&self) -> bool73     pub fn is_icmpv6_in_ipv4(&self) -> bool {
74         matches!(self, BuildWriteError::Icmpv6InIpv4)
75     }
76 }
77 
78 #[cfg(feature = "std")]
79 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
80 impl core::fmt::Display for BuildWriteError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result81     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82         use BuildWriteError::*;
83         match self {
84             Io(err) => err.fmt(f),
85             PayloadLen(err) => err.fmt(f),
86             Ipv4Exts(err) => err.fmt(f),
87             Ipv6Exts(err) => err.fmt(f),
88             ArpHeaderNotMatch => write!(f, "address size defined in the ARP header does not match the actual size"),
89             Icmpv6InIpv4 => write!(f, "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."),
90         }
91     }
92 }
93 
94 #[cfg(feature = "std")]
95 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
96 impl std::error::Error for BuildWriteError {
source(&self) -> Option<&(dyn std::error::Error + 'static)>97     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
98         use BuildWriteError::*;
99         match self {
100             Io(ref err) => Some(err),
101             PayloadLen(ref err) => Some(err),
102             Ipv4Exts(err) => Some(err),
103             Ipv6Exts(err) => Some(err),
104             Icmpv6InIpv4 => None,
105             ArpHeaderNotMatch => None,
106         }
107     }
108 }
109 
110 #[cfg(test)]
111 mod tests {
112     use super::{BuildWriteError::*, *};
113     use crate::{err::ValueType, *};
114     use alloc::format;
115     use std::error::Error;
116 
117     #[test]
io()118     fn io() {
119         assert!(Io(std::io::Error::new(
120             std::io::ErrorKind::UnexpectedEof,
121             "failed to fill whole buffer",
122         ))
123         .io()
124         .is_some());
125         assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced {
126             missing_ext: IpNumber::AUTHENTICATION_HEADER,
127         })
128         .io()
129         .is_none());
130     }
131 
132     #[test]
payload_len()133     fn payload_len() {
134         {
135             let err = ValueTooBigError {
136                 actual: 3,
137                 max_allowed: 2,
138                 value_type: ValueType::Ipv4PayloadLength,
139             };
140             assert_eq!(Some(&err), PayloadLen(err.clone()).payload_len());
141         }
142         {
143             let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
144                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
145             };
146             assert_eq!(None, Ipv4Exts(err.clone()).payload_len());
147         }
148     }
149 
150     #[test]
ipv4_exts()151     fn ipv4_exts() {
152         assert!(Io(std::io::Error::new(
153             std::io::ErrorKind::UnexpectedEof,
154             "failed to fill whole buffer",
155         ))
156         .ipv4_exts()
157         .is_none());
158         {
159             let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
160                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
161             };
162             assert_eq!(Some(&err), Ipv4Exts(err.clone()).ipv4_exts());
163         }
164     }
165 
166     #[test]
ipv6_exts()167     fn ipv6_exts() {
168         assert!(Io(std::io::Error::new(
169             std::io::ErrorKind::UnexpectedEof,
170             "failed to fill whole buffer",
171         ))
172         .ipv6_exts()
173         .is_none());
174         {
175             let err = ipv6_exts::ExtsWalkError::ExtNotReferenced {
176                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
177             };
178             assert_eq!(Some(&err), Ipv6Exts(err.clone()).ipv6_exts());
179         }
180     }
181 
182     #[test]
is_icmpv6_in_ipv4()183     fn is_icmpv6_in_ipv4() {
184         assert_eq!(
185             false,
186             Io(std::io::Error::new(
187                 std::io::ErrorKind::UnexpectedEof,
188                 "failed to fill whole buffer",
189             ))
190             .is_icmpv6_in_ipv4()
191         );
192         assert!(Icmpv6InIpv4.is_icmpv6_in_ipv4());
193     }
194 
195     #[test]
debug()196     fn debug() {
197         let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
198             missing_ext: IpNumber::AUTHENTICATION_HEADER,
199         };
200         assert_eq!(
201             format!("Ipv4Exts({:?})", err.clone()),
202             format!("{:?}", Ipv4Exts(err))
203         );
204     }
205 
206     #[test]
fmt()207     fn fmt() {
208         {
209             let err = std::io::Error::new(
210                 std::io::ErrorKind::UnexpectedEof,
211                 "failed to fill whole buffer",
212             );
213             assert_eq!(format!("{}", err), format!("{}", Io(err)));
214         }
215         {
216             let err = ValueTooBigError {
217                 actual: 3,
218                 max_allowed: 2,
219                 value_type: ValueType::Ipv4PayloadLength,
220             };
221             assert_eq!(format!("{}", err), format!("{}", PayloadLen(err.clone())));
222         }
223         {
224             let err = ipv4_exts::ExtsWalkError::ExtNotReferenced {
225                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
226             };
227             assert_eq!(format!("{}", err), format!("{}", Ipv4Exts(err.clone())));
228         }
229         {
230             let err = ipv6_exts::ExtsWalkError::ExtNotReferenced {
231                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
232             };
233             assert_eq!(format!("{}", err), format!("{}", Ipv6Exts(err.clone())));
234         }
235         assert_eq!(
236             "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated).",
237             format!("{}", Icmpv6InIpv4)
238         );
239     }
240 
241     #[cfg(feature = "std")]
242     #[test]
source()243     fn source() {
244         assert!(Io(std::io::Error::new(
245             std::io::ErrorKind::UnexpectedEof,
246             "failed to fill whole buffer",
247         ))
248         .source()
249         .is_some());
250         assert!(PayloadLen(ValueTooBigError {
251             actual: 3,
252             max_allowed: 2,
253             value_type: ValueType::Ipv4PayloadLength,
254         })
255         .source()
256         .is_some());
257         assert!(Ipv4Exts(ipv4_exts::ExtsWalkError::ExtNotReferenced {
258             missing_ext: IpNumber::AUTHENTICATION_HEADER,
259         })
260         .source()
261         .is_some());
262         assert!(Ipv6Exts(ipv6_exts::ExtsWalkError::ExtNotReferenced {
263             missing_ext: IpNumber::AUTHENTICATION_HEADER,
264         })
265         .source()
266         .is_some());
267         assert!(Icmpv6InIpv4.source().is_none());
268     }
269 }
270