use crate::errors::*;
use std::io::Write;
use std::io::Read;
use byteorder::{BigEndian, LittleEndian, ByteOrder, WriteBytesExt, ReadBytesExt};
use crate::{DataLink, Endianness, TsResolution};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PcapHeader {
pub magic_number: u32,
pub version_major: u16,
pub version_minor: u16,
pub ts_correction: i32,
pub ts_accuracy: u32,
pub snaplen: u32,
pub datalink: DataLink
}
impl PcapHeader {
pub fn from_reader<R: Read>(reader: &mut R) -> ResultParsing<PcapHeader> {
let magic_number = reader.read_u32::<BigEndian>()?;
match magic_number {
0xa1b2c3d4 | 0xa1b23c4d => return init_pcap_header::<_, BigEndian>(reader, magic_number),
0xd4c3b2a1 | 0x4d3cb2a1 => return init_pcap_header::<_, LittleEndian>(reader, magic_number),
_ => return Err(PcapError::InvalidField("PcapHeader wrong magic number"))
};
fn init_pcap_header<R: Read, B: ByteOrder>(reader: &mut R, magic_number:u32) -> ResultParsing<PcapHeader> {
Ok(
PcapHeader {
magic_number,
version_major : reader.read_u16::<B>()?,
version_minor : reader.read_u16::<B>()?,
ts_correction : reader.read_i32::<B>()?,
ts_accuracy : reader.read_u32::<B>()?,
snaplen : reader.read_u32::<B>()?,
datalink : DataLink::from(reader.read_u32::<B>()?)
}
)
}
}
pub fn from_slice(mut slice: &[u8]) -> ResultParsing<(&[u8], PcapHeader)> {
if slice.len() < 24 {
return Err(PcapError::IncompleteBuffer(24 - slice.len()))
}
let header = PcapHeader::from_reader(&mut slice)?;
Ok((slice, header))
}
pub fn set_ts_resolution(&mut self, ts_resolution: TsResolution) {
use TsResolution::*;
let mut new_magic: u32 = match ts_resolution {
MicroSecond => 0xa1b2c3d4,
NanoSecond => 0xa1b23c4d,
};
if self.endianness().is_little() {
new_magic = new_magic.swap_bytes();
}
self.magic_number = new_magic;
}
pub fn set_endianness(&mut self, endianness: Endianness) {
if self.endianness() != endianness {
self.magic_number = self.magic_number.swap_bytes();
}
}
pub fn write_to<W: Write, B: ByteOrder>(&self, writer: &mut W) -> ResultParsing<()> {
writer.write_u32::<BigEndian>(self.magic_number)?;
writer.write_u16::<B>(self.version_major)?;
writer.write_u16::<B>(self.version_minor)?;
writer.write_i32::<B>(self.ts_correction)?;
writer.write_u32::<B>(self.ts_accuracy)?;
writer.write_u32::<B>(self.snaplen)?;
writer.write_u32::<B>(self.datalink.into())?;
Ok(())
}
pub fn endianness(&self) -> Endianness {
match self.magic_number {
0xa1b2c3d4 | 0xa1b23c4d => Endianness::Big,
0xd4c3b2a1 | 0x4d3cb2a1 => Endianness::Little,
_ => unreachable!("Wrong magic number, can't get the header's endianness")
}
}
pub fn ts_resolution(&self) -> TsResolution {
match self.magic_number {
0xa1b2c3d4 | 0xd4c3b2a1 => TsResolution::MicroSecond,
0xa1b23c4d | 0x4d3cb2a1 => TsResolution::NanoSecond,
_ => unreachable!("Wrong magic number, can't get the header's timestamp resolution")
}
}
#[deprecated(since="1.0.0", note="Please use `write_to` instead")]
pub fn to_array<B: ByteOrder>(&self) -> ResultParsing<Vec<u8>> {
let mut out = Vec::with_capacity(24);
self.write_to::<_, B>(&mut out)?;
Ok(out)
}
#[deprecated(since="1.0.0", note="Please use the Default struct constructor instead, will be removed in 1.0")]
pub fn with_datalink(datalink: DataLink) -> PcapHeader {
PcapHeader {
datalink,
..Default::default()
}
}
}
impl Default for PcapHeader {
fn default() -> Self {
PcapHeader {
magic_number: 0xa1b2c3d4,
version_major: 2,
version_minor: 4,
ts_correction: 0,
ts_accuracy: 0,
snaplen: 65535,
datalink: DataLink::ETHERNET,
}
}
}