toe_beans/v4/message/
encode.rs

1use super::MAGIC;
2use crate::v4::error::Result;
3use log::trace;
4
5/// Define how your custom Message type encodes
6/// itself into the bytes of a DHCP message's fields.
7///
8/// ...or don't and use our homemade [Message](crate::v4::message::Message)
9/// with this already implemented.
10///
11/// If your type is in a different module you can define
12/// [From or Into](https://doc.rust-lang.org/std/convert/index.html)
13/// in that module and call that method in one of this trait's `encode_*`
14/// methods. See Message's implementation for details.
15pub trait EncodeMessage {
16    /// Represent any data type as the correct amount of op field bytes.
17    fn encode_op(&self) -> u8;
18    /// Represent any data type as the correct amount of htype field bytes.
19    fn encode_htype(&self) -> u8;
20    /// Represent any data type as the correct amount of hlen field bytes.
21    fn encode_hlen(&self) -> u8;
22    /// Represent any data type as the correct amount of hops field bytes.
23    fn encode_hops(&self) -> u8;
24    /// Represent any data type as the correct amount of xid field bytes.
25    fn encode_xid(&self) -> [u8; 4];
26    /// Represent any data type as the correct amount of secs field bytes.
27    fn encode_secs(&self) -> [u8; 2];
28    /// Represent any data type as the correct amount of flags field bytes.
29    fn encode_flags(&self) -> [u8; 2];
30    /// Represent any data type as the correct amount of ciaddr field bytes.
31    fn encode_ciaddr(&self) -> [u8; 4];
32    /// Represent any data type as the correct amount of yiaddr field bytes.
33    fn encode_yiaddr(&self) -> [u8; 4];
34    /// Represent any data type as the correct amount of siaddr field bytes.
35    fn encode_siaddr(&self) -> [u8; 4];
36    /// Represent any data type as the correct amount of giaddr field bytes.
37    fn encode_giaddr(&self) -> [u8; 4];
38    /// Represent any data type as the correct amount of chaddr field bytes.
39    fn encode_chaddr(&self) -> [u8; 16];
40    /// Represent any data type as the correct amount of sname field bytes.
41    fn encode_sname(&self) -> [u8; 64];
42    /// Represent any data type as the correct amount of file field bytes.
43    fn encode_file(&self) -> [u8; 128];
44    /// Represent any data type as a variable amount of options field bytes.
45    fn encode_options(&self) -> Vec<u8>;
46
47    /// Automagically defined because its a constant
48    fn encode_magic(&self) -> [u8; 4] {
49        MAGIC
50    }
51
52    /// Encodes a [Message](crate::v4::Message) into a Vec of bytes
53    /// by calling the encode_* methods defined in EncodeMessage,
54    /// and uses a Encoder to store the output.
55    fn to_bytes(&self) -> Result<Vec<u8>> {
56        trace!("to_bytes");
57
58        let mut encoder = Encoder {
59            output: Vec::with_capacity(552),
60        };
61
62        trace!("encode op");
63        encoder.encode_byte(self.encode_op());
64        trace!("encode htype");
65        encoder.encode_byte(self.encode_htype());
66        trace!("encode hlen");
67        encoder.encode_byte(self.encode_hlen());
68        trace!("encode hops");
69        encoder.encode_byte(self.encode_hops());
70        trace!("encode xid");
71        encoder.encode_bytes(&self.encode_xid());
72        trace!("encode secs");
73        encoder.encode_bytes(&self.encode_secs());
74        trace!("encode flags");
75        encoder.encode_bytes(&self.encode_flags());
76        trace!("encode ciaddr");
77        encoder.encode_bytes(&self.encode_ciaddr());
78        trace!("encode yiaddr");
79        encoder.encode_bytes(&self.encode_yiaddr());
80        trace!("encode siaddr");
81        encoder.encode_bytes(&self.encode_siaddr());
82        trace!("encode giaddr");
83        encoder.encode_bytes(&self.encode_giaddr());
84        trace!("encode chaddr");
85        encoder.encode_bytes(&self.encode_chaddr());
86        trace!("encode sname");
87        encoder.encode_bytes(&self.encode_sname());
88        trace!("encode file");
89        encoder.encode_bytes(&self.encode_file());
90        trace!("encode magic");
91        encoder.encode_bytes(&self.encode_magic());
92        trace!("encode options");
93        encoder.encode_bytes(self.encode_options().as_slice());
94
95        Ok(encoder.output)
96    }
97}
98
99/// Keeps track of the state of the output and provides methods to add data to the output.
100pub struct Encoder {
101    // This Vec starts empty and bytes are pushed as values are encoded.
102    output: Vec<u8>,
103}
104
105// Helpers for serializing in encode methods
106impl Encoder {
107    #[inline]
108    fn encode_bytes(&mut self, v: &[u8]) {
109        trace!("encode_bytes");
110        self.output.extend_from_slice(v);
111    }
112
113    #[inline]
114    fn encode_byte(&mut self, v: u8) {
115        trace!("encode_byte");
116        self.output.push(v);
117    }
118}
119
120// ---------------------------
121
122#[cfg(test)]
123mod tests {
124    use std::net::Ipv4Addr;
125
126    use super::*;
127    use crate::v4::*;
128
129    // Output additional debug info with
130    // RUST_LOG=debug cargo test test_to_bytes -- --show-output
131    fn init_logger() {
132        let _ = env_logger::builder().is_test(true).try_init();
133    }
134
135    #[test]
136    fn test_to_bytes() {
137        init_logger();
138
139        let message = Message {
140            op: Ops::Request,
141            htype: HTypes::Ethernet,
142            hlen: 6,
143            hops: 1,
144            xid: 4,
145            secs: 2,
146            flags: Flags { broadcast: true },
147            ciaddr: Ipv4Addr::new(1, 1, 1, 1),
148            yiaddr: Ipv4Addr::new(1, 1, 1, 1),
149            siaddr: Ipv4Addr::new(1, 1, 1, 1),
150            giaddr: Ipv4Addr::new(1, 1, 1, 1),
151            chaddr: [3; 16],
152            sname: SName::new(c"000000000000000000000000000000000000000000000000000000000000000").unwrap(),
153            file: File::new(c"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@").unwrap(),
154            magic: [99, 130, 83, 99],
155            options: vec![
156                MessageOptions::MessageType(MessageTypes::Discover),
157                MessageOptions::End
158            ],
159        };
160
161        let expected = vec![
162            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,
163            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,
164            48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
165            48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
166            48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
167            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
168            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
169            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
170            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
171            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
172            64, 64, 64, 64, 64, 0, 99, 130, 83, 99, 53, 1, 1, 255,
173        ];
174
175        assert_eq!(message.to_bytes().unwrap(), expected);
176    }
177}