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        // Automatically add the "End" option.
96        encoder.encode_byte(255);
97
98        Ok(encoder.output)
99    }
100}
101
102/// Keeps track of the state of the output and provides methods to add data to the output.
103pub struct Encoder {
104    // This Vec starts empty and bytes are pushed as values are encoded.
105    output: Vec<u8>,
106}
107
108// Helpers for serializing in encode methods
109impl Encoder {
110    #[inline]
111    fn encode_bytes(&mut self, v: &[u8]) {
112        trace!("encode_bytes");
113        self.output.extend_from_slice(v);
114    }
115
116    #[inline]
117    fn encode_byte(&mut self, v: u8) {
118        trace!("encode_byte");
119        self.output.push(v);
120    }
121}
122
123// ---------------------------
124
125#[cfg(test)]
126mod tests {
127    use std::net::Ipv4Addr;
128
129    use super::*;
130    use crate::v4::*;
131
132    // Output additional debug info with
133    // RUST_LOG=debug cargo test test_to_bytes -- --show-output
134    fn init_logger() {
135        let _ = env_logger::builder().is_test(true).try_init();
136    }
137
138    #[test]
139    fn test_to_bytes() {
140        init_logger();
141
142        let message = Message {
143            op: Ops::Request,
144            htype: HTypes::Ethernet,
145            hlen: 6,
146            hops: 1,
147            xid: 4,
148            secs: 2,
149            flags: Flags { broadcast: true },
150            ciaddr: Ipv4Addr::new(1, 1, 1, 1),
151            yiaddr: Ipv4Addr::new(1, 1, 1, 1),
152            siaddr: Ipv4Addr::new(1, 1, 1, 1),
153            giaddr: Ipv4Addr::new(1, 1, 1, 1),
154            chaddr: [3; 16],
155            sname: SName::new(c"000000000000000000000000000000000000000000000000000000000000000").unwrap(),
156            file: File::new(c"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@").unwrap(),
157            magic: [99, 130, 83, 99],
158            options: vec![
159                MessageOptions::MessageType(MessageTypes::Discover),
160            ],
161        };
162
163        let expected = vec![
164            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,
165            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,
166            48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
167            48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
168            48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 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, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
173            64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
174            64, 64, 64, 64, 64, 0, 99, 130, 83, 99, 53, 1, 1, 255,
175        ];
176
177        assert_eq!(message.to_bytes().unwrap(), expected);
178    }
179}