1use bitflags::bitflags;
4
5use crate::array::DynamicLengthArray;
6use crate::parse::{ByteReader, Parse, ParseError};
7use crate::serialize::{ByteWriter, Serialize, SerializeError};
8
9macro_rules! impl_for_bitflags {
11 ($name:ident) => {
12 impl<'a> Parse<'a> for $name {
13 fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
14 <Self as bitflags::Flags>::Bits::parse_partial(reader)
15 .map($name::from_bits_truncate)
16 }
17 }
18
19 impl Serialize for $name {
20 fn required_length(&self) -> usize {
21 self.bits().required_length()
22 }
23
24 fn serialize_partial(
25 &self,
26 byte_writer: &mut ByteWriter,
27 ) -> Result<(), SerializeError> {
28 self.bits().serialize_partial(byte_writer)
29 }
30 }
31 };
32}
33
34bitflags! {
35 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
37 pub struct HeaderFlags: u8 {
38 const REBOOT = 0b00000001;
40 const UNICAST = 0b00000010;
42 }
43}
44
45impl_for_bitflags!(HeaderFlags);
46
47#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
49pub struct Header<'a> {
50 pub flags: HeaderFlags,
52
53 pub reserved: Reserved,
56
57 pub entries: DynamicLengthArray<'a, Entry, u32, 32>,
59
60 pub options: DynamicLengthArray<'a, Option<'a>, u32, 32>,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct Reserved;
67
68impl Parse<'_> for Reserved {
69 fn parse_partial(reader: &mut ByteReader<'_>) -> Result<Self, ParseError> {
70 let _ = reader.read_slice(3)?;
71 Ok(Self)
72 }
73}
74
75impl Serialize for Reserved {
76 fn required_length(&self) -> usize {
77 3
78 }
79
80 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
81 byte_writer.write_slice(&[0; 3])
82 }
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum Entry {
88 FindService(ServiceEntry),
90 OfferService(ServiceEntry),
92 SubscribeEventgroup(EventgroupEntry),
94 SubscribeEventgroupAck(EventgroupEntry),
96}
97
98impl<'a> Parse<'a> for Entry {
99 fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
100 let r#type = reader.read_byte()?;
101
102 let entry = match r#type {
103 0x00 => Entry::FindService(ServiceEntry::parse_partial(reader)?),
104 0x01 => Entry::OfferService(ServiceEntry::parse_partial(reader)?),
105 0x06 => Entry::SubscribeEventgroup(EventgroupEntry::parse_partial(reader)?),
106 0x07 => Entry::SubscribeEventgroupAck(EventgroupEntry::parse_partial(reader)?),
107 _invalid => {
108 return Err(ParseError::MalformedMessage {
109 failed_at: core::any::type_name::<Self>(),
110 });
111 }
112 };
113
114 Ok(entry)
115 }
116}
117
118impl Serialize for Entry {
119 fn required_length(&self) -> usize {
120 1 + match self {
121 Entry::FindService(service_entry) => service_entry.required_length(),
122 Entry::OfferService(service_entry) => service_entry.required_length(),
123 Entry::SubscribeEventgroup(eventgroup_entry) => eventgroup_entry.required_length(),
124 Entry::SubscribeEventgroupAck(eventgroup_entry) => eventgroup_entry.required_length(),
125 }
126 }
127
128 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
129 match self {
130 Entry::FindService(service_entry) => {
131 byte_writer.write_byte(0x00)?;
132 service_entry.serialize_partial(byte_writer)
133 }
134 Entry::OfferService(service_entry) => {
135 byte_writer.write_byte(0x01)?;
136 service_entry.serialize_partial(byte_writer)
137 }
138 Entry::SubscribeEventgroup(eventgroup_entry) => {
139 byte_writer.write_byte(0x06)?;
140 eventgroup_entry.serialize_partial(byte_writer)
141 }
142 Entry::SubscribeEventgroupAck(eventgroup_entry) => {
143 byte_writer.write_byte(0x07)?;
144 eventgroup_entry.serialize_partial(byte_writer)
145 }
146 }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
152pub struct ServiceEntry {
153 pub first_option: u8,
155
156 pub second_option: u8,
158
159 pub option_counts: u8,
162
163 pub service_id: u16,
165
166 pub instance_id: u16,
169
170 pub major_version_ttl: u32,
173
174 pub minor_version: u32,
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize)]
180pub struct OptionsCount {
181 inner: u8,
182}
183
184impl OptionsCount {
185 pub fn first(&self) -> u8 {
189 self.inner & 0x0F
190 }
191
192 pub fn second(&self) -> u8 {
196 self.inner >> 4
197 }
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize)]
202pub struct Counter {
203 inner: u16,
204}
205
206impl Counter {
207 pub fn counter(&self) -> u8 {
211 (self.inner >> 12) as u8
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
217pub struct EventgroupEntry {
218 pub first_option: u8,
220 pub second_option: u8,
222 pub option_counts: OptionsCount,
224 pub service_id: u16,
226 pub instance_id: u16,
229 pub major_version: u8,
231 pub ttl: Ttl,
233 pub counter: Counter,
237 pub eventgroup_id: u16,
239}
240
241#[derive(Debug, Clone, PartialEq, Eq)]
243pub struct Ttl {
244 pub seconds: u32,
248}
249
250impl Parse<'_> for Ttl {
251 fn parse_partial(reader: &mut ByteReader<'_>) -> Result<Self, ParseError> {
252 let bytes = reader.read_slice(3)?;
253
254 Ok(Self {
255 seconds: u32::from_be_bytes([0, bytes[0], bytes[1], bytes[2]]),
256 })
257 }
258}
259
260impl Serialize for Ttl {
261 fn required_length(&self) -> usize {
262 3
263 }
264
265 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
266 byte_writer.write_slice(&self.seconds.to_be_bytes().as_slice()[1..])
267 }
268}
269
270#[derive(Debug, Clone, PartialEq, Eq)]
272pub enum Option<'a> {
273 Configuration(ConfigurationOption<'a>),
275 LoadBalancing(LoadBalancingOption),
277 Ipv4Endpoint(IpV4Option),
279 Ipv6Endpoint(IpV6Option),
281 Ipv4Multicast(IpV4Option),
283 Ipv6Multicast(IpV6Option),
285 Ipv4SdEndpoint(IpV4Option),
287 Ipv6SdEndpoint(IpV6Option),
289}
290
291impl<'a> Parse<'a> for Option<'a> {
292 fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
293 let length = u16::parse_partial(reader)? as usize;
294 let r#type = u8::parse_partial(reader)?;
295
296 let mut option_reader = reader.sub_reader(length)?;
297 let option = match r#type {
298 0x01 => Option::Configuration(ConfigurationOption::parse_partial(&mut option_reader)?),
299 0x02 => Option::LoadBalancing(
300 LoadBalancingOption::parse_partial(&mut option_reader).unwrap(),
301 ),
302 0x04 => Option::Ipv4Endpoint(
303 IpOption::<Ipv4Address>::parse_partial(&mut option_reader).unwrap(),
304 ),
305 0x06 => Option::Ipv6Endpoint(
306 IpOption::<Ipv6Address>::parse_partial(&mut option_reader).unwrap(),
307 ),
308 0x14 => Option::Ipv4Multicast(
309 IpOption::<Ipv4Address>::parse_partial(&mut option_reader).unwrap(),
310 ),
311 0x16 => Option::Ipv6Multicast(
312 IpOption::<Ipv6Address>::parse_partial(&mut option_reader).unwrap(),
313 ),
314 0x24 => Option::Ipv4SdEndpoint(
315 IpOption::<Ipv4Address>::parse_partial(&mut option_reader).unwrap(),
316 ),
317 0x26 => Option::Ipv6SdEndpoint(
318 IpOption::<Ipv6Address>::parse_partial(&mut option_reader).unwrap(),
319 ),
320 _invalid => {
321 return Err(ParseError::MalformedMessage {
322 failed_at: core::any::type_name::<Self>(),
323 });
324 }
325 };
326
327 Ok(option)
328 }
329}
330
331impl Serialize for Option<'_> {
332 fn required_length(&self) -> usize {
333 3 + match self {
334 Option::Configuration(configuration_option) => configuration_option.required_length(),
335 Option::LoadBalancing(load_balancing_option) => load_balancing_option.required_length(),
336 Option::Ipv4Endpoint(ip_option) => ip_option.required_length(),
337 Option::Ipv6Endpoint(ip_option) => ip_option.required_length(),
338 Option::Ipv4Multicast(ip_option) => ip_option.required_length(),
339 Option::Ipv6Multicast(ip_option) => ip_option.required_length(),
340 Option::Ipv4SdEndpoint(ip_option) => ip_option.required_length(),
341 Option::Ipv6SdEndpoint(ip_option) => ip_option.required_length(),
342 }
343 }
344
345 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
346 let reserved_length = byte_writer.reserve_length()?;
347
348 let length = match self {
349 Option::Configuration(configuration_option) => {
350 byte_writer.write_byte(0x01)?;
351 byte_writer.write_counted(|byte_writer| {
352 configuration_option.serialize_partial(byte_writer)
353 })?
354 }
355 Option::LoadBalancing(load_balancing_option) => {
356 byte_writer.write_byte(0x02)?;
357 byte_writer.write_counted(|byte_writer| {
358 load_balancing_option.serialize_partial(byte_writer)
359 })?
360 }
361 Option::Ipv4Endpoint(ip_option) => {
362 byte_writer.write_byte(0x04)?;
363 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
364 }
365 Option::Ipv6Endpoint(ip_option) => {
366 byte_writer.write_byte(0x06)?;
367 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
368 }
369 Option::Ipv4Multicast(ip_option) => {
370 byte_writer.write_byte(0x14)?;
371 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
372 }
373 Option::Ipv6Multicast(ip_option) => {
374 byte_writer.write_byte(0x16)?;
375 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
376 }
377 Option::Ipv4SdEndpoint(ip_option) => {
378 byte_writer.write_byte(0x24)?;
379 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
380 }
381 Option::Ipv6SdEndpoint(ip_option) => {
382 byte_writer.write_byte(0x26)?;
383 byte_writer.write_counted(|byte_writer| ip_option.serialize_partial(byte_writer))?
384 }
385 };
386
387 byte_writer.write_length(reserved_length, &(length as u16))
388 }
389}
390
391#[derive(Debug, Clone, PartialEq, Eq)]
393pub struct ConfigurationArray<'a> {
394 reader: ByteReader<'a>,
396}
397
398impl<'a> ConfigurationArray<'a> {
399 pub fn create<'b, I>(
401 mut strings: I,
402 buffer: &'a mut [u8],
403 ) -> Result<ConfigurationArray<'a>, SerializeError>
404 where
405 I: Iterator<Item = &'b ConfigurationString<'b>>,
406 {
407 let mut byte_writer = ByteWriter::new(buffer);
408
409 let used_bytes = byte_writer.write_counted(move |byte_writer| {
410 for string in strings.by_ref() {
411 string.serialize_partial(byte_writer)?;
412 }
413
414 byte_writer.write_byte(0x0)
416 })?;
417
418 let reader = ByteReader::new(&buffer[..used_bytes]);
419
420 Ok(Self { reader })
421 }
422
423 pub fn iter(&'a self) -> ConfigurationArrayIter<'a> {
425 ConfigurationArrayIter {
426 reader: self.reader.clone(),
427 }
428 }
429}
430
431impl<'a> Parse<'a> for ConfigurationArray<'a> {
432 fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
433 let reader = reader.take_remaining();
434
435 {
437 let mut item_reader = reader.clone();
438
439 while item_reader.len() > 1 {
440 let _ = ConfigurationString::parse_partial(&mut item_reader)?;
441 }
442
443 if item_reader.read_byte().unwrap() != 0 {
444 return Err(ParseError::MalformedMessage {
445 failed_at: core::any::type_name::<Self>(),
446 });
447 }
448 }
449
450 Ok(Self { reader })
451 }
452}
453
454impl Serialize for ConfigurationArray<'_> {
455 fn required_length(&self) -> usize {
456 self.reader.len()
457 }
458
459 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
460 byte_writer.write_slice(self.reader.remaining_slice())
461 }
462}
463
464#[derive(Debug)]
466pub struct ConfigurationArrayIter<'a> {
467 reader: ByteReader<'a>,
468}
469
470impl<'a> Iterator for ConfigurationArrayIter<'a> {
471 type Item = ConfigurationString<'a>;
472
473 fn next(&mut self) -> core::option::Option<Self::Item> {
474 if self.reader.len() == 1 {
475 return None;
476 }
477
478 Some(ConfigurationString::parse_partial(&mut self.reader).unwrap())
479 }
480}
481
482bitflags! {
483 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
485 pub struct ConfigurationOptionFlags: u8 {
486 const DISCARDABLE = 0b00000001;
488 }
489}
490
491impl_for_bitflags!(ConfigurationOptionFlags);
492
493#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
495pub struct ConfigurationOption<'a> {
496 pub flag_reserved: ConfigurationOptionFlags,
498 pub configuration_strings: ConfigurationArray<'a>,
500}
501
502#[derive(Debug, Clone, PartialEq, Eq)]
504pub enum ConfigurationStringValue<'a> {
505 None,
507 Empty,
509 Value(&'a str),
511}
512
513#[derive(Debug, Clone, PartialEq, Eq)]
522pub struct ConfigurationString<'a> {
523 pub key: &'a str,
525 pub value: ConfigurationStringValue<'a>,
527}
528
529impl<'a> Parse<'a> for ConfigurationString<'a> {
530 fn parse_partial(reader: &mut ByteReader<'a>) -> Result<Self, ParseError> {
531 let length = reader.read_byte()? as usize;
532 let string_slice = reader.read_slice(length)?;
533
534 let equal_position = string_slice.iter().position(|byte| *byte == b'=');
537 let key_length = equal_position.unwrap_or(length);
538 let (key_slice, value_slice) = string_slice.split_at(key_length);
539
540 if key_slice
542 .iter()
543 .any(|byte| !matches!(byte, 0x20..0x7E))
545 {
546 return Err(ParseError::MalformedMessage {
547 failed_at: core::any::type_name::<Self>(),
548 });
549 }
550
551 if !key_slice.iter().any(|byte| !byte.is_ascii_whitespace()) {
553 return Err(ParseError::MalformedMessage {
554 failed_at: core::any::type_name::<Self>(),
555 });
556 }
557
558 let key = core::str::from_utf8(key_slice).unwrap();
559
560 let value = if key_length == length {
561 ConfigurationStringValue::None
562 } else if key_length == (length) - 1 {
563 ConfigurationStringValue::Empty
564 } else {
565 let value = core::str::from_utf8(&value_slice[1..]).map_err(|_| {
566 ParseError::MalformedMessage {
567 failed_at: core::any::type_name::<Self>(),
568 }
569 })?;
570
571 ConfigurationStringValue::Value(value)
572 };
573
574 Ok(Self { key, value })
575 }
576}
577
578impl Serialize for ConfigurationString<'_> {
579 fn required_length(&self) -> usize {
580 1 + self.key.len()
581 + match self.value {
582 ConfigurationStringValue::None => 0,
583 ConfigurationStringValue::Empty => 1,
584 ConfigurationStringValue::Value(value) => value.len() + 1,
585 }
586 }
587
588 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
589 let reserved_length = byte_writer.reserve_length()?;
590
591 let length = byte_writer.write_counted(|byte_writer| {
592 byte_writer.write_slice(self.key.as_bytes())?;
593
594 match self.value {
595 ConfigurationStringValue::None => Ok(()),
596 ConfigurationStringValue::Empty => byte_writer.write_byte(b'='),
597 ConfigurationStringValue::Value(value) => {
598 byte_writer.write_byte(b'=')?;
599 byte_writer.write_slice(value.as_bytes())
600 }
601 }
602 })?;
603
604 let length = u8::try_from(length).map_err(|_| SerializeError::LengthOverflow)?;
605 byte_writer.write_length(reserved_length, &length)
606 }
607}
608
609bitflags! {
610 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
612 pub struct LoadBalancingOptionFlags: u8 {
613 const DISCARDABLE = 0b00000001;
615 }
616}
617
618impl_for_bitflags!(LoadBalancingOptionFlags);
619
620#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
622pub struct LoadBalancingOption {
623 pub flag_reserved: LoadBalancingOptionFlags,
625 pub priority: u16,
627 pub weight: u16,
629}
630
631#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
635pub struct IpOption<T>
636where
637 T: for<'p> Parse<'p> + Serialize,
638{
639 pub flag_reserved: u8,
642
643 pub address: T,
646
647 pub reserved: u8,
650
651 pub l4_proto: u8,
655
656 pub port_number: u16,
659}
660
661#[derive(Debug, Clone, PartialEq, Eq)]
663pub struct Ipv4Address {
664 pub octets: [u8; 4],
666}
667
668impl Parse<'_> for Ipv4Address {
669 fn parse_partial(reader: &mut ByteReader<'_>) -> Result<Self, ParseError> {
670 Ok(Self {
671 octets: reader.read_array()?,
672 })
673 }
674}
675
676impl Serialize for Ipv4Address {
677 fn required_length(&self) -> usize {
678 4
679 }
680
681 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
682 byte_writer.write_slice(self.octets.as_slice())
683 }
684}
685
686#[derive(Debug, Clone, PartialEq, Eq)]
688pub struct Ipv6Address {
689 pub octets: [u8; 16],
691}
692
693impl Parse<'_> for Ipv6Address {
694 fn parse_partial(reader: &mut ByteReader<'_>) -> Result<Self, ParseError> {
695 Ok(Self {
696 octets: reader.read_array()?,
697 })
698 }
699}
700
701impl Serialize for Ipv6Address {
702 fn required_length(&self) -> usize {
703 16
704 }
705
706 fn serialize_partial(&self, byte_writer: &mut ByteWriter) -> Result<(), SerializeError> {
707 byte_writer.write_slice(self.octets.as_slice())
708 }
709}
710
711pub type IpV4Option = IpOption<Ipv4Address>;
713
714pub type IpV6Option = IpOption<Ipv6Address>;
716
717#[cfg(test)]
718#[cfg_attr(coverage_nightly, coverage(off))]
719mod configuration_array {
720
721 use crate::parse::{ParseError, ParseExt};
722 use crate::serialize::SerializeError;
723 use crate::service_discovery::{
724 ConfigurationArray, ConfigurationString, ConfigurationStringValue,
725 };
726
727 #[test]
728 fn create() {
729 let strings = [ConfigurationString {
730 key: "key",
731 value: ConfigurationStringValue::Value("test"),
732 }];
733
734 let mut buffer = [0u8; 32];
735 let array = ConfigurationArray::create(strings.iter(), &mut buffer).unwrap();
736
737 assert!(array.iter().eq(strings.into_iter()));
738 }
739
740 #[test]
741 fn create_buffer_too_small() {
742 let strings = [ConfigurationString {
743 key: "key",
744 value: ConfigurationStringValue::Value("test"),
745 }];
746
747 let mut buffer = [0u8; 6];
748 assert!(matches!(
749 ConfigurationArray::create(strings.iter(), &mut buffer),
750 Err(SerializeError::BufferTooSmall)
751 ));
752 }
753
754 #[test]
755 fn parse_not_null_terminated() {
756 const TEST_DATA: &[u8] = &[4, 111, 111, 110, 101, 0xFF];
757
758 assert!(matches!(
759 ConfigurationArray::parse(TEST_DATA),
760 Err(ParseError::MalformedMessage { .. })
761 ));
762 }
763}
764
765#[cfg(test)]
766#[cfg_attr(coverage_nightly, coverage(off))]
767mod configuration_string {
768
769 use crate::parse::{Parse, ParseError, ParseExt};
770 use crate::serialize::{Serialize, SerializeError, SerializeExt};
771 use crate::service_discovery::{ConfigurationString, ConfigurationStringValue};
772
773 #[test]
774 fn conversion() {
775 const EXPECTED_DATA: &[u8] = b"\
776 \x03key\
777 \x04key=\
778 \x09key=value\
779 \x09yek=value";
780
781 #[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
782 struct Test<'a>(
783 ConfigurationString<'a>,
784 ConfigurationString<'a>,
785 ConfigurationString<'a>,
786 ConfigurationString<'a>,
787 );
788
789 let strings = Test(
790 ConfigurationString {
791 key: "key",
792 value: ConfigurationStringValue::None,
793 },
794 ConfigurationString {
795 key: "key",
796 value: ConfigurationStringValue::Empty,
797 },
798 ConfigurationString {
799 key: "key",
800 value: ConfigurationStringValue::Value("value"),
801 },
802 ConfigurationString {
803 key: "yek",
804 value: ConfigurationStringValue::Value("value"),
805 },
806 );
807
808 test_round_trip!(Test, strings, EXPECTED_DATA);
809 }
810
811 #[test]
812 fn parse_zero_length() {
813 const TEST_DATA: &[u8] = b"\x00";
814 assert!(matches!(
815 ConfigurationString::parse(TEST_DATA),
816 Err(ParseError::MalformedMessage { .. })
817 ));
818 }
819
820 #[test]
821 fn parse_no_key() {
822 const TEST_DATA: &[u8] = b"\x01=";
823 assert!(matches!(
824 ConfigurationString::parse(TEST_DATA),
825 Err(ParseError::MalformedMessage { .. })
826 ));
827 }
828
829 #[test]
830 fn parse_key_invalid_characters() {
831 const TEST_DATA: &[u8] = &[1, 0x10];
832 assert!(matches!(
833 ConfigurationString::parse(TEST_DATA),
834 Err(ParseError::MalformedMessage { .. })
835 ));
836 }
837
838 #[test]
839 fn parse_key_only_whitespaces() {
840 const TEST_DATA: &[u8] = b"\x01 ";
841 assert!(matches!(
842 ConfigurationString::parse(TEST_DATA),
843 Err(ParseError::MalformedMessage { .. })
844 ));
845 }
846
847 #[test]
848 fn parse_value_invalid_utf8() {
849 const TEST_DATA: &[u8] = &[5, b'k', b'=', 0xE2, 0x28, 0xA1];
850 assert!(matches!(
851 ConfigurationString::parse(TEST_DATA),
852 Err(ParseError::MalformedMessage { .. })
853 ));
854 }
855
856 #[test]
857 fn serialize_length_overflow() {
858 let long_key = core::str::from_utf8(&[b'a'; 256]).unwrap();
859
860 let string = ConfigurationString {
861 key: long_key,
862 value: ConfigurationStringValue::None,
863 };
864
865 assert_eq!(
866 string.serialize(&mut [0; 512]),
867 Err(SerializeError::LengthOverflow)
868 );
869 }
870}
871
872#[cfg(test)]
873#[cfg_attr(coverage_nightly, coverage(off))]
874mod header {
875 use crate::array::DynamicLengthArray;
876 use crate::service_discovery::{Entry, Header, HeaderFlags, Option, Reserved};
877
878 #[test]
879 fn reserved() {
880 const EXPECTED_DATA: &[u8] = &[0; 3];
881
882 let reserved = Reserved;
883
884 test_round_trip!(Reserved, reserved, EXPECTED_DATA);
885 }
886
887 #[test]
888 fn conversion() {
889 const EXPECTED_DATA: &[u8] = &[
890 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
895
896 let mut buffer = [0u8; 64];
897 let entries =
898 DynamicLengthArray::<'_, Entry, u32, 32>::create(core::iter::empty(), &mut buffer)
899 .unwrap();
900
901 let mut buffer = [0u8; 64];
902 let options =
903 DynamicLengthArray::<'_, Option, u32, 32>::create(core::iter::empty(), &mut buffer)
904 .unwrap();
905
906 let header = Header {
907 flags: HeaderFlags::all(),
908 reserved: Reserved,
909 entries,
910 options,
911 };
912
913 test_round_trip!(Header, header, EXPECTED_DATA);
914 }
915}
916
917#[cfg(test)]
918#[cfg_attr(coverage_nightly, coverage(off))]
919mod entry {
920
921 use super::{Counter, Entry, EventgroupEntry, OptionsCount, ServiceEntry};
922 use crate::parse::{Parse, ParseError, ParseExt};
923 use crate::serialize::Serialize;
924 use crate::service_discovery::Ttl;
925
926 #[test]
927 fn ttl() {
928 const EXPECTED_DATA: &[u8] = &[5, 59, 176];
929
930 let ttl = Ttl { seconds: 342960 };
931
932 test_round_trip!(Ttl, ttl, EXPECTED_DATA);
933 }
934
935 #[test]
936 fn entry() {
937 const EXPECTED_DATA: &[u8] = &[
938 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 1, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 6, 1, 2, 3, 0, 4, 0, 5, 6, 0, 0, 7, 0, 8, 0, 9, 7, 1, 2, 3, 0, 4, 0, 5, 6, 0, 0, 7, 0, 8, 0, 9, ];
943
944 #[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
945 struct Test(Entry, Entry, Entry, Entry);
946
947 let entries = Test(
948 Entry::FindService(ServiceEntry {
949 first_option: 1,
950 second_option: 2,
951 option_counts: 3,
952 service_id: 4,
953 instance_id: 5,
954 major_version_ttl: 6,
955 minor_version: 7,
956 }),
957 Entry::OfferService(ServiceEntry {
958 first_option: 1,
959 second_option: 2,
960 option_counts: 3,
961 service_id: 4,
962 instance_id: 5,
963 major_version_ttl: 6,
964 minor_version: 7,
965 }),
966 Entry::SubscribeEventgroup(EventgroupEntry {
967 first_option: 1,
968 second_option: 2,
969 option_counts: OptionsCount { inner: 3 },
970 service_id: 4,
971 instance_id: 5,
972 major_version: 6,
973 ttl: Ttl { seconds: 7 },
974 counter: Counter { inner: 8 },
975 eventgroup_id: 9,
976 }),
977 Entry::SubscribeEventgroupAck(EventgroupEntry {
978 first_option: 1,
979 second_option: 2,
980 option_counts: OptionsCount { inner: 3 },
981 service_id: 4,
982 instance_id: 5,
983 major_version: 6,
984 ttl: Ttl { seconds: 7 },
985 counter: Counter { inner: 8 },
986 eventgroup_id: 9,
987 }),
988 );
989
990 test_round_trip!(Test, entries, EXPECTED_DATA);
991 }
992
993 #[test]
994 fn invalid_entry() {
995 const USED_VALUES: &[u8] = &[0x00, 0x01, 0x06, 0x07];
996
997 for byte in 0x00..0xFF {
998 if !USED_VALUES.contains(&byte) {
999 assert!(matches!(
1000 Entry::parse(&[byte]),
1001 Err(ParseError::MalformedMessage { .. })
1002 ));
1003 }
1004 }
1005 }
1006
1007 #[test]
1008 fn options_count() {
1009 let count = OptionsCount { inner: 0xAF };
1010
1011 assert_eq!(count.first(), 0xF);
1012 assert_eq!(count.second(), 0xA);
1013 }
1014
1015 #[test]
1016 fn counter() {
1017 let counter = Counter { inner: 0x9000 };
1018 assert_eq!(counter.counter(), 0x9);
1019 }
1020}
1021
1022#[cfg(test)]
1023#[cfg_attr(coverage_nightly, coverage(off))]
1024mod option {
1025
1026 use super::Option;
1027 use crate::parse::{Parse, ParseError, ParseExt};
1028 use crate::serialize::Serialize;
1029 use crate::service_discovery::{
1030 ConfigurationArray, ConfigurationOption, ConfigurationOptionFlags, ConfigurationString,
1031 ConfigurationStringValue, IpV4Option, IpV6Option, Ipv4Address, Ipv6Address,
1032 LoadBalancingOption, LoadBalancingOptionFlags,
1033 };
1034
1035 #[test]
1036 fn ipv4_address() {
1037 const EXPECTED_DATA: &[u8] = &[192, 1, 2, 3];
1038
1039 let ip_address = Ipv4Address {
1040 octets: [192, 1, 2, 3],
1041 };
1042
1043 test_round_trip!(Ipv4Address, ip_address, EXPECTED_DATA);
1044 }
1045
1046 #[test]
1047 fn ipv6_address() {
1048 const EXPECTED_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1049
1050 let ip_address = Ipv6Address {
1051 octets: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1052 };
1053
1054 test_round_trip!(Ipv6Address, ip_address, EXPECTED_DATA);
1055 }
1056
1057 #[test]
1058 fn options() {
1059 const EXPECTED_DATA: &[u8] = &[
1060 0, 25, 1, 0, 4, 110, 111, 110, 101, 6, 101, 109, 112, 116, 121, 61, 10, 118, 97, 108,
1061 117, 101, 61, 116, 101, 115, 116, 0, 0, 5, 2, 0, 0, 1, 0, 2, 0, 9, 4, 1, 2, 2, 2, 2, 3, 4, 0, 5, 0, 21, 6, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 0,
1065 5, 0, 9, 20, 1, 2, 2, 2, 2, 3, 4, 0, 5, 0, 21, 22, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 0,
1068 5, 0, 9, 36, 1, 2, 2, 2, 2, 3, 4, 0, 5, 0, 21, 38, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 0,
1071 5, ];
1073
1074 let strings = [
1075 ConfigurationString {
1076 key: "none",
1077 value: ConfigurationStringValue::None,
1078 },
1079 ConfigurationString {
1080 key: "empty",
1081 value: ConfigurationStringValue::Empty,
1082 },
1083 ConfigurationString {
1084 key: "value",
1085 value: ConfigurationStringValue::Value("test"),
1086 },
1087 ];
1088
1089 let mut buffer = [0u8; 32];
1090 let configuration_strings =
1091 ConfigurationArray::create(strings.iter(), &mut buffer).unwrap();
1092
1093 #[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
1094 struct Test<'a>(
1095 Option<'a>,
1096 Option<'a>,
1097 Option<'a>,
1098 Option<'a>,
1099 Option<'a>,
1100 Option<'a>,
1101 Option<'a>,
1102 Option<'a>,
1103 );
1104
1105 let options = Test(
1106 Option::Configuration(ConfigurationOption {
1107 flag_reserved: ConfigurationOptionFlags::empty(),
1108 configuration_strings,
1109 }),
1110 Option::LoadBalancing(LoadBalancingOption {
1111 flag_reserved: LoadBalancingOptionFlags::empty(),
1112 priority: 1,
1113 weight: 2,
1114 }),
1115 Option::Ipv4Endpoint(IpV4Option {
1116 flag_reserved: 1,
1117 address: Ipv4Address { octets: [2; 4] },
1118 reserved: 3,
1119 l4_proto: 4,
1120 port_number: 5,
1121 }),
1122 Option::Ipv6Endpoint(IpV6Option {
1123 flag_reserved: 1,
1124 address: Ipv6Address { octets: [2; 16] },
1125 reserved: 3,
1126 l4_proto: 4,
1127 port_number: 5,
1128 }),
1129 Option::Ipv4Multicast(IpV4Option {
1130 flag_reserved: 1,
1131 address: Ipv4Address { octets: [2; 4] },
1132 reserved: 3,
1133 l4_proto: 4,
1134 port_number: 5,
1135 }),
1136 Option::Ipv6Multicast(IpV6Option {
1137 flag_reserved: 1,
1138 address: Ipv6Address { octets: [2; 16] },
1139 reserved: 3,
1140 l4_proto: 4,
1141 port_number: 5,
1142 }),
1143 Option::Ipv4SdEndpoint(IpV4Option {
1144 flag_reserved: 1,
1145 address: Ipv4Address { octets: [2; 4] },
1146 reserved: 3,
1147 l4_proto: 4,
1148 port_number: 5,
1149 }),
1150 Option::Ipv6SdEndpoint(IpV6Option {
1151 flag_reserved: 1,
1152 address: Ipv6Address { octets: [2; 16] },
1153 reserved: 3,
1154 l4_proto: 4,
1155 port_number: 5,
1156 }),
1157 );
1158
1159 test_round_trip!(Test, options, EXPECTED_DATA);
1160 }
1161
1162 #[test]
1163 fn invalid_option() {
1164 const USED_VALUES: &[u8] = &[0x01, 0x02, 0x04, 0x06, 0x14, 0x16, 0x24, 0x26];
1165
1166 for byte in 0x00..0xFF {
1167 if !USED_VALUES.contains(&byte) {
1168 assert!(matches!(
1169 Option::parse(&[0x0, 0x0, byte]),
1170 Err(ParseError::MalformedMessage { .. })
1171 ));
1172 }
1173 }
1174 }
1175
1176 #[test]
1177 fn invalid_configuration_option() {
1178 const TEST_DATA: &[u8] = &[
1179 0, 25, 1, 0, 4, 0x7E, 111, 110, 101, 6, 101, 109, 112, 116, 121, 61, 10, 118, 97, 108,
1180 117, 101, 61, 116, 101, 115, 116, 0, ];
1182
1183 assert!(matches!(
1184 Option::parse(TEST_DATA),
1185 Err(ParseError::MalformedMessage { .. })
1186 ));
1187 }
1188}