veecle_os_data_support_someip/
service_discovery.rs

1//! Provides support for serialization and deserialization of SOME/IP service discovery payloads.
2
3use bitflags::bitflags;
4
5use crate::array::DynamicLengthArray;
6use crate::parse::{ByteReader, Parse, ParseError};
7use crate::serialize::{ByteWriter, Serialize, SerializeError};
8
9/// Implements [`Parse`] and [`Serialize`] for types implementing [`Flags`](bitflags::Flags).
10macro_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    /// Service Discovery header flags.
36    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
37    pub struct HeaderFlags: u8 {
38        /// Set to 1 after reboot until Session-ID wraps to 1, then 0.
39        const REBOOT = 0b00000001;
40        /// Set to 1 for all SD messages to indicate unicast support.
41        const UNICAST = 0b00000010;
42    }
43}
44
45impl_for_bitflags!(HeaderFlags);
46
47/// SOME/IP service discovery header.
48#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
49pub struct Header<'a> {
50    /// Service discovery flags.
51    pub flags: HeaderFlags,
52
53    /// Reserved bits.
54    /// Should be set to 0.
55    pub reserved: Reserved,
56
57    /// Array of service [`Entry`]'s.
58    pub entries: DynamicLengthArray<'a, Entry, u32, 32>,
59
60    /// Array of [service_discovery::Option](`crate::service_discovery::Option`) for [`Self::entries`].
61    pub options: DynamicLengthArray<'a, Option<'a>, u32, 32>,
62}
63
64/// SOME/IP service discovery header reserved bytes.
65#[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/// SOME/IP service discovery entry.
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum Entry {
88    /// Service Entry with type 0x00.
89    FindService(ServiceEntry),
90    /// Service Entry with type 0x01.
91    OfferService(ServiceEntry),
92    /// Eventgroup entry with type 0x06.
93    SubscribeEventgroup(EventgroupEntry),
94    /// Eventgroup entry with type 0x07.
95    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/// Service entry.
151#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
152pub struct ServiceEntry {
153    /// Index of option in [`Header::options`] where first option run begins.
154    pub first_option: u8,
155
156    /// Index of option in [`Header::options`] where second option run begins.
157    pub second_option: u8,
158
159    /// Number of options in the first and second option runs.
160    /// Split into two u4 (first and second option runs respectively).
161    pub option_counts: u8,
162
163    /// ID of the service this entry belongs to.
164    pub service_id: u16,
165
166    /// ID of the service instance this entry belongs to.
167    /// When set to 0xffff, then this entry belongs to all service instances.
168    pub instance_id: u16,
169
170    /// Major version of the service and lifetime of this entry (in seconds).
171    /// Split into 8 (major version) and 24 (TTL) bits.
172    pub major_version_ttl: u32,
173
174    /// Minor version of the service.
175    pub minor_version: u32,
176}
177
178/// A wrapper type to gracefully parse the two `u4` option counts of the [`EventgroupEntry`].
179#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize)]
180pub struct OptionsCount {
181    inner: u8,
182}
183
184impl OptionsCount {
185    /// Describes the number of options the first option run uses.
186    ///
187    /// Represents a u4 in the Payload.
188    pub fn first(&self) -> u8 {
189        self.inner & 0x0F
190    }
191
192    /// Describes the number of options the second option run uses.
193    ///
194    /// Represents a u4 in the Payload.
195    pub fn second(&self) -> u8 {
196        self.inner >> 4
197    }
198}
199
200/// A wrapper type to gracefully parse the reserved `u12` and `u4` counter of the [`EventgroupEntry`].
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Parse, Serialize)]
202pub struct Counter {
203    inner: u16,
204}
205
206impl Counter {
207    /// Is used to differentiate identical Subscribe Eventgroups of the same subscriber. Set to 0x0 if not used.
208    ///
209    /// Represents a u4 in the Payload.
210    pub fn counter(&self) -> u8 {
211        (self.inner >> 12) as u8
212    }
213}
214
215/// Eventgroup entry.
216#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
217pub struct EventgroupEntry {
218    /// Index of this runs first option in the option array.
219    pub first_option: u8,
220    /// Index of this runs second option in the option array.
221    pub second_option: u8,
222    /// Describes the number of options the first and second option run uses.
223    pub option_counts: OptionsCount,
224    /// Describes the Service ID of the Service or Service-Instance this entry is concerned with.
225    pub service_id: u16,
226    /// Describes the Service Instance ID of the Service Instance this entry is concerned with or is set to 0xFFFF if
227    /// all service instances of a service are meant.
228    pub instance_id: u16,
229    ///  Encodes the major version of the service (instance).
230    pub major_version: u8,
231    /// Describes the lifetime of the entry in seconds.
232    pub ttl: Ttl,
233    /// Is used to differentiate identical Subscribe Eventgroups of the same subscriber. Set to 0x0 if not used.
234    ///
235    /// This type also includes the reserved bytes.
236    pub counter: Counter,
237    /// Transports the ID of an Eventgroup.
238    pub eventgroup_id: u16,
239}
240
241/// Lifetime of the entry in seconds.
242#[derive(Debug, Clone, PartialEq, Eq)]
243pub struct Ttl {
244    /// Lifetime of the entry in seconds.
245    ///
246    /// Represents a u24 in the payload.
247    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/// SOME/IP service discovery option.
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub enum Option<'a> {
273    /// Configuration Option.
274    Configuration(ConfigurationOption<'a>),
275    /// Load Balancing Option.
276    LoadBalancing(LoadBalancingOption),
277    /// IPv4 Endpoint Option.
278    Ipv4Endpoint(IpV4Option),
279    /// IPv6 Endpoint Option.
280    Ipv6Endpoint(IpV6Option),
281    /// IPv4 Multicast Option.
282    Ipv4Multicast(IpV4Option),
283    /// IPv6 Multicast Option.
284    Ipv6Multicast(IpV6Option),
285    /// IPv4 SD Endpoint Option.
286    Ipv4SdEndpoint(IpV4Option),
287    /// IPv6 SD Endpoint Option.
288    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/// Array of [`ConfigurationString`]s.
392#[derive(Debug, Clone, PartialEq, Eq)]
393pub struct ConfigurationArray<'a> {
394    /// Reader for the configuration array items.
395    reader: ByteReader<'a>,
396}
397
398impl<'a> ConfigurationArray<'a> {
399    /// Creates a new configuration array.
400    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            // Zero termination.
415            byte_writer.write_byte(0x0)
416        })?;
417
418        let reader = ByteReader::new(&buffer[..used_bytes]);
419
420        Ok(Self { reader })
421    }
422
423    /// Returns an iterator over all [`ConfigurationString`]s.
424    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        // Ensure that all the items are valid and the array is zero-terminated.
436        {
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/// Iterator over [`ConfigurationString`]s.
465#[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    /// Service Discovery configuration option flags.
484    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
485    pub struct ConfigurationOptionFlags: u8 {
486        /// Shall be set to 1 if the Option can be discarded by the receiver.
487        const DISCARDABLE = 0b00000001;
488    }
489}
490
491impl_for_bitflags!(ConfigurationOptionFlags);
492
493/// Configuration Option.
494#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
495pub struct ConfigurationOption<'a> {
496    /// Configuration option flags.
497    pub flag_reserved: ConfigurationOptionFlags,
498    /// Array of all configuration strings.
499    pub configuration_strings: ConfigurationArray<'a>,
500}
501
502/// Value of a [`ConfigurationString`].
503#[derive(Debug, Clone, PartialEq, Eq)]
504pub enum ConfigurationStringValue<'a> {
505    /// A key without a value (e.g. "foo")
506    None,
507    /// A key with an empty value (e.g. "foo=")
508    Empty,
509    /// A key with a value (e.g. "foo=bar")
510    Value(&'a str),
511}
512
513// Length is a one byte field.
514// The last configuration string has a length of 0, which indicates the end of the configuration option.
515// Every string has at least a key, optionally a value.
516// Strings with '=', shall be key-value if characters follow the '=', if not the value shall be considered empty.
517// Strings without '=' shall be considered present.
518// Key ends with '=' and shall only contain the ASCII characters 0x20-0x7E excluding 0x3D ('=').
519// The key must contain at least one non-whitespace character.
520/// Configuration string.
521#[derive(Debug, Clone, PartialEq, Eq)]
522pub struct ConfigurationString<'a> {
523    /// Key of a configuration string.
524    pub key: &'a str,
525    /// Value of a configuration string.
526    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        // Find position of '='.
535        // Everything before the `=` is the key, the rest will be deserialized by `ConfigStringValue`.
536        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        // Check for forbidden characters.
541        if key_slice
542            .iter()
543            // 0x3D ('=') is impossible due it being the key-value delimiter and used to derive `key_length`.
544            .any(|byte| !matches!(byte, 0x20..0x7E))
545        {
546            return Err(ParseError::MalformedMessage {
547                failed_at: core::any::type_name::<Self>(),
548            });
549        }
550
551        // Check for at least one non-whitespace character.
552        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    /// Service Discovery load balancing option flags.
611    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
612    pub struct LoadBalancingOptionFlags: u8 {
613        /// Shall be set to 1 if the Option can be discarded by the receiver.
614        const DISCARDABLE = 0b00000001;
615    }
616}
617
618impl_for_bitflags!(LoadBalancingOptionFlags);
619
620/// Load Balancing Option.
621#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
622pub struct LoadBalancingOption {
623    /// Load balancing option flags.
624    pub flag_reserved: LoadBalancingOptionFlags,
625    /// Carries the Priority of this instance. Lower value means higher priority.
626    pub priority: u16,
627    /// Carries the Weight of this instance. Large value means higher probability to be chosen.
628    pub weight: u16,
629}
630
631/// An arbitrary IP Option.
632///
633/// This type is a single representation for all the Ipv4 and Ipv6 options.
634#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize)]
635pub struct IpOption<T>
636where
637    T: for<'p> Parse<'p> + Serialize,
638{
639    /// Discardable flag and reserved bits.
640    /// Split into 1 bit (discardable) and 7 bits (reserved). Both shall be set to 0.
641    pub flag_reserved: u8,
642
643    /// IPv4-address.
644    /// Shall contain the unicast IP-address.
645    pub address: T,
646
647    /// Reserved bytes.
648    /// Shall be set to 0x00.
649    pub reserved: u8,
650
651    /// Transport protocol type.
652    /// Shall be set to the transport layer protocol (ISO/OSI layer 4)
653    /// based on the IANA/IETF types (0x06: TCP, 0x11: UDP).
654    pub l4_proto: u8,
655
656    /// Transport protocol port number.
657    /// Shall be set to the port of the layer 4 protocol.
658    pub port_number: u16,
659}
660
661/// An IPv4 address.
662#[derive(Debug, Clone, PartialEq, Eq)]
663pub struct Ipv4Address {
664    /// IP address octets.
665    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/// An IPv6 address.
687#[derive(Debug, Clone, PartialEq, Eq)]
688pub struct Ipv6Address {
689    /// IP address octets.
690    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
711/// An IPv4 Option.
712pub type IpV4Option = IpOption<Ipv4Address>;
713
714/// An IPv6 Option.
715pub 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, // Header Flags
891            0, 0, 0, // Reserved
892            0, 0, 0, 0, // Entries
893            0, 0, 0, 0, // Options
894        ];
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, // Find service
939            1, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, // Offers service
940            6, 1, 2, 3, 0, 4, 0, 5, 6, 0, 0, 7, 0, 8, 0, 9, // Subscribe eventgroup
941            7, 1, 2, 3, 0, 4, 0, 5, 6, 0, 0, 7, 0, 8, 0, 9, // Subscribe eventgroup ack
942        ];
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, // ConfigurationOption
1062            0, 5, 2, 0, 0, 1, 0, 2, // LoadBalancingOption
1063            0, 9, 4, 1, 2, 2, 2, 2, 3, 4, 0, 5, // Ipv4Endpoint
1064            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, // Ipv6Endpoint
1066            0, 9, 20, 1, 2, 2, 2, 2, 3, 4, 0, 5, //  Ipv4Multicast
1067            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, // Ipv6Multicast
1069            0, 9, 36, 1, 2, 2, 2, 2, 3, 4, 0, 5, // Ipv4SdEndpoint
1070            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, // Ipv6SdEndpoint
1072        ];
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, // ConfigurationOption
1181        ];
1182
1183        assert!(matches!(
1184            Option::parse(TEST_DATA),
1185            Err(ParseError::MalformedMessage { .. })
1186        ));
1187    }
1188}