use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read};
use std::net::Ipv6Addr;
use crate::Header;
#[derive(Debug)]
#[allow(missing_docs)]
#[allow(non_camel_case_types)]
pub enum BGP4PLUS {
NULL,
UPDATE(MESSAGE),
PREF_UPDATE,
STATE_CHANGE(STATE_CHANGE),
SYNC(SYNC),
OPEN(MESSAGE),
NOTIFY(MESSAGE),
KEEPALIVE(MESSAGE),
}
impl BGP4PLUS {
pub(crate) fn parse(header: &Header, stream: &mut Read) -> Result<BGP4PLUS, Error> {
match header.sub_type {
0 => Ok(BGP4PLUS::NULL),
1 => Ok(BGP4PLUS::UPDATE(MESSAGE::parse(header, stream)?)),
2 => Ok(BGP4PLUS::PREF_UPDATE),
3 => Ok(BGP4PLUS::STATE_CHANGE(STATE_CHANGE::parse(stream)?)),
4 => Ok(BGP4PLUS::SYNC(SYNC::parse(stream)?)),
5 => Ok(BGP4PLUS::OPEN(MESSAGE::parse(header, stream)?)),
6 => Ok(BGP4PLUS::NOTIFY(MESSAGE::parse(header, stream)?)),
7 => Ok(BGP4PLUS::KEEPALIVE(MESSAGE::parse(header, stream)?)),
_ => Err(Error::new(
ErrorKind::Other,
"Unknown MRT record subtype found in MRTHeader",
)),
}
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct MESSAGE {
pub peer_as: u16,
pub peer_ip: Ipv6Addr,
pub local_as: u16,
pub local_ip: Ipv6Addr,
pub message: Vec<u8>,
}
impl MESSAGE {
fn parse(header: &Header, stream: &mut Read) -> Result<MESSAGE, Error> {
let peer_as = stream.read_u16::<BigEndian>()?;
let peer_ip = Ipv6Addr::from(stream.read_u128::<BigEndian>()?);
let local_as = stream.read_u16::<BigEndian>()?;
let local_ip = Ipv6Addr::from(stream.read_u128::<BigEndian>()?);
let length = header.length - 12;
let mut message = vec![0; length as usize];
stream.read_exact(&mut message)?;
Ok(MESSAGE {
peer_as,
peer_ip,
local_as,
local_ip,
message,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct STATE_CHANGE {
pub peer_as: u16,
pub peer_ip: Ipv6Addr,
pub old_state: u16,
pub new_state: u16,
}
impl STATE_CHANGE {
fn parse(stream: &mut Read) -> Result<STATE_CHANGE, Error> {
Ok(STATE_CHANGE {
peer_as: stream.read_u16::<BigEndian>()?,
peer_ip: Ipv6Addr::from(stream.read_u128::<BigEndian>()?),
old_state: stream.read_u16::<BigEndian>()?,
new_state: stream.read_u16::<BigEndian>()?,
})
}
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct SYNC {
pub view_number: u16,
pub filename: Vec<u8>,
}
impl SYNC {
fn parse(stream: &mut Read) -> Result<SYNC, Error> {
let view_number = stream.read_u16::<BigEndian>()?;
let mut filename = Vec::new();
let mut buffer = stream.read_u8()?;
while buffer != b'\0' {
filename.push(buffer);
buffer = stream.read_u8()?;
}
Ok(SYNC {
view_number,
filename,
})
}
}