use crate::{err::Layer, LenSource};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct LenError {
pub required_len: usize,
pub len: usize,
pub len_source: LenSource,
pub layer: Layer,
pub layer_start_offset: usize,
}
impl LenError {
#[inline]
pub const fn add_offset(self, offset: usize) -> Self {
LenError {
required_len: self.required_len,
layer: self.layer,
len: self.len,
len_source: self.len_source,
layer_start_offset: self.layer_start_offset + offset,
}
}
}
impl core::fmt::Display for LenError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let len_source: &'static str = {
use LenSource::*;
match self.len_source {
Slice => "slice length",
Ipv4HeaderTotalLen => "length calculated from the IPv4 header 'total length' field",
Ipv6HeaderPayloadLen => {
"length calculated from the IPv6 header 'payload length' field"
}
UdpHeaderLen => "length calculated from the UDP header 'length' field",
TcpHeaderLen => "length calculated from the TCP header 'length' field",
}
};
if self.required_len > self.len {
if self.layer_start_offset > 0 {
write!(
f,
"{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {} ('{}' starts at overall parsed byte {}).",
self.layer.error_title(),
self.layer,
self.required_len,
self.len,
len_source,
self.layer,
self.layer_start_offset
)
} else {
write!(
f,
"{}: Not enough data to decode '{}'. {} byte(s) would be required, but only {} byte(s) are available based on the {}.",
self.layer.error_title(),
self.layer,
self.required_len,
self.len,
len_source
)
}
} else if self.layer_start_offset > 0 {
write!(
f,
"{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length ('{}' starts at overall parsed byte {}).",
self.layer.error_title(),
self.len,
self.layer,
self.required_len,
len_source,
self.layer,
self.layer_start_offset
)
} else {
write!(
f,
"{}: Length of {} byte(s) is too big for an '{}' (maximum is {} bytes). The {} was used to determine the length.",
self.layer.error_title(),
self.len,
self.layer,
self.required_len,
len_source
)
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for LenError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
#[cfg(test)]
mod test {
use super::*;
use alloc::format;
use std::{
collections::hash_map::DefaultHasher,
error::Error,
hash::{Hash, Hasher},
};
#[test]
fn add_offset() {
assert_eq!(
LenError {
required_len: 2,
layer: Layer::Icmpv4,
len: 1,
len_source: LenSource::Slice,
layer_start_offset: 20,
}
.add_offset(100),
LenError {
required_len: 2,
layer: Layer::Icmpv4,
len: 1,
len_source: LenSource::Slice,
layer_start_offset: 120,
}
);
}
#[test]
fn debug() {
assert_eq!(
format!(
"{:?}",
LenError {
required_len: 2,
layer: Layer::Ipv4Header,
len: 1,
len_source: LenSource::Slice,
layer_start_offset: 0
}
),
format!(
"LenError {{ required_len: {:?}, len: {:?}, len_source: {:?}, layer: {:?}, layer_start_offset: {:?} }}",
2, 1, LenSource::Slice, Layer::Ipv4Header, 0
),
);
}
#[test]
fn clone_eq_hash() {
let err = LenError {
required_len: 2,
layer: Layer::Icmpv4,
len: 1,
len_source: LenSource::Slice,
layer_start_offset: 20,
};
assert_eq!(err, err.clone());
let hash_a = {
let mut hasher = DefaultHasher::new();
err.hash(&mut hasher);
hasher.finish()
};
let hash_b = {
let mut hasher = DefaultHasher::new();
err.clone().hash(&mut hasher);
hasher.finish()
};
assert_eq!(hash_a, hash_b);
}
#[test]
fn fmt() {
{
use crate::LenSource::*;
let len_source_tests = [
(Slice, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the slice length."),
(Ipv4HeaderTotalLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the IPv4 header 'total length' field."),
(Ipv6HeaderPayloadLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the IPv6 header 'payload length' field."),
(UdpHeaderLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the UDP header 'length' field."),
(TcpHeaderLen, "IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the length calculated from the TCP header 'length' field."),
];
for test in len_source_tests {
assert_eq!(
test.1,
format!(
"{}",
LenError {
required_len: 2,
layer: Layer::Ipv4Header,
len: 1,
len_source: test.0,
layer_start_offset: 0
}
)
);
}
}
assert_eq!(
"IPv4 Header Error: Not enough data to decode 'IPv4 header'. 2 byte(s) would be required, but only 1 byte(s) are available based on the slice length ('IPv4 header' starts at overall parsed byte 4).",
format!(
"{}",
LenError{
required_len: 2,
len: 1,
len_source: LenSource::Slice,
layer: Layer::Ipv4Header,
layer_start_offset: 4
}
)
);
{
use crate::LenSource::*;
let len_source_tests = [
(Slice, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The slice length was used to determine the length."),
(Ipv4HeaderTotalLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the IPv4 header 'total length' field was used to determine the length."),
(Ipv6HeaderPayloadLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the IPv6 header 'payload length' field was used to determine the length."),
(UdpHeaderLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the UDP header 'length' field was used to determine the length."),
(TcpHeaderLen, "IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The length calculated from the TCP header 'length' field was used to determine the length."),
];
for test in len_source_tests {
assert_eq!(
test.1,
format!(
"{}",
LenError {
required_len: 1,
layer: Layer::Ipv4Header,
len: 2,
len_source: test.0,
layer_start_offset: 0
}
)
);
}
}
assert_eq!(
"IPv4 Header Error: Length of 2 byte(s) is too big for an 'IPv4 header' (maximum is 1 bytes). The slice length was used to determine the length ('IPv4 header' starts at overall parsed byte 4).",
format!(
"{}",
LenError{
required_len: 1,
len: 2,
len_source: LenSource::Slice,
layer: Layer::Ipv4Header,
layer_start_offset: 4
}
)
);
}
#[cfg(feature = "std")]
#[test]
fn source() {
assert!(LenError {
required_len: 0,
len: 0,
len_source: LenSource::Slice,
layer: Layer::Ipv4Header,
layer_start_offset: 0
}
.source()
.is_none());
}
}