use crate::common::{
PcapError,
PcapResult,
ReadEndian,
WriteEndian,
};
use std::io::Read;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PcapPacket {
pub ts_sec: u32,
pub ts_frac: u32,
pub incl_len: u32,
pub orig_len: u32,
pub data: Vec<u8>,
}
impl PcapPacket {
pub fn read<R>(reader: R) -> PcapResult<Self>
where
R: ReadEndian,
{
let data = vec![];
Self::read_with(reader, data)
}
pub fn read_with<R>(mut reader: R, mut data: Vec<u8>) -> PcapResult<Self>
where
R: ReadEndian,
{
let ts_sec = reader.read_u32()?;
let ts_frac = reader.read_u32()?;
let incl_len = reader.read_u32()?;
let orig_len = reader.read_u32()?;
let mut data_reader = reader.take(incl_len as u64);
data.clear();
data_reader.read_to_end(&mut data)?;
if data.len() != incl_len as usize {
return Err(PcapError::IncompleteBuffer);
}
let packet = PcapPacket {
ts_sec,
ts_frac,
incl_len,
orig_len,
data,
};
Ok(packet)
}
#[inline]
pub fn write<W>(&self, writer: W) -> PcapResult<u32>
where
W: WriteEndian,
{
write_packet(
writer,
self.ts_sec,
self.ts_frac,
self.incl_len,
self.orig_len,
&self.data,
)
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u32 {
16 + self.incl_len
}
}
#[inline]
pub(crate) fn write_packet<W>(
mut writer: W,
ts_sec: u32,
ts_frac: u32,
incl_len: u32,
orig_len: u32,
data: impl AsRef<[u8]>,
) -> PcapResult<u32>
where
W: WriteEndian,
{
let data = data.as_ref();
if data.len() != incl_len as usize {
return Err(PcapError::PacketPayloadMismatch);
}
writer.write_u32(ts_sec)?;
writer.write_u32(ts_frac)?;
writer.write_u32(incl_len)?;
writer.write_u32(orig_len)?;
writer.write_all(data)?;
Ok(16 + incl_len)
}