use super::MAGIC;
use crate::v4::{MAX_MESSAGE_SIZE, MagicBuffer};
use log::trace;
use std::fmt::Debug;
pub trait Encodable: EncodeMessage + Debug {}
pub trait EncodeMessage {
fn encode_op(&self) -> u8;
fn encode_htype(&self) -> u8;
fn encode_hlen(&self) -> u8;
fn encode_hops(&self) -> u8;
fn encode_xid(&self) -> [u8; 4];
fn encode_secs(&self) -> [u8; 2];
fn encode_flags(&self) -> [u8; 2];
fn encode_ciaddr(&self) -> [u8; 4];
fn encode_yiaddr(&self) -> [u8; 4];
fn encode_siaddr(&self) -> [u8; 4];
fn encode_giaddr(&self) -> [u8; 4];
fn encode_chaddr(&self) -> [u8; 16];
fn encode_sname(&self) -> [u8; 64];
fn encode_file(&self) -> [u8; 128];
fn encode_options(&self) -> Vec<u8>;
fn encode_magic(&self) -> MagicBuffer {
MAGIC
}
fn to_bytes(&self) -> Vec<u8> {
trace!("to_bytes");
let mut encoder = Encoder {
output: Vec::with_capacity(MAX_MESSAGE_SIZE),
};
trace!("encode op");
encoder.encode_byte(self.encode_op());
trace!("encode htype");
encoder.encode_byte(self.encode_htype());
trace!("encode hlen");
encoder.encode_byte(self.encode_hlen());
trace!("encode hops");
encoder.encode_byte(self.encode_hops());
trace!("encode xid");
encoder.encode_bytes(&self.encode_xid());
trace!("encode secs");
encoder.encode_bytes(&self.encode_secs());
trace!("encode flags");
encoder.encode_bytes(&self.encode_flags());
trace!("encode ciaddr");
encoder.encode_bytes(&self.encode_ciaddr());
trace!("encode yiaddr");
encoder.encode_bytes(&self.encode_yiaddr());
trace!("encode siaddr");
encoder.encode_bytes(&self.encode_siaddr());
trace!("encode giaddr");
encoder.encode_bytes(&self.encode_giaddr());
trace!("encode chaddr");
encoder.encode_bytes(&self.encode_chaddr());
trace!("encode sname");
encoder.encode_bytes(&self.encode_sname());
trace!("encode file");
encoder.encode_bytes(&self.encode_file());
trace!("encode magic");
encoder.encode_bytes(&self.encode_magic());
trace!("encode options");
encoder.encode_bytes(self.encode_options().as_slice());
encoder.encode_byte(255);
encoder.output
}
}
#[derive(Debug)]
pub struct Encoder {
output: Vec<u8>,
}
impl Encoder {
#[inline]
fn encode_bytes(&mut self, v: &[u8]) {
trace!("encode_bytes");
self.output.extend_from_slice(v);
}
#[inline]
fn encode_byte(&mut self, v: u8) {
trace!("encode_byte");
self.output.push(v);
}
}
#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
use super::*;
use crate::v4::*;
fn init_logger() {
let _ = env_logger::builder().is_test(true).try_init();
}
#[test]
fn test_to_bytes() {
init_logger();
let message = Message {
op: Ops::Request,
htype: HTypes::Ethernet,
hlen: 6,
hops: 1,
xid: 4,
secs: 2,
flags: Flags { broadcast: true },
ciaddr: Ipv4Addr::new(1, 1, 1, 1),
yiaddr: Ipv4Addr::new(1, 1, 1, 1),
siaddr: Ipv4Addr::new(1, 1, 1, 1),
giaddr: Ipv4Addr::new(1, 1, 1, 1),
chaddr: [3; 16],
sname: SName::new(c"000000000000000000000000000000000000000000000000000000000000000").unwrap(),
file: File::new(c"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@").unwrap(),
magic: [99, 130, 83, 99],
options: vec![
MessageOptions::MessageType(MessageTypes::Discover),
].into(),
};
let expected = vec![
1, 1, 6, 1, 0, 0, 0, 4, 0, 2, 128, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 0, 99, 130, 83, 99, 53, 1, 1, 255,
];
assert_eq!(message.to_bytes(), expected);
}
}