toe_beans/v4/message/options/
mod.rs1mod address;
2mod address_list;
3mod file;
4mod max_message;
5mod mtypes;
6mod opaque;
7mod overload_options;
8mod sname;
9mod string;
10mod time;
11mod time_offset;
12
13pub use self::address::*;
14pub use self::address_list::*;
15pub use self::file::*;
16pub use self::max_message::*;
17pub use self::mtypes::*;
18pub use self::opaque::*;
19pub use self::overload_options::*;
20pub use self::sname::*;
21pub use self::string::*;
22pub use self::time::*;
23pub use self::time_offset::*;
24
25use super::super::Slicer;
26use log::{trace, warn};
27use serde::{Deserialize, Serialize};
28
29pub const MAGIC_SIZE: usize = 4;
31pub const NON_MAGIC_SIZE: usize = 308; pub const MIN_OPTIONS_SIZE: usize = MAGIC_SIZE + NON_MAGIC_SIZE;
37
38pub type MagicBuffer = [u8; MAGIC_SIZE];
40
41pub const MAGIC: MagicBuffer = [99, 130, 83, 99];
43
44pub type OptionsBuffer = [u8; NON_MAGIC_SIZE];
46
47#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
52pub enum MessageOptions {
53 Pad,
55 Netmask(AddressOption),
57 TimeOffset(TimeOffset),
59 Router(AddressListOption),
61 DnsServer(AddressListOption),
63 HostName(StringOption),
66 DomainName(StringOption),
68 Broadcast(AddressOption),
70 RequestedIp(AddressOption),
74 LeaseTime(TimeOption),
80 Overload(OverloadOptions),
82 MessageType(MessageTypes),
84 ServerIdentifier(AddressOption),
86 RequestedOptions(Vec<u8>),
88 Message(StringOption),
90 MaxMessage(MaxMessage),
92 T1(TimeOption),
94 T2(TimeOption),
96 VendorId(OpaqueOption),
98 ClientId(OpaqueOption),
100 SName(SNameOption),
102 FileName(FileOption),
104 RapidCommit,
117 SubnetSelect(AddressOption),
119 End,
121 Other(u8, u8, Vec<u8>),
123}
124
125impl MessageOptions {
126 pub fn to_tag(&self) -> u8 {
129 match self {
130 Self::Pad => 0,
131 Self::Netmask(_) => 1,
132 Self::TimeOffset(_) => 2,
133 Self::Router(_) => 3,
134 Self::DnsServer(_) => 6,
135 Self::HostName(_) => 12,
136 Self::DomainName(_) => 15,
137 Self::Broadcast(_) => 28,
138 Self::RequestedIp(_) => 50,
139 Self::LeaseTime(_) => 51,
140 Self::Overload(_) => 52,
141 Self::MessageType(_) => 53,
142 Self::ServerIdentifier(_) => 54,
143 Self::RequestedOptions(_) => 55,
144 Self::Message(_) => 56,
145 Self::MaxMessage(_) => 57,
146 Self::T1(_) => 58,
147 Self::T2(_) => 59,
148 Self::VendorId(_) => 60,
149 Self::ClientId(_) => 61,
150 Self::SName(_) => 66,
151 Self::FileName(_) => 67,
152 Self::RapidCommit => 80,
153 Self::SubnetSelect(_) => 118,
154 Self::End => 255,
155 Self::Other(x, _, _) => *x,
156 }
157 }
158
159 fn from_tag_value(tag: u8, value: &[u8]) -> Self {
162 match tag {
163 1 => Self::Netmask(value.into()),
164 2 => Self::TimeOffset(value.into()),
165 3 => Self::Router(value.into()),
166 6 => Self::DnsServer(value.into()),
167 12 => Self::HostName(value.into()),
168 15 => Self::DomainName(value.into()),
169 28 => Self::Broadcast(value.into()),
170 50 => Self::RequestedIp(value.into()),
171 51 => Self::LeaseTime(value.into()),
172 52 => Self::Overload(value.into()),
173 53 => Self::MessageType(MessageTypes::from(value)),
174 54 => Self::ServerIdentifier(value.into()),
175 55 => Self::RequestedOptions(value.into()),
176 56 => Self::Message(value.into()),
177 57 => Self::MaxMessage(value.into()),
178 58 => Self::T1(value.into()),
179 59 => Self::T2(value.into()),
180 60 => Self::VendorId(value.into()),
181 61 => Self::ClientId(value.into()),
182 66 => Self::SName(value.into()),
183 67 => Self::FileName(value.into()),
184 118 => Self::SubnetSelect(value.into()),
185 _ => Self::Other(tag, value.len() as u8, value.into()),
186 }
187 }
188
189 #[inline]
191 pub fn extend_into(&self, bytes: &mut Vec<u8>) {
192 match self {
193 Self::Pad => bytes.push(0),
194 Self::End => {
195 warn!("The End option is automatically handled during encode/decode. Don't use it.")
196 }
197 Self::RapidCommit => bytes.push(80),
198 Self::LeaseTime(x) => x.extend_into(bytes, 51),
199 Self::T1(x) => x.extend_into(bytes, 58),
200 Self::T2(x) => x.extend_into(bytes, 59),
201 Self::RequestedIp(x) => x.extend_into(bytes, 50),
202 Self::ServerIdentifier(x) => x.extend_into(bytes, 54),
203 Self::MessageType(x) => x.extend_into(bytes, 53),
204 Self::Netmask(x) => x.extend_into(bytes, 1),
205 Self::Broadcast(x) => x.extend_into(bytes, 28),
206 Self::Overload(x) => x.extend_into(bytes, 52),
207 Self::SName(x) => x.extend_into(bytes, 66),
208 Self::FileName(x) => x.extend_into(bytes, 67),
209 Self::Router(x) => x.extend_into(bytes, 3),
210 Self::DnsServer(x) => x.extend_into(bytes, 6),
211 Self::MaxMessage(x) => x.extend_into(bytes, 57),
212 Self::HostName(x) => x.extend_into(bytes, 12),
213 Self::DomainName(x) => x.extend_into(bytes, 15),
214 Self::Message(x) => x.extend_into(bytes, 56),
215 Self::SubnetSelect(x) => x.extend_into(bytes, 118),
216 Self::VendorId(x) => x.extend_into(bytes, 60),
217 Self::ClientId(x) => x.extend_into(bytes, 61),
218 Self::TimeOffset(x) => x.extend_into(bytes, 2),
219
220 Self::RequestedOptions(v) => {
221 bytes.push(55);
222 bytes.push(v.len() as u8);
223 bytes.extend(v.iter());
224 }
225
226 Self::Other(t, l, v) => {
227 bytes.push(*t);
228 bytes.push(*l);
229 bytes.extend(v);
230 }
231 };
232 }
233}
234
235#[derive(Debug, PartialEq)]
237pub struct MessageOptionsList(Vec<MessageOptions>);
238
239impl MessageOptionsList {
240 #[inline]
242 pub fn find_option(&self, tag: u8) -> Option<&MessageOptions> {
243 self.0.iter().find(|&option| option.to_tag() == tag)
244 }
245
246 #[inline]
248 pub fn add_option(&mut self, option: MessageOptions) {
249 self.0.push(option);
250 }
251
252 #[deprecated]
255 pub fn get(&self, index: usize) -> Option<&MessageOptions> {
256 self.0.get(index)
257 }
258
259 #[deprecated]
262 pub fn set(&mut self, index: usize, option: MessageOptions) {
263 self.0[index] = option;
264 }
265
266 #[inline]
268 pub fn from_bytes(bytes: &[u8]) -> Self {
269 let mut slicer = Slicer::new(bytes);
270 let mut options: Vec<MessageOptions> = Vec::with_capacity(NON_MAGIC_SIZE);
271
272 while let Some(tag) = slicer.slice(1) {
274 trace!("parsing option {:?}", tag);
275 match tag[0] {
276 0 => {} 80 => {
278 options.push(MessageOptions::RapidCommit);
279 }
280 255 => {
281 break; }
284 tag_with_length => {
285 match slicer.slice(1) {
287 Some(length) => match slicer.slice(length[0] as usize) {
288 Some(value) => {
289 options.push(MessageOptions::from_tag_value(tag_with_length, value))
290 }
291 None => break, },
293 None => break, }
295 }
296 }
297 }
298
299 Self(options)
300 }
301}
302
303impl From<Vec<MessageOptions>> for MessageOptionsList {
304 fn from(options: Vec<MessageOptions>) -> Self {
305 Self(options)
306 }
307}
308
309impl From<&MessageOptionsList> for Vec<u8> {
310 #[inline]
311 fn from(list: &MessageOptionsList) -> Self {
312 let mut encoded = Vec::with_capacity(MIN_OPTIONS_SIZE);
313
314 list.0
315 .iter()
316 .for_each(|option| option.extend_into(&mut encoded));
317
318 encoded
319 }
320}