Skip to main content

toe_beans/v4/message/
encode.rs

1use super::MAGIC;
2use crate::v4::{MAX_MESSAGE_SIZE, MagicBuffer};
3use std::fmt::Debug;
4use tracing::trace;
5
6/// A supertrait that defines everything a custom message
7/// needs to be encoded before being sent by a socket.
8pub trait Encodable: EncodeMessage + Debug {}
9
10/// Define how your custom Message type encodes
11/// itself into the bytes of a DHCP message's fields.
12///
13/// ...or don't and use our homemade [Message](crate::v4::message::Message)
14/// with this already implemented.
15///
16/// If your type is in a different module you can define
17/// [From or Into](https://doc.rust-lang.org/std/convert/index.html)
18/// in that module and call that method in one of this trait's `encode_*`
19/// methods. See Message's implementation for details.
20pub trait EncodeMessage {
21    /// Represent any data type as the correct amount of op field bytes.
22    fn encode_op(&self) -> u8;
23    /// Represent any data type as the correct amount of htype field bytes.
24    fn encode_htype(&self) -> u8;
25    /// Represent any data type as the correct amount of hlen field bytes.
26    fn encode_hlen(&self) -> u8;
27    /// Represent any data type as the correct amount of hops field bytes.
28    fn encode_hops(&self) -> u8;
29    /// Represent any data type as the correct amount of xid field bytes.
30    fn encode_xid(&self) -> [u8; 4];
31    /// Represent any data type as the correct amount of secs field bytes.
32    fn encode_secs(&self) -> [u8; 2];
33    /// Represent any data type as the correct amount of flags field bytes.
34    fn encode_flags(&self) -> [u8; 2];
35    /// Represent any data type as the correct amount of ciaddr field bytes.
36    fn encode_ciaddr(&self) -> [u8; 4];
37    /// Represent any data type as the correct amount of yiaddr field bytes.
38    fn encode_yiaddr(&self) -> [u8; 4];
39    /// Represent any data type as the correct amount of siaddr field bytes.
40    fn encode_siaddr(&self) -> [u8; 4];
41    /// Represent any data type as the correct amount of giaddr field bytes.
42    fn encode_giaddr(&self) -> [u8; 4];
43    /// Represent any data type as the correct amount of chaddr field bytes.
44    fn encode_chaddr(&self) -> [u8; 16];
45    /// Represent any data type as the correct amount of sname field bytes.
46    fn encode_sname(&self) -> [u8; 64];
47    /// Represent any data type as the correct amount of file field bytes.
48    fn encode_file(&self) -> [u8; 128];
49    /// Represent any data type as a variable amount of options field bytes.
50    fn encode_options(&self) -> Vec<u8>;
51
52    /// Automagically defined because its a constant
53    fn encode_magic(&self) -> MagicBuffer {
54        MAGIC
55    }
56
57    /// Encodes a [Message](crate::v4::Message) into a Vec of bytes
58    /// by calling the encode_* methods defined in EncodeMessage,
59    /// and uses a Encoder to store the output.
60    fn to_bytes(&self) -> Vec<u8> {
61        trace!("to_bytes");
62
63        let mut encoder = Encoder {
64            output: Vec::with_capacity(MAX_MESSAGE_SIZE),
65        };
66
67        trace!("encode op");
68        encoder.encode_byte(self.encode_op());
69        trace!("encode htype");
70        encoder.encode_byte(self.encode_htype());
71        trace!("encode hlen");
72        encoder.encode_byte(self.encode_hlen());
73        trace!("encode hops");
74        encoder.encode_byte(self.encode_hops());
75        trace!("encode xid");
76        encoder.encode_bytes(&self.encode_xid());
77        trace!("encode secs");
78        encoder.encode_bytes(&self.encode_secs());
79        trace!("encode flags");
80        encoder.encode_bytes(&self.encode_flags());
81        trace!("encode ciaddr");
82        encoder.encode_bytes(&self.encode_ciaddr());
83        trace!("encode yiaddr");
84        encoder.encode_bytes(&self.encode_yiaddr());
85        trace!("encode siaddr");
86        encoder.encode_bytes(&self.encode_siaddr());
87        trace!("encode giaddr");
88        encoder.encode_bytes(&self.encode_giaddr());
89        trace!("encode chaddr");
90        encoder.encode_bytes(&self.encode_chaddr());
91        trace!("encode sname");
92        encoder.encode_bytes(&self.encode_sname());
93        trace!("encode file");
94        encoder.encode_bytes(&self.encode_file());
95        trace!("encode magic");
96        encoder.encode_bytes(&self.encode_magic());
97        trace!("encode options");
98        encoder.encode_bytes(self.encode_options().as_slice());
99
100        // Automatically add the "End" option.
101        encoder.encode_byte(255);
102
103        encoder.output
104    }
105}
106
107/// Keeps track of the state of the output and provides methods to add data to the output.
108#[derive(Debug)]
109pub struct Encoder {
110    // This Vec starts empty and bytes are pushed as values are encoded.
111    output: Vec<u8>,
112}
113
114// Helpers for serializing in encode methods
115impl Encoder {
116    #[inline]
117    fn encode_bytes(&mut self, v: &[u8]) {
118        trace!("encode_bytes");
119        self.output.extend_from_slice(v);
120    }
121
122    #[inline]
123    fn encode_byte(&mut self, v: u8) {
124        trace!("encode_byte");
125        self.output.push(v);
126    }
127}
128
129// ---------------------------
130
131#[cfg(test)]
132mod tests {
133    use std::net::Ipv4Addr;
134
135    use super::*;
136    use crate::v4::*;
137
138    #[test]
139    fn test_to_bytes() {
140        init_logger(true);
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            ].into(),
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(), expected);
178    }
179}