use crate::models::{CommonHeader, EntryType};
use crate::ParserError;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::io::Read;
pub fn parse_common_header<T: Read>(input: &mut T) -> Result<CommonHeader, ParserError> {
let mut raw_bytes = [0u8; 12];
input.read_exact(&mut raw_bytes)?;
let mut data = BytesMut::from(&raw_bytes[..]);
let timestamp = data.get_u32();
let entry_type_raw = data.get_u16();
let entry_type = EntryType::try_from(entry_type_raw)?;
let entry_subtype = data.get_u16();
let mut length = data.get_u32();
let microsecond_timestamp = match &entry_type {
EntryType::BGP4MP_ET => {
length -= 4;
let mut raw_bytes: [u8; 4] = [0; 4];
input.read_exact(&mut raw_bytes)?;
Some(BytesMut::from(&raw_bytes[..]).get_u32())
}
_ => None,
};
Ok(CommonHeader {
timestamp,
microsecond_timestamp,
entry_type,
entry_subtype,
length,
})
}
impl CommonHeader {
pub fn encode(&self) -> Bytes {
let mut bytes = BytesMut::new();
bytes.put_slice(&self.timestamp.to_be_bytes());
bytes.put_u16(self.entry_type as u16);
bytes.put_u16(self.entry_subtype);
match self.microsecond_timestamp {
None => bytes.put_u32(self.length),
Some(microseconds) => {
bytes.put_u32(self.length + 4);
bytes.put_u32(microseconds);
}
};
bytes.freeze()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::EntryType;
use bytes::Buf;
#[test]
fn test_encode_common_header() {
let header = CommonHeader {
timestamp: 1,
microsecond_timestamp: None,
entry_type: EntryType::BGP4MP,
entry_subtype: 4,
length: 5,
};
let expected = Bytes::from_static(&[
0, 0, 0, 1, 0, 16, 0, 4, 0, 0, 0, 5, ]);
let encoded = header.encode();
assert_eq!(encoded, expected);
let mut reader = expected.reader();
let parsed = parse_common_header(&mut reader).unwrap();
assert_eq!(parsed, header);
}
#[test]
fn test_encode_common_header_et() {
let header = CommonHeader {
timestamp: 1,
microsecond_timestamp: Some(230_000),
entry_type: EntryType::BGP4MP_ET,
entry_subtype: 4,
length: 5,
};
let expected = Bytes::from_static(&[
0, 0, 0, 1, 0, 17, 0, 4, 0, 0, 0, 9, 0, 3, 130, 112, ]);
let encoded = header.encode();
assert_eq!(encoded, expected);
let mut reader = expected.reader();
let parsed = parse_common_header(&mut reader).unwrap();
assert_eq!(parsed, header);
}
}