1use alloc::vec::Vec;
18
19use crate::error::{Error, Result};
20use crate::ext::{self, HeaderExtension, WORD};
21
22pub const NORM_VERSION: u8 = 1;
24pub const COMMON_HEADER_LEN: usize = 8;
26pub const SENDER_WORD_LEN: usize = 4;
28
29pub const NORM_NODE_NONE: u32 = 0x0000_0000;
31pub const NORM_NODE_ANY: u32 = 0xFFFF_FFFF;
33
34pub const HET_EXT_AUTH: u8 = 1;
36pub const HET_EXT_CC: u8 = 3;
38pub const HET_EXT_FTI: u8 = 64;
40pub const HET_EXT_RATE: u8 = 128;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize))]
46#[non_exhaustive]
47pub enum NormMessageType {
48 Info,
50 Data,
52 Cmd,
54 Nack,
56 Ack,
58 Report,
60 Other(u8),
62}
63
64impl NormMessageType {
65 pub fn from_u8(v: u8) -> Self {
67 match v {
68 1 => NormMessageType::Info,
69 2 => NormMessageType::Data,
70 3 => NormMessageType::Cmd,
71 4 => NormMessageType::Nack,
72 5 => NormMessageType::Ack,
73 6 => NormMessageType::Report,
74 other => NormMessageType::Other(other),
75 }
76 }
77
78 pub fn to_u8(self) -> u8 {
80 match self {
81 NormMessageType::Info => 1,
82 NormMessageType::Data => 2,
83 NormMessageType::Cmd => 3,
84 NormMessageType::Nack => 4,
85 NormMessageType::Ack => 5,
86 NormMessageType::Report => 6,
87 NormMessageType::Other(v) => v,
88 }
89 }
90
91 pub fn name(&self) -> &'static str {
93 match self {
94 NormMessageType::Info => "NORM_INFO",
95 NormMessageType::Data => "NORM_DATA",
96 NormMessageType::Cmd => "NORM_CMD",
97 NormMessageType::Nack => "NORM_NACK",
98 NormMessageType::Ack => "NORM_ACK",
99 NormMessageType::Report => "NORM_REPORT",
100 NormMessageType::Other(_) => "reserved",
101 }
102 }
103}
104
105broadcast_common::impl_spec_display!(NormMessageType, Other);
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize))]
114pub struct NormCommonHeader {
115 pub version: u8,
117 pub message_type: NormMessageType,
119 pub sequence: u16,
121 pub source_id: u32,
123}
124
125impl NormCommonHeader {
126 pub fn parse(data: &[u8]) -> Result<(Self, u8)> {
129 if data.len() < COMMON_HEADER_LEN {
130 return Err(Error::BufferTooShort {
131 need: COMMON_HEADER_LEN,
132 have: data.len(),
133 what: "NORM common header",
134 });
135 }
136 let version = data[0] >> 4;
137 let message_type = NormMessageType::from_u8(data[0] & 0x0F);
138 let hdr_len = data[1];
139 let sequence = u16::from_be_bytes([data[2], data[3]]);
140 let source_id = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
141 Ok((
142 NormCommonHeader {
143 version,
144 message_type,
145 sequence,
146 source_id,
147 },
148 hdr_len,
149 ))
150 }
151
152 pub fn serialize_into(&self, out: &mut [u8], hdr_len: u8) -> Result<usize> {
155 if out.len() < COMMON_HEADER_LEN {
156 return Err(Error::OutputBufferTooSmall {
157 need: COMMON_HEADER_LEN,
158 have: out.len(),
159 });
160 }
161 if self.version > 0x0F {
162 return Err(Error::FieldTooWide {
163 what: "version",
164 value: self.version as u64,
165 bits: 4,
166 });
167 }
168 let ty = self.message_type.to_u8();
169 if ty > 0x0F {
170 return Err(Error::FieldTooWide {
171 what: "type",
172 value: ty as u64,
173 bits: 4,
174 });
175 }
176 out[0] = (self.version << 4) | (ty & 0x0F);
177 out[1] = hdr_len;
178 out[2..4].copy_from_slice(&self.sequence.to_be_bytes());
179 out[4..8].copy_from_slice(&self.source_id.to_be_bytes());
180 Ok(COMMON_HEADER_LEN)
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187#[cfg_attr(feature = "serde", derive(serde::Serialize))]
188pub struct SenderWord {
189 pub instance_id: u16,
191 pub grtt: u8,
193 pub backoff: u8,
195 pub gsize: u8,
197}
198
199impl SenderWord {
200 pub fn parse(data: &[u8]) -> Result<Self> {
202 if data.len() < SENDER_WORD_LEN {
203 return Err(Error::BufferTooShort {
204 need: SENDER_WORD_LEN,
205 have: data.len(),
206 what: "NORM sender word",
207 });
208 }
209 Ok(SenderWord {
210 instance_id: u16::from_be_bytes([data[0], data[1]]),
211 grtt: data[2],
212 backoff: data[3] >> 4,
213 gsize: data[3] & 0x0F,
214 })
215 }
216
217 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
219 if out.len() < SENDER_WORD_LEN {
220 return Err(Error::OutputBufferTooSmall {
221 need: SENDER_WORD_LEN,
222 have: out.len(),
223 });
224 }
225 if self.backoff > 0x0F {
226 return Err(Error::FieldTooWide {
227 what: "backoff",
228 value: self.backoff as u64,
229 bits: 4,
230 });
231 }
232 if self.gsize > 0x0F {
233 return Err(Error::FieldTooWide {
234 what: "gsize",
235 value: self.gsize as u64,
236 bits: 4,
237 });
238 }
239 out[0..2].copy_from_slice(&self.instance_id.to_be_bytes());
240 out[2] = self.grtt;
241 out[3] = (self.backoff << 4) | (self.gsize & 0x0F);
242 Ok(SENDER_WORD_LEN)
243 }
244}
245
246#[derive(Debug, Clone, PartialEq, Eq)]
255#[cfg_attr(feature = "serde", derive(serde::Serialize))]
256pub struct NormInfo<'a> {
257 pub common: NormCommonHeader,
259 pub sender: SenderWord,
261 pub flags: u8,
263 pub fec_id: u8,
265 pub object_transport_id: u16,
267 pub extensions: Vec<HeaderExtension<'a>>,
269 pub payload: &'a [u8],
271}
272
273pub const NORM_INFO_FIXED_LEN: usize = COMMON_HEADER_LEN + SENDER_WORD_LEN + WORD;
276
277impl<'a> NormInfo<'a> {
278 fn header_bytes(&self) -> usize {
280 NORM_INFO_FIXED_LEN + ext::chain_len(&self.extensions)
281 }
282
283 pub fn serialized_len(&self) -> usize {
285 self.header_bytes() + self.payload.len()
286 }
287
288 pub fn parse(data: &'a [u8]) -> Result<Self> {
290 let (common, hdr_len) = NormCommonHeader::parse(data)?;
291 let sender = SenderWord::parse(&data[COMMON_HEADER_LEN..])?;
292 let off = COMMON_HEADER_LEN + SENDER_WORD_LEN;
293 if data.len() < off + WORD {
294 return Err(Error::BufferTooShort {
295 need: off + WORD,
296 have: data.len(),
297 what: "NORM_INFO flags word",
298 });
299 }
300 let flags = data[off];
301 let fec_id = data[off + 1];
302 let object_transport_id = u16::from_be_bytes([data[off + 2], data[off + 3]]);
303
304 let header_end = hdr_len as usize * WORD;
306 if header_end < NORM_INFO_FIXED_LEN {
307 return Err(Error::InconsistentLength {
308 length: hdr_len,
309 reason: "hdr_len smaller than the NORM_INFO fixed header",
310 });
311 }
312 if data.len() < header_end {
313 return Err(Error::BufferTooShort {
314 need: header_end,
315 have: data.len(),
316 what: "NORM_INFO header (per hdr_len)",
317 });
318 }
319 let extensions = ext::parse_chain(&data[NORM_INFO_FIXED_LEN..header_end])?;
320 let payload = &data[header_end..];
321
322 Ok(NormInfo {
323 common,
324 sender,
325 flags,
326 fec_id,
327 object_transport_id,
328 extensions,
329 payload,
330 })
331 }
332
333 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
335 let total = self.serialized_len();
336 if out.len() < total {
337 return Err(Error::OutputBufferTooSmall {
338 need: total,
339 have: out.len(),
340 });
341 }
342 let header_bytes = self.header_bytes();
343 if !header_bytes.is_multiple_of(WORD) {
344 return Err(Error::InvalidField {
345 what: "hdr_len",
346 reason: "NORM_INFO header length is not a multiple of 4 bytes",
347 });
348 }
349 let words = header_bytes / WORD;
350 if words > u8::MAX as usize {
351 return Err(Error::FieldTooWide {
352 what: "hdr_len",
353 value: words as u64,
354 bits: 8,
355 });
356 }
357 let mut off = self.common.serialize_into(out, words as u8)?;
358 off += self.sender.serialize_into(&mut out[off..])?;
359 out[off] = self.flags;
360 out[off + 1] = self.fec_id;
361 out[off + 2..off + 4].copy_from_slice(&self.object_transport_id.to_be_bytes());
362 off += WORD;
363 off += ext::serialize_chain(&self.extensions, &mut out[off..])?;
364 out[off..off + self.payload.len()].copy_from_slice(self.payload);
365 off += self.payload.len();
366 Ok(off)
367 }
368}
369
370pub const NORM_FLAG_REPAIR: u8 = 0x01;
373pub const NORM_FLAG_EXPLICIT: u8 = 0x02;
375pub const NORM_FLAG_INFO: u8 = 0x04;
377pub const NORM_FLAG_UNRELIABLE: u8 = 0x08;
379pub const NORM_FLAG_FILE: u8 = 0x10;
381pub const NORM_FLAG_STREAM: u8 = 0x20;
383
384#[derive(Debug, Clone, PartialEq, Eq)]
392#[cfg_attr(feature = "serde", derive(serde::Serialize))]
393pub struct NormData<'a> {
394 pub common: NormCommonHeader,
396 pub sender: SenderWord,
398 pub flags: u8,
400 pub fec_id: u8,
402 pub object_transport_id: u16,
404 pub fec_payload_id: &'a [u8],
406 pub extensions: Vec<HeaderExtension<'a>>,
408 pub payload: &'a [u8],
410}
411
412impl<'a> NormData<'a> {
413 fn header_bytes(&self) -> usize {
416 COMMON_HEADER_LEN
417 + SENDER_WORD_LEN
418 + WORD
419 + self.fec_payload_id.len()
420 + ext::chain_len(&self.extensions)
421 }
422
423 pub fn serialized_len(&self) -> usize {
425 self.header_bytes() + self.payload.len()
426 }
427
428 pub fn parse(data: &'a [u8], fec_payload_id_len: usize) -> Result<Self> {
431 let (common, hdr_len) = NormCommonHeader::parse(data)?;
432 let sender = SenderWord::parse(&data[COMMON_HEADER_LEN..])?;
433 let mut off = COMMON_HEADER_LEN + SENDER_WORD_LEN;
434 if data.len() < off + WORD {
435 return Err(Error::BufferTooShort {
436 need: off + WORD,
437 have: data.len(),
438 what: "NORM_DATA flags word",
439 });
440 }
441 let flags = data[off];
442 let fec_id = data[off + 1];
443 let object_transport_id = u16::from_be_bytes([data[off + 2], data[off + 3]]);
444 off += WORD;
445
446 if data.len() < off + fec_payload_id_len {
447 return Err(Error::BufferTooShort {
448 need: off + fec_payload_id_len,
449 have: data.len(),
450 what: "NORM_DATA fec_payload_id",
451 });
452 }
453 let fec_payload_id = &data[off..off + fec_payload_id_len];
454 off += fec_payload_id_len;
455
456 let header_end = hdr_len as usize * WORD;
459 if header_end < off {
460 return Err(Error::InconsistentLength {
461 length: hdr_len,
462 reason: "hdr_len smaller than the fixed NORM_DATA header + fec_payload_id",
463 });
464 }
465 if data.len() < header_end {
466 return Err(Error::BufferTooShort {
467 need: header_end,
468 have: data.len(),
469 what: "NORM_DATA header (per hdr_len)",
470 });
471 }
472 let extensions = ext::parse_chain(&data[off..header_end])?;
473 let payload = &data[header_end..];
474
475 Ok(NormData {
476 common,
477 sender,
478 flags,
479 fec_id,
480 object_transport_id,
481 fec_payload_id,
482 extensions,
483 payload,
484 })
485 }
486
487 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
489 let total = self.serialized_len();
490 if out.len() < total {
491 return Err(Error::OutputBufferTooSmall {
492 need: total,
493 have: out.len(),
494 });
495 }
496 let header_bytes = self.header_bytes();
497 if !header_bytes.is_multiple_of(WORD) {
498 return Err(Error::InvalidField {
499 what: "hdr_len",
500 reason: "NORM_DATA header length is not a multiple of 4 bytes",
501 });
502 }
503 let words = header_bytes / WORD;
504 if words > u8::MAX as usize {
505 return Err(Error::FieldTooWide {
506 what: "hdr_len",
507 value: words as u64,
508 bits: 8,
509 });
510 }
511 let mut off = self.common.serialize_into(out, words as u8)?;
512 off += self.sender.serialize_into(&mut out[off..])?;
513 out[off] = self.flags;
514 out[off + 1] = self.fec_id;
515 out[off + 2..off + 4].copy_from_slice(&self.object_transport_id.to_be_bytes());
516 off += WORD;
517 out[off..off + self.fec_payload_id.len()].copy_from_slice(self.fec_payload_id);
518 off += self.fec_payload_id.len();
519 off += ext::serialize_chain(&self.extensions, &mut out[off..])?;
520 out[off..off + self.payload.len()].copy_from_slice(self.payload);
521 off += self.payload.len();
522 Ok(off)
523 }
524}
525
526#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
528#[cfg_attr(feature = "serde", derive(serde::Serialize))]
529#[non_exhaustive]
530pub enum NormCmdType {
531 Flush,
533 Eot,
535 Squelch,
537 Cc,
539 RepairAdv,
541 AckReq,
543 Application,
545 Other(u8),
547}
548
549impl NormCmdType {
550 pub fn from_u8(v: u8) -> Self {
552 match v {
553 1 => NormCmdType::Flush,
554 2 => NormCmdType::Eot,
555 3 => NormCmdType::Squelch,
556 4 => NormCmdType::Cc,
557 5 => NormCmdType::RepairAdv,
558 6 => NormCmdType::AckReq,
559 7 => NormCmdType::Application,
560 other => NormCmdType::Other(other),
561 }
562 }
563
564 pub fn to_u8(self) -> u8 {
566 match self {
567 NormCmdType::Flush => 1,
568 NormCmdType::Eot => 2,
569 NormCmdType::Squelch => 3,
570 NormCmdType::Cc => 4,
571 NormCmdType::RepairAdv => 5,
572 NormCmdType::AckReq => 6,
573 NormCmdType::Application => 7,
574 NormCmdType::Other(v) => v,
575 }
576 }
577
578 pub fn name(&self) -> &'static str {
580 match self {
581 NormCmdType::Flush => "NORM_CMD(FLUSH)",
582 NormCmdType::Eot => "NORM_CMD(EOT)",
583 NormCmdType::Squelch => "NORM_CMD(SQUELCH)",
584 NormCmdType::Cc => "NORM_CMD(CC)",
585 NormCmdType::RepairAdv => "NORM_CMD(REPAIR_ADV)",
586 NormCmdType::AckReq => "NORM_CMD(ACK_REQ)",
587 NormCmdType::Application => "NORM_CMD(APPLICATION)",
588 NormCmdType::Other(_) => "reserved",
589 }
590 }
591}
592
593broadcast_common::impl_spec_display!(NormCmdType, Other);
594
595#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
597#[cfg_attr(feature = "serde", derive(serde::Serialize))]
598#[non_exhaustive]
599pub enum NormAckType {
600 Cc,
602 Flush,
604 Reserved(u8),
606 Application(u8),
608}
609
610impl NormAckType {
611 pub fn from_u8(v: u8) -> Self {
613 match v {
614 1 => NormAckType::Cc,
615 2 => NormAckType::Flush,
616 3..=15 => NormAckType::Reserved(v),
617 _ => NormAckType::Application(v),
618 }
619 }
620
621 pub fn to_u8(self) -> u8 {
623 match self {
624 NormAckType::Cc => 1,
625 NormAckType::Flush => 2,
626 NormAckType::Reserved(v) | NormAckType::Application(v) => v,
627 }
628 }
629
630 pub fn name(&self) -> &'static str {
632 match self {
633 NormAckType::Cc => "NORM_ACK(CC)",
634 NormAckType::Flush => "NORM_ACK(FLUSH)",
635 NormAckType::Reserved(_) => "reserved",
636 NormAckType::Application(_) => "application",
637 }
638 }
639}
640
641broadcast_common::impl_spec_display!(NormAckType, Reserved, Application);
642
643#[derive(Debug, Clone, PartialEq, Eq)]
652#[cfg_attr(feature = "serde", derive(serde::Serialize))]
653pub struct NormCmd<'a> {
654 pub common: NormCommonHeader,
656 pub sender: SenderWord,
658 pub sub_type: NormCmdType,
660 pub head: [u8; 3],
664 pub extensions: Vec<HeaderExtension<'a>>,
666 pub content: &'a [u8],
669}
670
671impl<'a> NormCmd<'a> {
672 fn header_bytes(&self) -> usize {
673 COMMON_HEADER_LEN + SENDER_WORD_LEN + WORD + ext::chain_len(&self.extensions)
675 }
676
677 pub fn serialized_len(&self) -> usize {
679 self.header_bytes() + self.content.len()
680 }
681
682 pub fn parse(data: &'a [u8]) -> Result<Self> {
684 let (common, hdr_len) = NormCommonHeader::parse(data)?;
685 let sender = SenderWord::parse(&data[COMMON_HEADER_LEN..])?;
686 let mut off = COMMON_HEADER_LEN + SENDER_WORD_LEN;
687 if data.len() < off + WORD {
688 return Err(Error::BufferTooShort {
689 need: off + WORD,
690 have: data.len(),
691 what: "NORM_CMD sub-type word",
692 });
693 }
694 let sub_type = NormCmdType::from_u8(data[off]);
695 let head = [data[off + 1], data[off + 2], data[off + 3]];
696 off += WORD;
697
698 let header_end = hdr_len as usize * WORD;
699 if header_end < off {
700 return Err(Error::InconsistentLength {
701 length: hdr_len,
702 reason: "hdr_len smaller than the NORM_CMD fixed header",
703 });
704 }
705 if data.len() < header_end {
706 return Err(Error::BufferTooShort {
707 need: header_end,
708 have: data.len(),
709 what: "NORM_CMD header (per hdr_len)",
710 });
711 }
712 let extensions = ext::parse_chain(&data[off..header_end])?;
713 let content = &data[header_end..];
714 Ok(NormCmd {
715 common,
716 sender,
717 sub_type,
718 head,
719 extensions,
720 content,
721 })
722 }
723
724 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
726 let total = self.serialized_len();
727 if out.len() < total {
728 return Err(Error::OutputBufferTooSmall {
729 need: total,
730 have: out.len(),
731 });
732 }
733 let words = self.header_bytes() / WORD;
734 if words > u8::MAX as usize {
735 return Err(Error::FieldTooWide {
736 what: "hdr_len",
737 value: words as u64,
738 bits: 8,
739 });
740 }
741 let mut off = self.common.serialize_into(out, words as u8)?;
742 off += self.sender.serialize_into(&mut out[off..])?;
743 out[off] = self.sub_type.to_u8();
744 out[off + 1..off + 4].copy_from_slice(&self.head);
745 off += WORD;
746 off += ext::serialize_chain(&self.extensions, &mut out[off..])?;
747 out[off..off + self.content.len()].copy_from_slice(self.content);
748 off += self.content.len();
749 Ok(off)
750 }
751}
752
753#[derive(Debug, Clone, PartialEq, Eq)]
758#[cfg_attr(feature = "serde", derive(serde::Serialize))]
759pub struct NormFeedback<'a> {
760 pub common: NormCommonHeader,
762 pub server_id: u32,
764 pub instance_id: u16,
766 pub ack_or_reserved: u16,
769 pub grtt_response_sec: u32,
771 pub grtt_response_usec: u32,
773 pub extensions: Vec<HeaderExtension<'a>>,
775 pub payload: &'a [u8],
777}
778
779pub const FEEDBACK_FIXED_LEN: usize = COMMON_HEADER_LEN + 4 + 4 + 8;
782
783impl<'a> NormFeedback<'a> {
784 pub fn ack_type(&self) -> NormAckType {
786 NormAckType::from_u8((self.ack_or_reserved >> 8) as u8)
787 }
788 pub fn ack_id(&self) -> u8 {
790 self.ack_or_reserved as u8
791 }
792
793 fn header_bytes(&self) -> usize {
794 FEEDBACK_FIXED_LEN + ext::chain_len(&self.extensions)
795 }
796
797 pub fn serialized_len(&self) -> usize {
799 self.header_bytes() + self.payload.len()
800 }
801
802 pub fn parse(data: &'a [u8]) -> Result<Self> {
804 let (common, hdr_len) = NormCommonHeader::parse(data)?;
805 if data.len() < FEEDBACK_FIXED_LEN {
806 return Err(Error::BufferTooShort {
807 need: FEEDBACK_FIXED_LEN,
808 have: data.len(),
809 what: "NORM feedback fixed header",
810 });
811 }
812 let server_id = u32::from_be_bytes([data[8], data[9], data[10], data[11]]);
813 let instance_id = u16::from_be_bytes([data[12], data[13]]);
814 let ack_or_reserved = u16::from_be_bytes([data[14], data[15]]);
815 let grtt_response_sec = u32::from_be_bytes([data[16], data[17], data[18], data[19]]);
816 let grtt_response_usec = u32::from_be_bytes([data[20], data[21], data[22], data[23]]);
817
818 let header_end = hdr_len as usize * WORD;
819 if header_end < FEEDBACK_FIXED_LEN {
820 return Err(Error::InconsistentLength {
821 length: hdr_len,
822 reason: "hdr_len smaller than the NORM feedback fixed header",
823 });
824 }
825 if data.len() < header_end {
826 return Err(Error::BufferTooShort {
827 need: header_end,
828 have: data.len(),
829 what: "NORM feedback header (per hdr_len)",
830 });
831 }
832 let extensions = ext::parse_chain(&data[FEEDBACK_FIXED_LEN..header_end])?;
833 let payload = &data[header_end..];
834 Ok(NormFeedback {
835 common,
836 server_id,
837 instance_id,
838 ack_or_reserved,
839 grtt_response_sec,
840 grtt_response_usec,
841 extensions,
842 payload,
843 })
844 }
845
846 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
848 let total = self.serialized_len();
849 if out.len() < total {
850 return Err(Error::OutputBufferTooSmall {
851 need: total,
852 have: out.len(),
853 });
854 }
855 let words = self.header_bytes() / WORD;
856 if words > u8::MAX as usize {
857 return Err(Error::FieldTooWide {
858 what: "hdr_len",
859 value: words as u64,
860 bits: 8,
861 });
862 }
863 let mut off = self.common.serialize_into(out, words as u8)?;
864 out[off..off + 4].copy_from_slice(&self.server_id.to_be_bytes());
865 out[off + 4..off + 6].copy_from_slice(&self.instance_id.to_be_bytes());
866 out[off + 6..off + 8].copy_from_slice(&self.ack_or_reserved.to_be_bytes());
867 out[off + 8..off + 12].copy_from_slice(&self.grtt_response_sec.to_be_bytes());
868 out[off + 12..off + 16].copy_from_slice(&self.grtt_response_usec.to_be_bytes());
869 off += 16;
870 off += ext::serialize_chain(&self.extensions, &mut out[off..])?;
871 out[off..off + self.payload.len()].copy_from_slice(self.payload);
872 off += self.payload.len();
873 Ok(off)
874 }
875}
876
877#[cfg(test)]
878mod tests {
879 use super::*;
880 use alloc::string::ToString;
881 use alloc::vec;
882
883 fn common(ty: NormMessageType) -> NormCommonHeader {
884 NormCommonHeader {
885 version: NORM_VERSION,
886 message_type: ty,
887 sequence: 0x1234,
888 source_id: 0xCAFEBABE,
889 }
890 }
891
892 fn sender() -> SenderWord {
893 SenderWord {
894 instance_id: 0x00FF,
895 grtt: 0x40,
896 backoff: 0x0A,
897 gsize: 0x05,
898 }
899 }
900
901 #[test]
902 fn message_type_round_trip() {
903 for v in 0u8..=6 {
904 assert_eq!(NormMessageType::from_u8(v).to_u8(), v);
905 }
906 assert_eq!(NormMessageType::Data.to_string(), "NORM_DATA");
907 assert_eq!(NormMessageType::Other(9).to_string(), "reserved(0x09)");
908 }
909
910 #[test]
911 fn common_header_exact_bytes() {
912 let c = common(NormMessageType::Data);
913 let mut out = [0u8; COMMON_HEADER_LEN];
914 c.serialize_into(&mut out, 7).unwrap();
915 assert_eq!(out, [0x12, 0x07, 0x12, 0x34, 0xCA, 0xFE, 0xBA, 0xBE]);
917 let (re, hl) = NormCommonHeader::parse(&out).unwrap();
918 assert_eq!(re, c);
919 assert_eq!(hl, 7);
920 }
921
922 #[test]
923 fn sender_word_exact_bytes() {
924 let s = sender();
925 let mut out = [0u8; SENDER_WORD_LEN];
926 s.serialize_into(&mut out).unwrap();
927 assert_eq!(out, [0x00, 0xFF, 0x40, 0xA5]);
929 assert_eq!(SenderWord::parse(&out).unwrap(), s);
930 }
931
932 #[test]
933 fn norm_data_round_trip_with_fec_payload_id() {
934 let fpid = [0x00u8, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02];
936 let payload = [0xDEu8, 0xAD, 0xBE, 0xEF];
937 let d = NormData {
938 common: common(NormMessageType::Data),
939 sender: sender(),
940 flags: NORM_FLAG_FILE,
941 fec_id: 129,
942 object_transport_id: 0x0007,
943 fec_payload_id: &fpid,
944 extensions: vec![],
945 payload: &payload,
946 };
947 let mut out = vec![0u8; d.serialized_len()];
949 let n = d.serialize_into(&mut out).unwrap();
950 assert_eq!(n, d.serialized_len());
951 assert_eq!(out[1], 6, "hdr_len");
952 let re = NormData::parse(&out, 8).unwrap();
953 assert_eq!(re, d);
954 }
955
956 #[test]
957 fn norm_data_with_ext_fti() {
958 let fti = [
960 0x40u8, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x04, 0x00, 0x00, 0x10, ];
963 let (ext_fti, used) = HeaderExtension::parse(&fti).unwrap();
964 assert_eq!(used, 16);
965 let fpid = [0u8; 8];
966 let d = NormData {
967 common: common(NormMessageType::Data),
968 sender: sender(),
969 flags: 0,
970 fec_id: 129,
971 object_transport_id: 1,
972 fec_payload_id: &fpid,
973 extensions: vec![ext_fti],
974 payload: &[],
975 };
976 let mut out = vec![0u8; d.serialized_len()];
978 d.serialize_into(&mut out).unwrap();
979 assert_eq!(out[1], 10);
980 let re = NormData::parse(&out, 8).unwrap();
981 assert_eq!(re, d);
982 assert_eq!(re.extensions.len(), 1);
983 assert_eq!(re.extensions[0].het, HET_EXT_FTI);
984 }
985
986 #[test]
987 fn norm_cmd_eot_round_trip() {
988 let c = NormCmd {
989 common: common(NormMessageType::Cmd),
990 sender: sender(),
991 sub_type: NormCmdType::Eot,
992 head: [0, 0, 0], extensions: vec![],
994 content: &[],
995 };
996 let mut out = vec![0u8; c.serialized_len()];
997 c.serialize_into(&mut out).unwrap();
998 assert_eq!(out[1], 4);
1000 assert_eq!(out[12], 2);
1002 let re = NormCmd::parse(&out).unwrap();
1003 assert_eq!(re, c);
1004 assert_eq!(re.sub_type, NormCmdType::Eot);
1005 }
1006
1007 #[test]
1008 fn norm_cmd_flush_with_content() {
1009 let c = NormCmd {
1011 common: common(NormMessageType::Cmd),
1012 sender: sender(),
1013 sub_type: NormCmdType::Flush,
1014 head: [129, 0x00, 0x07], extensions: vec![],
1016 content: &[0, 0, 0, 1, 0, 5, 0, 2],
1017 };
1018 let mut out = vec![0u8; c.serialized_len()];
1019 c.serialize_into(&mut out).unwrap();
1020 let re = NormCmd::parse(&out).unwrap();
1021 assert_eq!(re, c);
1022 }
1023
1024 #[test]
1025 fn norm_nack_round_trip() {
1026 let f = NormFeedback {
1027 common: common(NormMessageType::Nack),
1028 server_id: 0x11223344,
1029 instance_id: 0x00FF,
1030 ack_or_reserved: 0, grtt_response_sec: 0x55667788,
1032 grtt_response_usec: 0x99AABBCC,
1033 extensions: vec![],
1034 payload: &[0x01, 0x02, 0x00, 0x04],
1035 };
1036 let mut out = vec![0u8; f.serialized_len()];
1038 f.serialize_into(&mut out).unwrap();
1039 assert_eq!(out[1], 6);
1040 let re = NormFeedback::parse(&out).unwrap();
1041 assert_eq!(re, f);
1042 }
1043
1044 #[test]
1045 fn norm_ack_ack_type_id() {
1046 let f = NormFeedback {
1047 common: common(NormMessageType::Ack),
1048 server_id: 1,
1049 instance_id: 2,
1050 ack_or_reserved: (2 << 8) | 0x07, grtt_response_sec: 0,
1052 grtt_response_usec: 0,
1053 extensions: vec![],
1054 payload: &[],
1055 };
1056 assert_eq!(f.ack_type(), NormAckType::Flush);
1057 assert_eq!(f.ack_id(), 7);
1058 let mut out = vec![0u8; f.serialized_len()];
1059 f.serialize_into(&mut out).unwrap();
1060 let re = NormFeedback::parse(&out).unwrap();
1061 assert_eq!(re, f);
1062 }
1063
1064 #[test]
1065 fn ack_type_ranges() {
1066 assert_eq!(NormAckType::from_u8(1), NormAckType::Cc);
1067 assert_eq!(NormAckType::from_u8(2), NormAckType::Flush);
1068 assert_eq!(NormAckType::from_u8(10), NormAckType::Reserved(10));
1069 assert_eq!(NormAckType::from_u8(200), NormAckType::Application(200));
1070 assert_eq!(NormAckType::Reserved(10).to_string(), "reserved(0x0A)");
1071 }
1072
1073 #[test]
1077 fn norm_info_round_trip() {
1078 let payload = [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01, 0x02, 0x03u8];
1079 let info = NormInfo {
1080 common: common(NormMessageType::Info),
1081 sender: sender(),
1082 flags: NORM_FLAG_FILE,
1083 fec_id: 129,
1084 object_transport_id: 0x0042,
1085 extensions: vec![],
1086 payload: &payload,
1087 };
1088 assert_eq!(info.header_bytes(), NORM_INFO_FIXED_LEN);
1090 let total = info.serialized_len();
1091 assert_eq!(total, NORM_INFO_FIXED_LEN + payload.len());
1092
1093 let mut out = vec![0u8; total];
1094 let n = info.serialize_into(&mut out).unwrap();
1095 assert_eq!(n, total);
1096
1097 assert_eq!(out[0], 0x11, "version=1 type=1");
1099 assert_eq!(out[1], 4, "hdr_len = 4 words");
1100 assert_eq!(out[12], NORM_FLAG_FILE);
1102 assert_eq!(out[13], 129);
1103 assert_eq!(u16::from_be_bytes([out[14], out[15]]), 0x0042);
1104 assert_eq!(&out[16..], &payload);
1106
1107 let re = NormInfo::parse(&out).unwrap();
1108 assert_eq!(re, info);
1109 }
1110
1111 #[test]
1114 fn norm_info_mutated_field_changes_wire() {
1115 let payload = [0u8; 4];
1116 let make = |oti: u16| {
1117 let i = NormInfo {
1118 common: common(NormMessageType::Info),
1119 sender: sender(),
1120 flags: 0,
1121 fec_id: 0,
1122 object_transport_id: oti,
1123 extensions: vec![],
1124 payload: &payload,
1125 };
1126 let mut out = vec![0u8; i.serialized_len()];
1127 i.serialize_into(&mut out).unwrap();
1128 out
1129 };
1130 let a = make(0x0001);
1131 let b = make(0x0002);
1132 assert_ne!(a, b);
1133 assert_eq!(u16::from_be_bytes([a[14], a[15]]), 0x0001);
1135 assert_eq!(u16::from_be_bytes([b[14], b[15]]), 0x0002);
1136 }
1137
1138 #[test]
1140 fn norm_info_with_ext_fti() {
1141 let fti = [
1143 0x40u8, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x04, 0x00,
1144 0x00, 0x10,
1145 ];
1146 let (ext_fti, _) = HeaderExtension::parse(&fti).unwrap();
1147 let payload = [0xAB, 0xCDu8];
1148 let info = NormInfo {
1149 common: common(NormMessageType::Info),
1150 sender: sender(),
1151 flags: NORM_FLAG_INFO,
1152 fec_id: 129,
1153 object_transport_id: 3,
1154 extensions: vec![ext_fti],
1155 payload: &payload,
1156 };
1157 assert_eq!(info.header_bytes(), 32);
1159 let mut out = vec![0u8; info.serialized_len()];
1160 info.serialize_into(&mut out).unwrap();
1161 assert_eq!(out[1], 8, "hdr_len with EXT_FTI");
1162 let re = NormInfo::parse(&out).unwrap();
1163 assert_eq!(re, info);
1164 assert_eq!(re.extensions.len(), 1);
1165 assert_eq!(re.extensions[0].het, HET_EXT_FTI);
1166 }
1167}