1 use super::HeadersError; 2 use crate::err::LenError; 3 4 /// Error when decoding an IP header via a `std::io::Read` source. 5 #[cfg(feature = "std")] 6 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 7 #[derive(Debug)] 8 pub enum HeaderReadError { 9 /// IO error was encountered while reading header. 10 Io(std::io::Error), 11 12 /// Errors caused by conflicts with the lengths defined 13 /// in the headers (i.e. IPv4 length too small to read the 14 /// lower layer headers) 15 Len(LenError), 16 17 /// Error caused by the contents of the header. 18 Content(HeadersError), 19 } 20 21 #[cfg(feature = "std")] 22 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 23 impl HeaderReadError { 24 /// Returns the `std::io::Error` value if the `HeaderReadError` is `Io`. 25 /// Otherwise `None` is returned. 26 #[inline] io(self) -> Option<std::io::Error>27 pub fn io(self) -> Option<std::io::Error> { 28 use HeaderReadError::*; 29 match self { 30 Io(value) => Some(value), 31 _ => None, 32 } 33 } 34 35 /// Returns the `err::LenError` value if the `HeaderReadError` is `Len`. 36 /// Otherwise `None` is returned. 37 #[inline] len(self) -> Option<LenError>38 pub fn len(self) -> Option<LenError> { 39 use HeaderReadError::*; 40 match self { 41 Len(value) => Some(value), 42 _ => None, 43 } 44 } 45 46 /// Returns the `err::ip::HeaderError` value if the `HeaderReadError` is `Content`. 47 /// Otherwise `None` is returned. 48 #[inline] content(self) -> Option<HeadersError>49 pub fn content(self) -> Option<HeadersError> { 50 use HeaderReadError::*; 51 match self { 52 Content(value) => Some(value), 53 _ => None, 54 } 55 } 56 } 57 58 #[cfg(feature = "std")] 59 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 60 impl core::fmt::Display for HeaderReadError { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result61 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 62 use HeaderReadError::*; 63 match self { 64 Io(err) => write!(f, "IP Header IO Error: {}", err), 65 Len(err) => err.fmt(f), 66 Content(err) => err.fmt(f), 67 } 68 } 69 } 70 71 #[cfg(feature = "std")] 72 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 73 impl std::error::Error for HeaderReadError { source(&self) -> Option<&(dyn std::error::Error + 'static)>74 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 75 use HeaderReadError::*; 76 match self { 77 Io(err) => Some(err), 78 Len(err) => Some(err), 79 Content(err) => Some(err), 80 } 81 } 82 } 83 84 #[cfg(all(test, feature = "std"))] 85 mod test { 86 use super::{super::HeaderError::*, super::HeadersError::*, HeaderReadError::*, *}; 87 use crate::{err::Layer, LenSource}; 88 use alloc::format; 89 90 #[test] debug()91 fn debug() { 92 let err = HeadersError::Ip(UnsupportedIpVersion { version_number: 6 }); 93 assert_eq!( 94 format!("Content({:?})", err.clone()), 95 format!("{:?}", Content(err)) 96 ); 97 } 98 99 #[test] fmt()100 fn fmt() { 101 { 102 let err = std::io::Error::new( 103 std::io::ErrorKind::UnexpectedEof, 104 "failed to fill whole buffer", 105 ); 106 assert_eq!( 107 format!("IP Header IO Error: {}", err), 108 format!("{}", Io(err)) 109 ); 110 } 111 { 112 let err = LenError { 113 required_len: 2, 114 len: 1, 115 len_source: LenSource::Slice, 116 layer: Layer::Icmpv4, 117 layer_start_offset: 3, 118 }; 119 assert_eq!(format!("{}", Len(err.clone())), format!("{}", err)); 120 } 121 { 122 let err = Ip(UnsupportedIpVersion { version_number: 6 }); 123 assert_eq!(format!("{}", &err), format!("{}", Content(err.clone()))); 124 } 125 } 126 127 #[test] source()128 fn source() { 129 use std::error::Error; 130 assert!(Io(std::io::Error::new( 131 std::io::ErrorKind::UnexpectedEof, 132 "failed to fill whole buffer", 133 )) 134 .source() 135 .is_some()); 136 assert!(Len(LenError { 137 required_len: 2, 138 len: 1, 139 len_source: LenSource::Slice, 140 layer: Layer::Icmpv4, 141 layer_start_offset: 3, 142 }) 143 .source() 144 .is_some()); 145 assert!(Content(Ip(UnsupportedIpVersion { version_number: 6 })) 146 .source() 147 .is_some()); 148 } 149 150 #[test] io()151 fn io() { 152 assert!(Io(std::io::Error::new( 153 std::io::ErrorKind::UnexpectedEof, 154 "failed to fill whole buffer", 155 )) 156 .io() 157 .is_some()); 158 assert!(Content(Ip(UnsupportedIpVersion { version_number: 6 })) 159 .io() 160 .is_none()); 161 } 162 163 #[test] len()164 fn len() { 165 { 166 let err = LenError { 167 required_len: 2, 168 len: 1, 169 len_source: LenSource::Slice, 170 layer: Layer::Icmpv4, 171 layer_start_offset: 3, 172 }; 173 assert_eq!(Len(err.clone()).len(), Some(err)); 174 } 175 assert!(Io(std::io::Error::new( 176 std::io::ErrorKind::UnexpectedEof, 177 "failed to fill whole buffer", 178 )) 179 .len() 180 .is_none()); 181 } 182 183 #[test] content()184 fn content() { 185 assert_eq!( 186 None, 187 Io(std::io::Error::new( 188 std::io::ErrorKind::UnexpectedEof, 189 "failed to fill whole buffer", 190 )) 191 .content() 192 ); 193 { 194 let err = Ip(UnsupportedIpVersion { version_number: 6 }); 195 assert_eq!(Some(err.clone()), Content(err.clone()).content()); 196 } 197 } 198 } 199