1use alloc::{
2 collections::{BTreeMap, LinkedList},
3 vec::Vec,
4};
5use core::convert::TryFrom;
6
7use crate::{
8 error::{
9 IncompatibleOptionValueFormat, InvalidContentFormat, InvalidObserve,
10 MessageError,
11 },
12 header::{Header, HeaderRaw, MessageClass},
13 option_value::{OptionValueType, OptionValueU16, OptionValueU32},
14};
15
16macro_rules! u8_to_unsigned_be {
17 ($src:ident, $start:expr, $end:expr, $t:ty) => ({
18 (0..=$end - $start).rev().fold(
19 0, |acc, i| acc | $src[$start+i] as $t << i * 8
20 )
21 })
22}
23
24#[derive(Debug, Clone, Copy, PartialEq)]
26pub enum CoapOption {
27 IfMatch,
28 UriHost,
29 ETag,
30 IfNoneMatch,
31 Observe,
32 UriPort,
33 LocationPath,
34 Oscore,
35 UriPath,
36 ContentFormat,
37 MaxAge,
38 UriQuery,
39 Accept,
40 LocationQuery,
41 Block2,
42 Block1,
43 ProxyUri,
44 ProxyScheme,
45 Size1,
46 Size2,
47 NoResponse,
48 Unknown(u16),
49}
50
51impl From<u16> for CoapOption {
52 fn from(number: u16) -> CoapOption {
53 match number {
54 1 => CoapOption::IfMatch,
55 3 => CoapOption::UriHost,
56 4 => CoapOption::ETag,
57 5 => CoapOption::IfNoneMatch,
58 6 => CoapOption::Observe,
59 7 => CoapOption::UriPort,
60 8 => CoapOption::LocationPath,
61 9 => CoapOption::Oscore,
62 11 => CoapOption::UriPath,
63 12 => CoapOption::ContentFormat,
64 14 => CoapOption::MaxAge,
65 15 => CoapOption::UriQuery,
66 17 => CoapOption::Accept,
67 20 => CoapOption::LocationQuery,
68 23 => CoapOption::Block2,
69 27 => CoapOption::Block1,
70 35 => CoapOption::ProxyUri,
71 39 => CoapOption::ProxyScheme,
72 60 => CoapOption::Size1,
73 28 => CoapOption::Size2,
74 258 => CoapOption::NoResponse,
75 _ => CoapOption::Unknown(number),
76 }
77 }
78}
79
80impl From<CoapOption> for u16 {
81 fn from(option: CoapOption) -> u16 {
82 match option {
83 CoapOption::IfMatch => 1,
84 CoapOption::UriHost => 3,
85 CoapOption::ETag => 4,
86 CoapOption::IfNoneMatch => 5,
87 CoapOption::Observe => 6,
88 CoapOption::UriPort => 7,
89 CoapOption::LocationPath => 8,
90 CoapOption::Oscore => 9,
91 CoapOption::UriPath => 11,
92 CoapOption::ContentFormat => 12,
93 CoapOption::MaxAge => 14,
94 CoapOption::UriQuery => 15,
95 CoapOption::Accept => 17,
96 CoapOption::LocationQuery => 20,
97 CoapOption::Block2 => 23,
98 CoapOption::Block1 => 27,
99 CoapOption::ProxyUri => 35,
100 CoapOption::ProxyScheme => 39,
101 CoapOption::Size1 => 60,
102 CoapOption::Size2 => 28,
103 CoapOption::NoResponse => 258,
104 CoapOption::Unknown(number) => number,
105 }
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq)]
111#[non_exhaustive]
112pub enum ContentFormat {
113 TextPlain,
114 ApplicationCoseEncrypt0,
116 ApplicationCoseMac0,
118 ApplicationCoseSign1,
120 ApplicationAceCbor,
121 ImageGif,
122 ImageJpeg,
123 ImagePng,
124 ApplicationLinkFormat,
125 ApplicationXML,
126 ApplicationOctetStream,
127 ApplicationEXI,
128 ApplicationJSON,
129 ApplicationJsonPatchJson,
130 ApplicationMergePatchJson,
131 ApplicationCBOR,
132 ApplicationCWt,
133 ApplicationMultipartCore,
134 ApplicationCborSeq,
135 ApplicationCoseEncrypt,
137 ApplicationCoseMac,
139 ApplicationCoseSign,
141 ApplicationCoseKey,
142 ApplicationCoseKeySet,
143 ApplicationSenmlJSON,
144 ApplicationSensmlJSON,
145 ApplicationSenmlCBOR,
146 ApplicationSensmlCBOR,
147 ApplicationSenmlExi,
148 ApplicationSensmlExi,
149 ApplicationYangDataCborSid,
151 ApplicationCoapGroupJson,
152 ApplicationDotsCbor,
153 ApplicationMissingBlocksCborSeq,
154 ApplicationPkcs7MimeServerGeneratedKey,
156 ApplicationPkcs7MimeCertsOnly,
158 ApplicationPkcs8,
159 ApplicationCsrattrs,
160 ApplicationPkcs10,
161 ApplicationPkixCert,
162 ApplicationAifCbor,
163 ApplicationAifJson,
164 ApplicationSenmlXML,
165 ApplicationSensmlXML,
166 ApplicationSenmlEtchJson,
167 ApplicationSenmlEtchCbor,
168 ApplicationYangDataCbor,
169 ApplicationYangDataCborName,
171 ApplicationTdJson,
172 ApplicationVoucherCoseCbor,
173 ApplicationVndOcfCbor,
174 ApplicationOscore,
175 ApplicationJavascript,
176 ApplicationJsonDeflate,
177 ApplicationCborDeflate,
178 ApplicationVndOmaLwm2mTlv,
179 ApplicationVndOmaLwm2mJson,
180 ApplicationVndOmaLwm2mCbor,
181 TextCss,
182 ImageSvgXml,
183}
184
185impl TryFrom<usize> for ContentFormat {
186 type Error = InvalidContentFormat;
187
188 fn try_from(number: usize) -> Result<ContentFormat, InvalidContentFormat> {
189 match number {
190 0 => Ok(ContentFormat::TextPlain),
191 16 => Ok(ContentFormat::ApplicationCoseEncrypt0),
192 17 => Ok(ContentFormat::ApplicationCoseMac0),
193 18 => Ok(ContentFormat::ApplicationCoseSign1),
194 19 => Ok(ContentFormat::ApplicationAceCbor),
195 21 => Ok(ContentFormat::ImageGif),
196 22 => Ok(ContentFormat::ImageJpeg),
197 23 => Ok(ContentFormat::ImagePng),
198 40 => Ok(ContentFormat::ApplicationLinkFormat),
199 41 => Ok(ContentFormat::ApplicationXML),
200 42 => Ok(ContentFormat::ApplicationOctetStream),
201 47 => Ok(ContentFormat::ApplicationEXI),
202 50 => Ok(ContentFormat::ApplicationJSON),
203 51 => Ok(ContentFormat::ApplicationJsonPatchJson),
204 52 => Ok(ContentFormat::ApplicationMergePatchJson),
205 60 => Ok(ContentFormat::ApplicationCBOR),
206 61 => Ok(ContentFormat::ApplicationCWt),
207 62 => Ok(ContentFormat::ApplicationMultipartCore),
208 63 => Ok(ContentFormat::ApplicationCborSeq),
209 96 => Ok(ContentFormat::ApplicationCoseEncrypt),
210 97 => Ok(ContentFormat::ApplicationCoseMac),
211 98 => Ok(ContentFormat::ApplicationCoseSign),
212 101 => Ok(ContentFormat::ApplicationCoseKey),
213 102 => Ok(ContentFormat::ApplicationCoseKeySet),
214 110 => Ok(ContentFormat::ApplicationSenmlJSON),
215 111 => Ok(ContentFormat::ApplicationSensmlJSON),
216 112 => Ok(ContentFormat::ApplicationSenmlCBOR),
217 113 => Ok(ContentFormat::ApplicationSensmlCBOR),
218 114 => Ok(ContentFormat::ApplicationSenmlExi),
219 115 => Ok(ContentFormat::ApplicationSensmlExi),
220 140 => Ok(ContentFormat::ApplicationYangDataCborSid),
221 256 => Ok(ContentFormat::ApplicationCoapGroupJson),
222 271 => Ok(ContentFormat::ApplicationDotsCbor),
223 272 => Ok(ContentFormat::ApplicationMissingBlocksCborSeq),
224 280 => Ok(ContentFormat::ApplicationPkcs7MimeServerGeneratedKey),
225 281 => Ok(ContentFormat::ApplicationPkcs7MimeCertsOnly),
226 284 => Ok(ContentFormat::ApplicationPkcs8),
227 285 => Ok(ContentFormat::ApplicationCsrattrs),
228 286 => Ok(ContentFormat::ApplicationPkcs10),
229 287 => Ok(ContentFormat::ApplicationPkixCert),
230 290 => Ok(ContentFormat::ApplicationAifCbor),
231 291 => Ok(ContentFormat::ApplicationAifJson),
232 310 => Ok(ContentFormat::ApplicationSenmlXML),
233 311 => Ok(ContentFormat::ApplicationSensmlXML),
234 320 => Ok(ContentFormat::ApplicationSenmlEtchJson),
235 322 => Ok(ContentFormat::ApplicationSenmlEtchCbor),
236 340 => Ok(ContentFormat::ApplicationYangDataCbor),
237 341 => Ok(ContentFormat::ApplicationYangDataCborName),
238 432 => Ok(ContentFormat::ApplicationTdJson),
239 836 => Ok(ContentFormat::ApplicationVoucherCoseCbor),
240 10000 => Ok(ContentFormat::ApplicationVndOcfCbor),
241 10001 => Ok(ContentFormat::ApplicationOscore),
242 10002 => Ok(ContentFormat::ApplicationJavascript),
243 11050 => Ok(ContentFormat::ApplicationJsonDeflate),
244 11060 => Ok(ContentFormat::ApplicationCborDeflate),
245 11542 => Ok(ContentFormat::ApplicationVndOmaLwm2mTlv),
246 11543 => Ok(ContentFormat::ApplicationVndOmaLwm2mJson),
247 11544 => Ok(ContentFormat::ApplicationVndOmaLwm2mCbor),
248 20000 => Ok(ContentFormat::TextCss),
249 30000 => Ok(ContentFormat::ImageSvgXml),
250 _ => Err(InvalidContentFormat),
251 }
252 }
253}
254
255impl From<ContentFormat> for usize {
256 fn from(format: ContentFormat) -> usize {
257 match format {
258 ContentFormat::TextPlain => 0,
259 ContentFormat::ApplicationCoseEncrypt0 => 16,
260 ContentFormat::ApplicationCoseMac0 => 17,
261 ContentFormat::ApplicationCoseSign1 => 18,
262 ContentFormat::ApplicationAceCbor => 19,
263 ContentFormat::ImageGif => 21,
264 ContentFormat::ImageJpeg => 22,
265 ContentFormat::ImagePng => 23,
266 ContentFormat::ApplicationLinkFormat => 40,
267 ContentFormat::ApplicationXML => 41,
268 ContentFormat::ApplicationOctetStream => 42,
269 ContentFormat::ApplicationEXI => 47,
270 ContentFormat::ApplicationJSON => 50,
271 ContentFormat::ApplicationJsonPatchJson => 51,
272 ContentFormat::ApplicationMergePatchJson => 52,
273 ContentFormat::ApplicationCBOR => 60,
274 ContentFormat::ApplicationCWt => 61,
275 ContentFormat::ApplicationMultipartCore => 62,
276 ContentFormat::ApplicationCborSeq => 63,
277 ContentFormat::ApplicationCoseEncrypt => 96,
278 ContentFormat::ApplicationCoseMac => 97,
279 ContentFormat::ApplicationCoseSign => 98,
280 ContentFormat::ApplicationCoseKey => 101,
281 ContentFormat::ApplicationCoseKeySet => 102,
282 ContentFormat::ApplicationSenmlJSON => 110,
283 ContentFormat::ApplicationSensmlJSON => 111,
284 ContentFormat::ApplicationSenmlCBOR => 112,
285 ContentFormat::ApplicationSensmlCBOR => 113,
286 ContentFormat::ApplicationSenmlExi => 114,
287 ContentFormat::ApplicationSensmlExi => 115,
288 ContentFormat::ApplicationYangDataCborSid => 140,
289 ContentFormat::ApplicationCoapGroupJson => 256,
290 ContentFormat::ApplicationDotsCbor => 271,
291 ContentFormat::ApplicationMissingBlocksCborSeq => 272,
292 ContentFormat::ApplicationPkcs7MimeServerGeneratedKey => 280,
293 ContentFormat::ApplicationPkcs7MimeCertsOnly => 281,
294 ContentFormat::ApplicationPkcs8 => 284,
295 ContentFormat::ApplicationCsrattrs => 285,
296 ContentFormat::ApplicationPkcs10 => 286,
297 ContentFormat::ApplicationPkixCert => 287,
298 ContentFormat::ApplicationAifCbor => 290,
299 ContentFormat::ApplicationAifJson => 291,
300 ContentFormat::ApplicationSenmlXML => 310,
301 ContentFormat::ApplicationSensmlXML => 311,
302 ContentFormat::ApplicationSenmlEtchJson => 320,
303 ContentFormat::ApplicationSenmlEtchCbor => 322,
304 ContentFormat::ApplicationYangDataCbor => 340,
305 ContentFormat::ApplicationYangDataCborName => 341,
306 ContentFormat::ApplicationTdJson => 432,
307 ContentFormat::ApplicationVoucherCoseCbor => 836,
308 ContentFormat::ApplicationVndOcfCbor => 10000,
309 ContentFormat::ApplicationOscore => 10001,
310 ContentFormat::ApplicationJavascript => 10002,
311 ContentFormat::ApplicationJsonDeflate => 11050,
312 ContentFormat::ApplicationCborDeflate => 11060,
313 ContentFormat::ApplicationVndOmaLwm2mTlv => 11542,
314 ContentFormat::ApplicationVndOmaLwm2mJson => 11543,
315 ContentFormat::ApplicationVndOmaLwm2mCbor => 11544,
316 ContentFormat::TextCss => 20000,
317 ContentFormat::ImageSvgXml => 30000,
318 }
319 }
320}
321
322#[derive(Debug, Clone, Copy, PartialEq)]
324pub enum ObserveOption {
325 Register,
326 Deregister,
327}
328
329impl TryFrom<usize> for ObserveOption {
330 type Error = InvalidObserve;
331
332 fn try_from(number: usize) -> Result<ObserveOption, InvalidObserve> {
333 match number {
334 0 => Ok(ObserveOption::Register),
335 1 => Ok(ObserveOption::Deregister),
336 _ => Err(InvalidObserve),
337 }
338 }
339}
340
341impl From<ObserveOption> for usize {
342 fn from(observe: ObserveOption) -> usize {
343 match observe {
344 ObserveOption::Register => 0,
345 ObserveOption::Deregister => 1,
346 }
347 }
348}
349
350#[derive(Debug, Clone, Default, PartialEq)]
352pub struct Packet {
353 pub header: Header,
354 token: Vec<u8>,
355 pub(crate) options: BTreeMap<u16, LinkedList<Vec<u8>>>,
356 pub payload: Vec<u8>,
357}
358
359pub type Options<'a> =
361 alloc::collections::btree_map::Iter<'a, u16, LinkedList<Vec<u8>>>;
362
363impl Packet {
364 #[cfg(not(feature = "udp"))]
367 pub const MAX_SIZE: usize = 1280;
368
369 #[cfg(feature = "udp")]
371 pub const MAX_SIZE: usize = 64_000;
372
373 pub fn new() -> Packet {
375 Default::default()
376 }
377
378 pub fn options(&self) -> Options {
380 self.options.iter()
381 }
382
383 pub fn set_token(&mut self, token: Vec<u8>) {
385 self.header.set_token_length(token.len() as u8);
386 self.token = token;
387 }
388
389 pub fn get_token(&self) -> &[u8] {
391 &self.token
392 }
393
394 pub fn set_option(&mut self, tp: CoapOption, value: LinkedList<Vec<u8>>) {
396 self.options.insert(tp.into(), value);
397 }
398
399 pub fn set_options_as<T: OptionValueType>(
401 &mut self,
402 tp: CoapOption,
403 value: LinkedList<T>,
404 ) {
405 let raw_value = value.into_iter().map(|x| x.into()).collect();
406 self.set_option(tp, raw_value);
407 }
408
409 pub fn get_option(&self, tp: CoapOption) -> Option<&LinkedList<Vec<u8>>> {
411 self.options.get(&tp.into())
412 }
413
414 pub fn get_options_as<T: OptionValueType>(
417 &self,
418 tp: CoapOption,
419 ) -> Option<LinkedList<Result<T, IncompatibleOptionValueFormat>>> {
420 self.get_option(tp).map(|options| {
421 options
422 .iter()
423 .map(|raw_value| T::try_from(raw_value.clone()))
424 .collect()
425 })
426 }
427
428 pub fn get_first_option(&self, tp: CoapOption) -> Option<&Vec<u8>> {
431 self.options
432 .get(&tp.into())
433 .and_then(|options| options.front())
434 }
435
436 pub fn get_first_option_as<T: OptionValueType>(
439 &self,
440 tp: CoapOption,
441 ) -> Option<Result<T, IncompatibleOptionValueFormat>> {
442 self.get_first_option(tp)
443 .map(|value| T::try_from(value.clone()))
444 }
445
446 pub fn add_option(&mut self, tp: CoapOption, value: Vec<u8>) {
448 let num = tp.into();
449 if let Some(list) = self.options.get_mut(&num) {
450 list.push_back(value);
451 return;
452 }
453
454 let mut list = LinkedList::new();
455 list.push_back(value);
456 self.options.insert(num, list);
457 }
458
459 pub fn add_option_as<T: OptionValueType>(
461 &mut self,
462 tp: CoapOption,
463 value: T,
464 ) {
465 self.add_option(tp, value.into());
466 }
467
468 pub fn clear_option(&mut self, tp: CoapOption) {
470 if let Some(list) = self.options.get_mut(&tp.into()) {
471 list.clear()
472 }
473 }
474
475 pub fn clear_all_options(&mut self) {
477 self.options.clear()
478 }
479
480 pub fn set_content_format(&mut self, cf: ContentFormat) {
482 let content_format: u16 = u16::try_from(usize::from(cf)).unwrap();
483 self.add_option_as(
484 CoapOption::ContentFormat,
485 OptionValueU16(content_format),
486 );
487 }
488
489 pub fn get_content_format(&self) -> Option<ContentFormat> {
491 self.get_first_option_as::<OptionValueU16>(CoapOption::ContentFormat)
492 .and_then(|option| option.ok())
493 .map(|value| usize::from(value.0))
494 .and_then(|value| ContentFormat::try_from(value).ok())
495 }
496
497 pub fn set_observe_value(&mut self, value: u32) {
499 self.clear_option(CoapOption::Observe);
500 self.add_option_as(CoapOption::Observe, OptionValueU32(value));
501 }
502
503 pub fn get_observe_value(
505 &self,
506 ) -> Option<Result<u32, IncompatibleOptionValueFormat>> {
507 self.get_first_option_as::<OptionValueU32>(CoapOption::Observe)
508 .map(|option| option.map(|value| value.0))
509 }
510
511 pub fn from_bytes(buf: &[u8]) -> Result<Packet, MessageError> {
513 let header_result = HeaderRaw::try_from(buf);
514 match header_result {
515 Ok(raw_header) => {
516 let header = Header::from_raw(&raw_header);
517 let token_length = header.get_token_length();
518 let options_start: usize = 4 + token_length as usize;
519
520 if token_length > 8 {
521 return Err(MessageError::InvalidTokenLength);
522 }
523
524 if options_start > buf.len() {
525 return Err(MessageError::InvalidTokenLength);
526 }
527
528 let token = buf[4..options_start].to_vec();
529
530 let mut idx = options_start;
531 let mut options_number = 0u16;
532 let mut options: BTreeMap<u16, LinkedList<Vec<u8>>> =
533 BTreeMap::new();
534 while idx < buf.len() {
535 let byte = buf[idx];
536
537 if byte == 255 || idx > buf.len() {
538 break;
539 }
540
541 let mut delta = (byte >> 4) as u16;
542 let mut length = (byte & 0xF) as usize;
543
544 idx += 1;
545
546 match delta {
548 13 => {
549 if idx >= buf.len() {
550 return Err(MessageError::InvalidOptionLength);
551 }
552 delta = buf[idx] as u16 + 13;
553 idx += 1;
554 }
555 14 => {
556 if idx + 1 >= buf.len() {
557 return Err(MessageError::InvalidOptionLength);
558 }
559
560 delta = u16::from_be(u8_to_unsigned_be!(
561 buf,
562 idx,
563 idx + 1,
564 u16
565 ))
566 .checked_add(269)
567 .ok_or(MessageError::InvalidOptionDelta)?;
568 idx += 2;
569 }
570 15 => {
571 return Err(MessageError::InvalidOptionDelta);
572 }
573 _ => {}
574 };
575
576 match length {
578 13 => {
579 if idx >= buf.len() {
580 return Err(MessageError::InvalidOptionLength);
581 }
582
583 length = buf[idx] as usize + 13;
584 idx += 1;
585 }
586 14 => {
587 if idx + 1 >= buf.len() {
588 return Err(MessageError::InvalidOptionLength);
589 }
590
591 length = (u16::from_be(u8_to_unsigned_be!(
592 buf,
593 idx,
594 idx + 1,
595 u16
596 ))
597 .checked_add(269)
598 .ok_or(MessageError::InvalidOptionLength)?)
599 .into();
600 idx += 2;
601 }
602 15 => {
603 return Err(MessageError::InvalidOptionLength);
604 }
605 _ => {}
606 };
607
608 options_number = options_number
609 .checked_add(delta)
610 .ok_or(MessageError::InvalidOptionDelta)?;
611
612 let end = idx + length;
613 if end > buf.len() {
614 return Err(MessageError::InvalidOptionLength);
615 }
616 let options_value = buf[idx..end].to_vec();
617
618 options
619 .entry(options_number)
620 .or_default()
621 .push_back(options_value);
622
623 idx += length;
624 }
625
626 let payload = if idx < buf.len() {
627 buf[(idx + 1)..buf.len()].to_vec()
628 } else {
629 Vec::new()
630 };
631
632 Ok(Packet {
633 header,
634 token,
635 options,
636 payload,
637 })
638 }
639 Err(_) => Err(MessageError::InvalidHeader),
640 }
641 }
642
643 pub fn to_bytes(&self) -> Result<Vec<u8>, MessageError> {
645 self.to_bytes_internal(Some(Self::MAX_SIZE))
646 }
647
648 pub fn to_bytes_with_limit(
651 &self,
652 limit: usize,
653 ) -> Result<Vec<u8>, MessageError> {
654 self.to_bytes_internal(Some(limit))
655 }
656
657 pub fn to_bytes_unlimited(&self) -> Result<Vec<u8>, MessageError> {
660 self.to_bytes_internal(None)
661 }
662
663 fn to_bytes_internal(
664 &self,
665 limit: Option<usize>,
666 ) -> Result<Vec<u8>, MessageError> {
667 let mut options_delta_length = 0;
668 let mut options_bytes: Vec<u8> = Vec::new();
669 for (number, value_list) in self.options.iter() {
670 for value in value_list.iter() {
671 let mut header: Vec<u8> = Vec::with_capacity(1 + 2 + 2);
672 let delta = number - options_delta_length;
673
674 let mut byte: u8 = 0;
675 if delta <= 12 {
676 byte |= (delta << 4) as u8;
677 } else if delta < 269 {
678 byte |= 13 << 4;
679 } else {
680 byte |= 14 << 4;
681 }
682 if value.len() <= 12 {
683 byte |= value.len() as u8;
684 } else if value.len() < 269 {
685 byte |= 13;
686 } else {
687 byte |= 14;
688 }
689 header.push(byte);
690
691 if delta > 12 && delta < 269 {
692 header.push((delta - 13) as u8);
693 } else if delta >= 269 {
694 let fix = delta - 269;
695 header.push((fix >> 8) as u8);
696 header.push((fix & 0xFF) as u8);
697 }
698
699 if value.len() > 12 && value.len() < 269 {
700 header.push((value.len() - 13) as u8);
701 } else if value.len() >= 269 {
702 let fix = (value.len() - 269) as u16;
703 header.push((fix >> 8) as u8);
704 header.push((fix & 0xFF) as u8);
705 }
706
707 options_delta_length += delta;
708
709 options_bytes.reserve(header.len() + value.len());
710 unsafe {
711 use core::ptr;
712 let buf_len = options_bytes.len();
713 ptr::copy(
714 header.as_ptr(),
715 options_bytes.as_mut_ptr().add(buf_len),
716 header.len(),
717 );
718 ptr::copy(
719 value.as_ptr(),
720 options_bytes.as_mut_ptr().add(buf_len + header.len()),
721 value.len(),
722 );
723 options_bytes
724 .set_len(buf_len + header.len() + value.len());
725 }
726 }
727 }
728
729 let mut buf_length = 4 + self.payload.len() + self.token.len();
730 if self.header.code != MessageClass::Empty && !self.payload.is_empty()
731 {
732 buf_length += 1;
733 }
734 buf_length += options_bytes.len();
735
736 if limit.is_some() && buf_length > limit.unwrap() {
737 return Err(MessageError::InvalidPacketLength);
738 }
739
740 let mut buf: Vec<u8> = Vec::with_capacity(buf_length);
741 let header_result = self.header.to_raw().serialize_into(&mut buf);
742
743 match header_result {
744 Ok(_) => {
745 buf.reserve(self.token.len() + options_bytes.len());
746 unsafe {
747 use core::ptr;
748 let buf_len = buf.len();
749 ptr::copy(
750 self.token.as_ptr(),
751 buf.as_mut_ptr().add(buf_len),
752 self.token.len(),
753 );
754 ptr::copy(
755 options_bytes.as_ptr(),
756 buf.as_mut_ptr().add(buf_len + self.token.len()),
757 options_bytes.len(),
758 );
759 buf.set_len(
760 buf_len + self.token.len() + options_bytes.len(),
761 );
762 }
763
764 if self.header.code != MessageClass::Empty
765 && !self.payload.is_empty()
766 {
767 buf.push(0xFF);
768 buf.reserve(self.payload.len());
769 unsafe {
770 use core::ptr;
771 let buf_len = buf.len();
772 ptr::copy(
773 self.payload.as_ptr(),
774 buf.as_mut_ptr().add(buf.len()),
775 self.payload.len(),
776 );
777 buf.set_len(buf_len + self.payload.len());
778 }
779 }
780 Ok(buf)
781 }
782 Err(_) => Err(MessageError::InvalidHeader),
783 }
784 }
785}
786
787#[cfg(test)]
788mod test {
789 use super::*;
790 use crate::{header, option_value::OptionValueString};
791 use alloc::borrow::ToOwned;
792
793 #[test]
794 fn test_decode_packet_with_options() {
795 let buf = [
796 0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69,
797 0x04, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31,
798 ];
799 let packet = Packet::from_bytes(&buf);
800 assert!(packet.is_ok());
801 let packet = packet.unwrap();
802 assert_eq!(packet.header.get_version(), 1);
803 assert_eq!(packet.header.get_type(), header::MessageType::Confirmable);
804 assert_eq!(packet.header.get_token_length(), 4);
805 assert_eq!(
806 packet.header.code,
807 header::MessageClass::Request(header::RequestType::Get)
808 );
809 assert_eq!(packet.header.message_id, 33950);
810 assert_eq!(*packet.get_token(), vec![0x51, 0x55, 0x77, 0xE8]);
811 assert_eq!(packet.options.len(), 2);
812
813 let uri_path = packet.get_option(CoapOption::UriPath);
814 assert!(uri_path.is_some());
815 let uri_path = uri_path.unwrap();
816 let mut expected_uri_path = LinkedList::new();
817 expected_uri_path.push_back("Hi".as_bytes().to_vec());
818 expected_uri_path.push_back("Test".as_bytes().to_vec());
819 assert_eq!(*uri_path, expected_uri_path);
820
821 let uri_query = packet.get_option(CoapOption::UriQuery);
822 assert!(uri_query.is_some());
823 let uri_query = uri_query.unwrap();
824 let mut expected_uri_query = LinkedList::new();
825 expected_uri_query.push_back("a=1".as_bytes().to_vec());
826 assert_eq!(*uri_query, expected_uri_query);
827 }
828
829 #[test]
830 fn test_decode_packet_with_payload() {
831 let buf = [
832 0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48, 0x65,
833 0x6C, 0x6C, 0x6F,
834 ];
835 let packet = Packet::from_bytes(&buf);
836 assert!(packet.is_ok());
837 let packet = packet.unwrap();
838 assert_eq!(packet.header.get_version(), 1);
839 assert_eq!(
840 packet.header.get_type(),
841 header::MessageType::Acknowledgement
842 );
843 assert_eq!(packet.header.get_token_length(), 4);
844 assert_eq!(
845 packet.header.code,
846 header::MessageClass::Response(header::ResponseType::Content)
847 );
848 assert_eq!(packet.header.message_id, 5117);
849 assert_eq!(*packet.get_token(), vec![0xD0, 0xE2, 0x4D, 0xAC]);
850 assert_eq!(packet.payload, "Hello".as_bytes().to_vec());
851 }
852
853 #[test]
854 fn test_encode_packet_with_options() {
855 let mut packet = Packet::new();
856 packet.header.set_version(1);
857 packet.header.set_type(header::MessageType::Confirmable);
858 packet.header.code =
859 header::MessageClass::Request(header::RequestType::Get);
860 packet.header.message_id = 33950;
861 packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
862 packet.add_option(CoapOption::UriPath, b"Hi".to_vec());
863 packet.add_option(CoapOption::UriPath, b"Test".to_vec());
864 packet.add_option(CoapOption::UriQuery, b"a=1".to_vec());
865 assert_eq!(
866 packet.to_bytes().unwrap(),
867 vec![
868 0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48,
869 0x69, 0x04, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31
870 ]
871 );
872 }
873
874 #[test]
875 fn test_encode_packet_with_payload() {
876 let mut packet = Packet::new();
877 packet.header.set_version(1);
878 packet.header.set_type(header::MessageType::Acknowledgement);
879 packet.header.code =
880 header::MessageClass::Response(header::ResponseType::Content);
881 packet.header.message_id = 5117;
882 packet.set_token(vec![0xD0, 0xE2, 0x4D, 0xAC]);
883 packet.payload = "Hello".as_bytes().to_vec();
884 assert_eq!(
885 packet.to_bytes().unwrap(),
886 vec![
887 0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48,
888 0x65, 0x6C, 0x6C, 0x6F
889 ]
890 );
891 }
892
893 #[test]
894 fn test_encode_decode_content_format() {
895 let mut packet = Packet::new();
896 packet.set_content_format(ContentFormat::TextPlain);
897 assert_eq!(
898 ContentFormat::TextPlain,
899 packet.get_content_format().unwrap()
900 )
901 }
902
903 #[test]
904 fn test_encode_decode_content_format_without_msb() {
905 let mut packet = Packet::new();
906 packet.set_content_format(ContentFormat::ApplicationJSON);
907 assert_eq!(
908 ContentFormat::ApplicationJSON,
909 packet.get_content_format().unwrap()
910 )
911 }
912
913 #[test]
914 fn test_encode_decode_content_format_with_msb() {
915 let mut packet = Packet::new();
916 packet.set_content_format(ContentFormat::ApplicationSensmlXML);
917 assert_eq!(
918 ContentFormat::ApplicationSensmlXML,
919 packet.get_content_format().unwrap()
920 )
921 }
922
923 #[test]
924 fn test_decode_empty_content_format() {
925 let packet = Packet::new();
926 assert!(packet.get_content_format().is_none());
927 }
928
929 #[test]
930 fn option() {
931 for i in 0..512 {
932 assert_eq!(i, CoapOption::from(i).into());
933 }
934 }
935
936 #[test]
937 fn content_format() {
938 for i in 0..512 {
939 if let Ok(o) = ContentFormat::try_from(i) {
940 assert_eq!(i, o.into());
941 }
942 }
943 }
944
945 #[test]
946 fn observe_option() {
947 for i in 0..8 {
948 if let Ok(o) = ObserveOption::try_from(i) {
949 assert_eq!(i, o.into());
950 }
951 }
952 }
953
954 #[test]
955 fn options() {
956 let mut p = Packet::new();
957 p.add_option(CoapOption::UriHost, vec![0]);
958 p.add_option(CoapOption::UriPath, vec![1]);
959 p.add_option(CoapOption::ETag, vec![2]);
960 p.clear_option(CoapOption::ETag);
961 assert_eq!(3, p.options().len());
962
963 let bytes = p.to_bytes().unwrap();
964 let mut pp = Packet::from_bytes(&bytes).unwrap();
965 assert_eq!(2, pp.options().len());
966
967 let mut values = LinkedList::new();
968 values.push_back(vec![3]);
969 values.push_back(vec![4]);
970 pp.set_option(CoapOption::Oscore, values);
971 assert_eq!(3, pp.options().len());
972 }
973
974 #[test]
975 fn test_option_u32_format() {
976 let mut p = Packet::new();
977 let option_key = CoapOption::Observe;
978 let values = vec![0, 100, 1000, 10000, u32::MAX];
979 for &value in &values {
980 p.add_option_as(option_key, OptionValueU32(value));
981 }
982 let expected = values.iter().map(|&x| Ok(OptionValueU32(x))).collect();
983 let actual = p.get_options_as::<OptionValueU32>(option_key);
984 assert_eq!(actual, Some(expected));
985 }
986
987 #[test]
988 fn test_option_utf8_format() {
989 let mut p = Packet::new();
990 let option_key = CoapOption::UriPath;
991 let values = vec!["", "simple", "unicode 😁 stuff"];
992 for &value in &values {
993 p.add_option_as(option_key, OptionValueString(value.to_owned()));
994 }
995 let expected = values
996 .iter()
997 .map(|&x| Ok(OptionValueString(x.to_owned())))
998 .collect();
999 let actual = p.get_options_as::<OptionValueString>(option_key);
1000 assert_eq!(actual, Some(expected));
1001 }
1002
1003 #[test]
1004 fn observe() {
1005 let mut p = Packet::new();
1006 assert_eq!(None, p.get_observe_value());
1007 p.set_observe_value(0);
1008 assert_eq!(Some(Ok(0)), p.get_observe_value());
1009 }
1010
1011 #[test]
1012 fn to_bytes_limits_work() {
1013 let mut packet = Packet::new();
1014
1015 packet.payload = vec![0u8; 1200];
1016 assert!(packet.to_bytes().is_ok());
1017
1018 packet.payload = vec![0u8; 1300];
1019 assert_eq!(packet.to_bytes(), Err(MessageError::InvalidPacketLength));
1020 assert!(packet.to_bytes_with_limit(1380).is_ok());
1021 assert!(packet.to_bytes_unlimited().is_ok());
1022 }
1023
1024 #[test]
1025 fn option_delta_u8_overflow() {
1026 let mut input = Packet::new();
1032 let option_1 = CoapOption::IfMatch;
1033 let option_258 = CoapOption::NoResponse;
1034
1035 input.add_option(option_1, vec![0]);
1036 input.add_option(option_258, vec![1]);
1037 let bytes = input.to_bytes().unwrap();
1038
1039 let output = Packet::from_bytes(&bytes).unwrap();
1041 assert_eq!(output.options().len(), 2);
1042 assert_eq!(output.get_first_option(option_1), Some(vec![0]).as_ref());
1043 assert_eq!(
1044 output.get_first_option(option_258),
1045 Some(vec![1]).as_ref()
1046 );
1047 }
1048
1049 #[test]
1050 fn reject_excessive_option_delta() {
1051 let bytes = [
1058 0x40, 0x01, 0x00, 0x00,
1060 0xe0, 0xfe, 0xf3,
1062 ];
1063
1064 let result = Packet::from_bytes(&bytes);
1065 assert_eq!(result, Err(MessageError::InvalidOptionDelta));
1066 }
1067
1068 #[test]
1069 fn reject_excessive_option_number() {
1070 let bytes = [
1077 0x40, 0x01, 0x00, 0x00,
1079 0xe0, 0xfe, 0xf2,
1081 0x10,
1083 ];
1084
1085 let result = Packet::from_bytes(&bytes);
1086 assert_eq!(result, Err(MessageError::InvalidOptionDelta));
1087 }
1088}