tokio_coap/message/
mod.rs

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, // TODO: use
24}
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            // Note: length errors for 13 & 14 will be caught in the check below.
251            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        // estimate packet size
319        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}