1pub mod option;
2
3use self::option::Options;
4
5use smallvec::SmallVec;
6
7#[derive(PartialEq, Eq, Debug)]
8pub struct Message {
9 pub version: u8,
10 pub mtype: Mtype,
11 pub code: Code,
12 pub mid: u16,
13 pub token: SmallVec<[u8; 8]>,
14 pub options: Options,
15 pub payload: Vec<u8>,
16}
17
18#[derive(PartialEq, Debug)]
19pub enum Error {
20 MessageFormat,
21 InvalidToken,
22 InvalidOptionNumber,
23 UnrecognizedCriticalOption, }
25
26#[derive(PartialEq, Eq, Debug)]
27#[repr(u8)]
28pub enum Mtype {
29 Confirmable,
30 NonConfirmable,
31 Acknowledgement,
32 Reset,
33}
34
35impl Mtype {
36 pub fn from_u8(raw_mtype: u8) -> Mtype {
37 match raw_mtype & 0x03 {
38 0 => Mtype::Confirmable,
39 1 => Mtype::NonConfirmable,
40 2 => Mtype::Acknowledgement,
41 3 => Mtype::Reset,
42 _ => unreachable!(),
43 }
44 }
45
46 pub fn as_u8(&self) -> u8 {
47 match *self {
48 Mtype::Confirmable => 0,
49 Mtype::NonConfirmable => 1,
50 Mtype::Acknowledgement => 2,
51 Mtype::Reset => 3,
52 }
53 }
54}
55
56#[derive(PartialEq, Eq, Debug)]
57pub enum Code {
58 Empty,
59 Get,
60 Post,
61 Put,
62 Delete,
63 Created,
64 Deleted,
65 Valid,
66 Changed,
67 Content,
68 BadRequest,
69 Unauthorized,
70 BadOption,
71 Forbidden,
72 NotFound,
73 MethodNotAllowed,
74 NotAcceptable,
75 PreconditionFailed,
76 RequestEntityTooLarge,
77 UnsupportedContentFormat,
78 InternalServerError,
79 NotImplemented,
80 BadGateway,
81 ServiceUnavailable,
82 GatewayTimeout,
83 ProxyingNotSupported,
84 Unknown(u8),
85}
86
87impl Code {
88 pub fn from_u8(raw_code: u8) -> Code {
89 match raw_code {
90 0 => Code::Empty,
91 1 => Code::Get,
92 2 => Code::Post,
93 3 => Code::Put,
94 4 => Code::Delete,
95 65 => Code::Created,
96 66 => Code::Deleted,
97 67 => Code::Valid,
98 68 => Code::Changed,
99 69 => Code::Content,
100 128 => Code::BadRequest,
101 129 => Code::Unauthorized,
102 130 => Code::BadOption,
103 131 => Code::Forbidden,
104 132 => Code::NotFound,
105 133 => Code::MethodNotAllowed,
106 134 => Code::NotAcceptable,
107 140 => Code::PreconditionFailed,
108 141 => Code::RequestEntityTooLarge,
109 142 => Code::UnsupportedContentFormat,
110 160 => Code::InternalServerError,
111 161 => Code::NotImplemented,
112 162 => Code::BadGateway,
113 163 => Code::ServiceUnavailable,
114 164 => Code::GatewayTimeout,
115 165 => Code::ProxyingNotSupported,
116 _ => Code::Unknown(raw_code),
117 }
118 }
119
120 pub fn as_u8(&self) -> u8 {
121 match *self {
122 Code::Empty => Self::build(0, 00),
123 Code::Get => Self::build(0, 01),
124 Code::Post => Self::build(0, 02),
125 Code::Put => Self::build(0, 03),
126 Code::Delete => Self::build(0, 04),
127 Code::Created => Self::build(2, 01),
128 Code::Deleted => Self::build(2, 02),
129 Code::Valid => Self::build(2, 03),
130 Code::Changed => Self::build(2, 04),
131 Code::Content => Self::build(2, 05),
132 Code::BadRequest => Self::build(4, 00),
133 Code::Unauthorized => Self::build(4, 01),
134 Code::BadOption => Self::build(4, 02),
135 Code::Forbidden => Self::build(4, 03),
136 Code::NotFound => Self::build(4, 04),
137 Code::MethodNotAllowed => Self::build(4, 05),
138 Code::NotAcceptable => Self::build(4, 06),
139 Code::PreconditionFailed => Self::build(4, 12),
140 Code::RequestEntityTooLarge => Self::build(4, 13),
141 Code::UnsupportedContentFormat => Self::build(4, 15),
142 Code::InternalServerError => Self::build(5, 00),
143 Code::NotImplemented => Self::build(5, 01),
144 Code::BadGateway => Self::build(5, 02),
145 Code::ServiceUnavailable => Self::build(5, 03),
146 Code::GatewayTimeout => Self::build(5, 04),
147 Code::ProxyingNotSupported => Self::build(5, 05),
148 Code::Unknown(code) => code,
149 }
150 }
151
152 #[inline(always)]
153 fn build(class: u8, detail: u8) -> u8 {
154 ((class & 0x07) << 5) | (detail & 0x1F)
155 }
156
157 pub fn class(&self) -> u8 {
158 self.as_u8() >> 5
159 }
160
161 pub fn detail(&self) -> u8 {
162 self.as_u8() & 0x1F
163 }
164}
165
166impl Message {
167 pub fn new() -> Self {
168 Message {
169 version: 1,
170 mtype: Mtype::Confirmable,
171 code: Code::Get,
172 mid: 0,
173 token: SmallVec::new(),
174 options: Options::new(),
175 payload: Vec::new(),
176
177 }
178 }
179
180 pub fn new_reply(&self) -> Self {
181 Self::new().with_token(&self.token)
182 .with_mid(self.mid)
183 .with_mtype(Mtype::Acknowledgement)
184 }
185
186 pub fn with_mtype(mut self, mtype: Mtype) -> Self {
187 self.mtype = mtype;
188 self
189 }
190
191 pub fn with_code(mut self, code: Code) -> Self {
192 self.code = code;
193 self
194 }
195
196 pub fn with_mid(mut self, mid: u16) -> Self {
197 self.mid = mid;
198 self
199 }
200
201 pub fn with_token(mut self, token: &[u8]) -> Self {
202 self.token.truncate(0);
203 self.token.extend_from_slice(token);
204 self
205 }
206
207 pub fn with_option<T: option::Option + option::Byteable>(mut self, option: T) -> Self {
208 self.options.map
209 .entry(option.number())
210 .or_insert_with(|| Vec::new())
211 .push(option.to_bytes().into_owned());
212 self
213 }
214
215 pub fn with_payload(mut self, payload: Vec<u8>) -> Self {
216 self.payload = payload;
217 self
218 }
219
220 pub fn from_bytes(pkt: &[u8]) -> Result<Message, Error> {
221 let mut i: usize;
222
223 if pkt.len() < 4 {
224 return Err(Error::MessageFormat);
225 }
226
227 let version = pkt[0] >> 6;
228 let mtype = Mtype::from_u8((pkt[0] >> 4) & 0x03);
229 let token_length = pkt[0] & 0x0F;
230 let code = Code::from_u8(pkt[1]);
231 let mid = ((pkt[2] as u16) << 8) | pkt[3] as u16;
232
233 if pkt.len() < 4 + token_length as usize {
234 return Err(Error::MessageFormat);
235 }
236
237 let token = pkt[4..4+token_length as usize].into();
238
239 i = 4 + token_length as usize;
240
241 let mut options = option::Options::new();
242 let mut option_number_offset = 0u16;
243
244 while i < pkt.len() {
245 if pkt[i] == 0xFF {
246 i += 1;
247 break;
248 }
249
250 let delta = match pkt[i] >> 4 {
252 d @ 0...12 => d as u16,
253 13 => {
254 i += 1;
255 pkt[i] as u16 + 13
256 }
257 14 => {
258 i += 2;
259 (((pkt[i - 1] as u16) << 8) | pkt[i] as u16) + 269
260 }
261 15 => return Err(Error::MessageFormat),
262 _ => unreachable!(),
263 };
264 let length = match pkt[i] & 0x0F {
265 d @ 0...12 => d as u16,
266 13 => {
267 i += 1;
268 pkt[i] as u16 + 13
269 }
270 14 => {
271 i += 2;
272 ((pkt[i - 1] as u16) << 8) | pkt[i] as u16 + 269
273 }
274 15 => return Err(Error::MessageFormat),
275 _ => unreachable!(),
276 };
277
278 i += 1;
279
280 let option_number = option_number_offset + delta;
281 option_number_offset = option_number;
282
283 if length >= 65000 {
284 return Err(Error::MessageFormat);
285 }
286
287 if pkt.len() >= i + (length as usize) {
288 options.push_raw(option_number, pkt[i..i+(length as usize)].into());
289 } else {
290 return Err(Error::MessageFormat);
291 }
292
293 i += length as usize;
294 }
295
296 let payload = if i < pkt.len() {
297 pkt[i..].to_vec()
298 } else {
299 vec![]
300 };
301
302 Ok(Message {
303 version: version,
304 mtype: mtype,
305 code: code,
306 mid: mid,
307 token: token,
308 options: options,
309 payload: payload,
310 })
311 }
312
313 pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
314 if self.token.len() > 8 {
315 return Err(Error::MessageFormat);
316 }
317
318 let mut est_pkt_size: usize = 4 + self.token.len() + 1 + 1 + self.payload.len();
320
321 for (number, bytes) in self.options.iter() {
322 est_pkt_size += 2 + bytes.len() as usize;
323
324 if number >= 65000 {
325 return Err(Error::MessageFormat);
326 }
327 }
328
329 let mut pkt = Vec::with_capacity(est_pkt_size);
330
331 pkt.push((self.version << 6) | self.mtype.as_u8() << 4 | self.token.len() as u8);
332 pkt.push(self.code.as_u8());
333 pkt.push((self.mid >> 8) as u8);
334 pkt.push((self.mid & 0xFF) as u8);
335
336 for byte in &self.token {
337 pkt.push(*byte)
338 }
339
340 let mut last_option_number = 0;
341
342 for (number, bytes) in self.options.iter() {
343 pkt.extend(option::build_header(number, bytes, &mut last_option_number).iter());
344 pkt.extend(bytes);
345 }
346
347 if self.payload.len() > 0 {
348 pkt.push(0xFF);
349 pkt.extend(&self.payload);
350 }
351
352 Ok(pkt)
353 }
354}
355
356
357#[test]
358fn test_msg_parse_empty() {
359 let ref_bin = [64, 0, 0, 0];
360
361 let msg = Message::from_bytes(&ref_bin).unwrap();
362
363 assert!(msg.version == 1);
364 assert!(msg.mtype == Mtype::Confirmable);
365 assert!(msg.code == Code::Empty);
366 assert!(msg.code.class() == 0);
367 assert!(msg.code.detail() == 0);
368 assert!(msg.mid == 0);
369 assert!(msg.token.len() == 0);
370 assert!(msg.options == option::Options::new());
371 assert!(msg.payload.len() == 0);
372}
373
374#[test]
375fn test_msg_serialize_empty() {
376 let ref_bin = [64, 0, 0, 0];
377 let msg = Message {
378 version: 1,
379 mtype: Mtype::Confirmable,
380 code: Code::Empty,
381 mid: 0,
382 token: SmallVec::new(),
383 options: option::Options::new(),
384 payload: vec![],
385 };
386
387 let test_bin = msg.to_bytes().unwrap();
388
389 assert!(test_bin == ref_bin);
390}
391
392#[test]
393fn test_msg_parse_empty_con_with_token() {
394 let ref_bin = [66, 0, 0, 0, 37, 42];
395
396 let msg = Message::from_bytes(&ref_bin).unwrap();
397
398 assert!(msg.version == 1);
399 assert!(msg.mtype == Mtype::Confirmable);
400 assert!(msg.code == Code::Empty);
401 assert!(msg.code.class() == 0);
402 assert!(msg.code.detail() == 0);
403 assert!(msg.mid == 0);
404 assert!(msg.token == [37, 42].into());
405 assert!(msg.options == option::Options::new());
406 assert!(msg.payload.len() == 0);
407}
408
409#[test]
410fn test_msg_parse_get_con() {
411 let ref_bin = [0x41, 0x01, 0x00, 0x37, 0x99, 0xFF, 0x01, 0x02];
412
413 let msg = Message::from_bytes(&ref_bin).unwrap();
414
415 assert!(msg.version == 1);
416 assert!(msg.mtype == Mtype::Confirmable);
417 assert!(msg.code == Code::Get);
418 assert!(msg.code.class() == 0);
419 assert!(msg.code.detail() == 1);
420 assert!(msg.mid == 0x37);
421 assert!(msg.token == [0x99].into());
422 assert!(msg.options == option::Options::new());
423 assert!(msg.payload == [0x01, 0x02]);
424}
425
426#[test]
427fn test_msg_parse_get_con_with_opts() {
428 use self::option::{Option, Options, UriPath, UriQuery};
429
430 let ref_bin = [0x40, 0x02, 0x00, 0x37, 0xb2, 0x31, 0x61, 0x04, 0x74, 0x65, 0x6d, 0x70, 0x4d,
431 0x1b, 0x61, 0x33, 0x32, 0x63, 0x38, 0x35, 0x62, 0x61, 0x39, 0x64, 0x64, 0x61,
432 0x34, 0x35, 0x38, 0x32, 0x33, 0x62, 0x65, 0x34, 0x31, 0x36, 0x32, 0x34, 0x36,
433 0x63, 0x66, 0x38, 0x62, 0x34, 0x33, 0x33, 0x62, 0x61, 0x61, 0x30, 0x36, 0x38,
434 0x64, 0x37, 0xFF, 0x39, 0x39];
435
436 let mut opts = Options::new();
437 opts.push(UriPath::new("1a".to_owned()));
438 opts.push(UriPath::new("temp".to_owned()));
439 opts.push(UriQuery::new("a32c85ba9dda45823be416246cf8b433baa068d7".to_owned()));
440
441 let msg = Message::from_bytes(&ref_bin).unwrap();
442
443 assert!(msg.version == 1);
444 assert!(msg.mtype == Mtype::Confirmable);
445 assert!(msg.code == Code::Post);
446 assert!(msg.code.class() == 0);
447 assert!(msg.code.detail() == 2);
448 assert!(msg.mid == 0x0037);
449 assert!(msg.token.len() == 0);
450 assert!(msg.options == opts);
451 assert!(msg.payload == [0x39, 0x39]);
452}
453
454#[test]
455fn test_msg_encode_get_con_with_opts() {
456 use self::option::{Option, Options, UriPath, UriQuery};
457
458 let ref_bin = [0x40, 0x02, 0x00, 0x37, 0xb2, 0x31, 0x61, 0x04, 0x74, 0x65, 0x6d, 0x70, 0x4d,
459 0x1b, 0x61, 0x33, 0x32, 0x63, 0x38, 0x35, 0x62, 0x61, 0x39, 0x64, 0x64, 0x61,
460 0x34, 0x35, 0x38, 0x32, 0x33, 0x62, 0x65, 0x34, 0x31, 0x36, 0x32, 0x34, 0x36,
461 0x63, 0x66, 0x38, 0x62, 0x34, 0x33, 0x33, 0x62, 0x61, 0x61, 0x30, 0x36, 0x38,
462 0x64, 0x37, 0xFF, 0x39, 0x39];
463
464 let mut opts = Options::new();
465 opts.push(UriPath::new("1a".to_owned()));
466 opts.push(UriPath::new("temp".to_owned()));
467 opts.push(UriQuery::new("a32c85ba9dda45823be416246cf8b433baa068d7".to_owned()));
468
469 let msg = Message {
470 version: 1,
471 mtype: Mtype::Confirmable,
472 code: Code::Post,
473 mid: 0x0037,
474 token: SmallVec::new(),
475 options: opts,
476 payload: vec![0x39, 0x39],
477 };
478
479 let test_bin = msg.to_bytes().unwrap();
480
481 assert!(test_bin.len() == ref_bin.len());
482
483 for i in 0..ref_bin.len() {
484 assert_eq!(test_bin[i], ref_bin[i]);
485 }
486}