someip_parse/
sd.rs

1use crate::err::{SdReadError, SdValueError, SdWriteError};
2use std::io::{Read, Seek, Write};
3
4///Length of someip sd header, flags + reserved + entries length + options length
5///excluding entries and options arrays
6pub const MIN_SD_HEADER_LENGTH: usize = 1 + 3 + 4 + 4;
7
8pub const EVENT_ENTRY_INITIAL_DATA_REQUESTED_FLAG: u8 = 0b1000_0000;
9
10/// Constants related to the flags in the sd header
11pub mod sd_flags {
12    /// Reboot flag in the first byte of the sd header indicating
13    /// that the session ids have not yet wrapped around since startup.
14    pub const REBOOT_FLAG: u8 = 0b1000_0000;
15
16    /// Unicast flag in the first byte of the sd header indicating
17    /// that unicast is supported.
18    ///
19    /// # Note (from the SOMEIP SD specification):
20    ///
21    /// The Unicast Flag is left over from historical SOME/IP versions
22    /// and is only kept for compatibility reasons. Its use besides this
23    /// is very limited.
24    pub const UNICAST_FLAG: u8 = 0b0100_0000;
25
26    /// Explicit initial data control is supported.
27    ///
28    /// # Note:
29    ///
30    /// This flag has been removed in the release R21-11
31    /// of the "SOME/IP Service Discovery Protocol Specification".
32    pub const EXPLICIT_INITIAL_DATA_CONTROL_FLAG: u8 = 0b0010_0000;
33}
34
35/// Constants related to sd entries.
36pub mod sd_entries {
37    use super::{SdEventGroupEntryType, SdServiceEntryType};
38
39    /// Maximum entry length that is supported by the read & from slice functions.
40    ///
41    /// This constant is used to make sure no attacks with too large length
42    /// values can trigger large allocations. E.g. if a some ip sd header
43    /// with an entries length of 4 gigabytes gets passed to the `read` function
44    /// it could triggering an allocation of 4 gigabytes. This allocation would then
45    /// take a very long time or lead to a failure and potential crash.
46    ///
47    /// To prevent attacks like these the length gets checked against
48    /// this constant before any allocation gets triggered.
49    ///
50    /// The maximum entry length is calculated from the fact that SOMEIP SD is
51    /// only allowed via UDP and that the SOMEIP specification states the following
52    /// conceirning the maximum payload size:
53    ///
54    /// > The size of the SOME/IP payload field depends on the transport protocol used.
55    /// > With UDP the SOME/IP payload shall be between 0 and 1400 Bytes.
56    ///
57    /// With these facts we can calculcuate the maximum length of bytes
58    /// the following way:
59    ///
60    /// `1400 - sd reserved & flags (4) - entries length(4) - options length(4)`
61    ///
62    /// For sd options array we assume an empty array.
63    pub const MAX_ENTRIES_LEN: u32 = crate::SOMEIP_MAX_PAYLOAD_LEN_UDP - 4 - 4 - 4;
64
65    /// Length of an sd entry (note that all entry types currently have
66    /// the same length).
67    pub const ENTRY_LEN: usize = 16;
68
69    /// SOMEIP service discovery entry for a service.
70    #[derive(Clone, Debug, Eq, PartialEq)]
71    pub struct ServiceEntry {
72        pub _type: SdServiceEntryType,
73        pub index_first_option_run: u8,
74        pub index_second_option_run: u8,
75        pub number_of_options_1: u8,
76        pub number_of_options_2: u8,
77        pub service_id: u16,
78        pub instance_id: u16,
79        pub major_version: u8,
80        pub ttl: u32,
81        pub minor_version: u32,
82    }
83
84    /// SOMEIP service discovery entry for an eventgroup.
85    #[derive(Clone, Debug, Eq, PartialEq)]
86    pub struct EventgroupEntry {
87        pub _type: SdEventGroupEntryType,
88        pub index_first_option_run: u8,
89        pub index_second_option_run: u8,
90        pub number_of_options_1: u8,
91        pub number_of_options_2: u8,
92        pub service_id: u16,
93        pub instance_id: u16,
94        pub major_version: u8,
95        pub ttl: u32,
96        /// True if initial data shall be sent by server
97        pub initial_data_requested: bool,
98        /// distinguish identical subscribe eventgroups of the same subscriber
99        /// 4 bit
100        pub counter: u8,
101        pub eventgroup_id: u16,
102    }
103}
104
105/// Constants related to sd options.
106pub mod sd_options {
107    use super::TransportProtocol;
108
109    /// Maximum length of options array that is supported by the read & from slice functions.
110    ///
111    /// This constant is used to make sure no attacks with large length
112    /// values can trigger large allocations. E.g. if a some ip sd header
113    /// with an options array length of 4 gigabytes gets passed to the `read` function
114    /// it could triggering an allocation of 4 gigabytes. This allocation would then
115    /// take a very long time or lead to a failure and potential crash.
116    ///
117    /// To prevent attacks like these the length gets checked against
118    /// this constant before any allocation gets triggered.
119    ///
120    /// The maximum entry length is calculated from the fact that SOMEIP SD is
121    /// only allowed via UDP and that the SOMEIP specification states the following
122    /// conceirning the maximum payload size:
123    ///
124    /// > The size of the SOME/IP payload field depends on the transport protocol used.
125    /// > With UDP the SOME/IP payload shall be between 0 and 1400 Bytes.
126    ///
127    /// With these facts we can calculcuate the maximum length of bytes
128    /// the following way:
129    ///
130    /// `1400 - sd reserved & flags (4) - entries length(4) - options length(4)`
131    ///
132    /// For the sd entries we assume an empty array.
133    pub const MAX_OPTIONS_LEN: u32 = crate::SOMEIP_MAX_PAYLOAD_LEN_UDP - 4 - 4 - 4;
134
135    /// Flag in the 4th byte (reserved) indicating that the option is allowed
136    /// to be discarded by the receiver if not supported.
137    pub const DISCARDABLE_FLAG: u8 = 0b1000_0000;
138
139    /// Value of the `type` field of a configuration sd option.
140    pub const CONFIGURATION_TYPE: u8 = 0x01;
141
142    /// Value of the `length` field of a load balancing sd option.
143    pub const LOAD_BALANCING_LEN: u16 = 0x0005;
144
145    /// Value of the `type` field of a load balancing sd option.
146    pub const LOAD_BALANCING_TYPE: u8 = 0x02;
147
148    /// Value of the `length` field of an ipv4 endpoint sd option.
149    pub const IPV4_ENDPOINT_LEN: u16 = 0x0009;
150
151    /// Value of the `type` field of an ipv4 endpoint sd option.
152    pub const IPV4_ENDPOINT_TYPE: u8 = 0x04;
153
154    /// Value of the `length` field of an ipv6 endpoint sd option.
155    pub const IPV6_ENDPOINT_LEN: u16 = 0x0015;
156
157    /// Value of the `type` field of an ipv6 endpoint sd option.
158    pub const IPV6_ENDPOINT_TYPE: u8 = 0x06;
159
160    /// Value of the `length` field of an ipv4 multicast sd option.
161    pub const IPV4_MULTICAST_LEN: u16 = 0x0009;
162
163    /// Value of the `type` field of an ipv4 multicast sd option.
164    pub const IPV4_MULTICAST_TYPE: u8 = 0x14;
165
166    /// Value of the `length` field of an ipv6 multicast sd option.
167    pub const IPV6_MULTICAST_LEN: u16 = 0x0015;
168
169    /// Value of the `type` field of an ipv6 multicast sd option.
170    pub const IPV6_MULTICAST_TYPE: u8 = 0x16;
171
172    /// Value of the `length` field of an ipv4 sd endpoint sd option.
173    pub const IPV4_SD_ENDPOINT_LEN: u16 = 0x009;
174
175    /// Value of the `type` field of an ipv4 sd endpoint sd option.
176    pub const IPV4_SD_ENDPOINT_TYPE: u8 = 0x24;
177
178    /// Value of the `length` field of an ipv6 sd endpoint sd option.
179    pub const IPV6_SD_ENDPOINT_LEN: u16 = 0x0015;
180
181    /// Value of the `type` field of an ipv6 sd endpoint sd option.
182    pub const IPV6_SD_ENDPOINT_TYPE: u8 = 0x26;
183
184    #[derive(Clone, Debug, Eq, PartialEq)]
185    pub struct ConfigurationOption {
186        /// Shall be set to `true` if the option can be discarded by the receiver.
187        pub discardable: bool,
188        // TODO DNS TXT / DNS-SD format
189        pub configuration_string: Vec<u8>,
190    }
191
192    #[derive(Clone, Debug, Eq, PartialEq)]
193    pub struct LoadBalancingOption {
194        /// Shall be set to `true` if the option can be discarded by the receiver.
195        pub discardable: bool,
196        pub priority: u16,
197        pub weight: u16,
198    }
199
200    #[derive(Clone, Debug, Eq, PartialEq)]
201    pub struct Ipv4EndpointOption {
202        pub ipv4_address: [u8; 4],
203        pub transport_protocol: TransportProtocol,
204        pub port: u16,
205    }
206
207    #[derive(Clone, Debug, Eq, PartialEq)]
208    pub struct Ipv6EndpointOption {
209        pub ipv6_address: [u8; 16],
210        pub transport_protocol: TransportProtocol,
211        pub port: u16,
212    }
213
214    #[derive(Clone, Debug, Eq, PartialEq)]
215    pub struct Ipv4MulticastOption {
216        pub ipv4_address: [u8; 4],
217        pub transport_protocol: TransportProtocol,
218        pub port: u16,
219    }
220
221    #[derive(Clone, Debug, Eq, PartialEq)]
222    pub struct Ipv6MulticastOption {
223        pub ipv6_address: [u8; 16],
224        pub transport_protocol: TransportProtocol,
225        pub port: u16,
226    }
227
228    #[derive(Clone, Debug, Eq, PartialEq)]
229    pub struct Ipv4SdEndpointOption {
230        pub ipv4_address: [u8; 4],
231        pub transport_protocol: TransportProtocol,
232        pub port: u16,
233    }
234
235    #[derive(Clone, Debug, Eq, PartialEq)]
236    pub struct Ipv6SdEndpointOption {
237        pub ipv6_address: [u8; 16],
238        pub transport_protocol: TransportProtocol,
239        pub port: u16,
240    }
241
242    /// An unknown option that is flagged as "discardable" and
243    /// should be ignored by the receiver if not supported.
244    ///
245    /// This option is only intended to be used for reading,
246    /// to ensure the option indices are still matching. In case
247    /// this option is passed to a write function an error will be
248    /// triggered.
249    #[derive(Clone, Debug, Eq, PartialEq)]
250    pub struct UnknownDiscardableOption {
251        pub length: u16,
252        pub option_type: u8,
253    }
254}
255
256use self::sd_entries::*;
257use self::sd_options::*;
258
259/// Flags at the start of a SOMEIP service discovery header.
260#[derive(Clone, Debug, Eq, PartialEq)]
261pub struct SdHeaderFlags {
262    pub reboot: bool,
263    pub unicast: bool,
264    pub explicit_initial_data_control: bool,
265}
266
267impl Default for SdHeaderFlags {
268    fn default() -> Self {
269        SdHeaderFlags {
270            reboot: false,
271            // set unicast & explicit_initial_data_control to true
272            // by default as they have to be supported by current someip
273            // implementations by default.
274            unicast: true,
275            explicit_initial_data_control: true,
276        }
277    }
278}
279
280impl SdHeaderFlags {
281    /// Returns the first 4 bytes of an SOMEIP SD header.
282    pub fn to_bytes(&self) -> [u8; 4] {
283        use sd_flags::*;
284        [
285            if self.reboot { REBOOT_FLAG } else { 0 }
286                | if self.unicast { UNICAST_FLAG } else { 0 }
287                | if self.explicit_initial_data_control {
288                    EXPLICIT_INITIAL_DATA_CONTROL_FLAG
289                } else {
290                    0
291                },
292            0,
293            0,
294            0,
295        ]
296    }
297}
298
299/// SOMEIP service discovery header
300#[derive(Clone, Debug, Default, Eq, PartialEq)]
301pub struct SdHeader {
302    pub flags: SdHeaderFlags,
303    // reserved: [u8;3],
304    // Length of entries array in bytes
305    // length_of_entries: u32,
306    pub entries: Vec<SdEntry>,
307    // Length of entries array in bytes
308    // length_of_options: u32,
309    pub options: Vec<SdOption>,
310}
311
312impl SdHeader {
313    #[inline]
314    pub fn new(reboot: bool, entries: Vec<SdEntry>, options: Vec<SdOption>) -> Self {
315        Self {
316            flags: SdHeaderFlags {
317                reboot,
318                unicast: true,
319                explicit_initial_data_control: true,
320            },
321            entries,
322            options,
323        }
324    }
325
326    #[inline]
327    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
328    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Self, SdReadError> {
329        SdHeader::read_with_flag(reader, false)
330    }
331
332    #[inline]
333    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
334    pub fn read_with_flag<T: Read + Seek>(
335        reader: &mut T,
336        discard_unknown_option: bool,
337    ) -> Result<Self, SdReadError> {
338        const HEADER_LENGTH: usize = 1 + 3 + 4; // flags + rev + entries length
339        let mut header_bytes: [u8; HEADER_LENGTH] = [0; HEADER_LENGTH];
340        reader.read_exact(&mut header_bytes)?;
341
342        let num_entries = {
343            let length_entries = u32::from_be_bytes([
344                header_bytes[4],
345                header_bytes[5],
346                header_bytes[6],
347                header_bytes[7],
348            ]);
349
350            if length_entries > MAX_ENTRIES_LEN {
351                return Err(SdReadError::SdEntriesArrayLengthTooLarge(length_entries));
352            }
353
354            // Note this function only supports 32 & 64 bit systems.
355            // `read` has been disabled for 16 bit systems to
356            // make this explicit.
357            (length_entries as usize) / ENTRY_LEN
358        };
359        let entries = {
360            let mut entries = Vec::new();
361            entries.try_reserve(num_entries)?;
362            for _ in 0..num_entries {
363                entries.push(SdEntry::read(reader)?);
364            }
365            entries
366        };
367
368        let mut options_length = {
369            let mut options_length_bytes: [u8; 4] = [0x00; 4];
370            reader.read_exact(&mut options_length_bytes)?;
371            u32::from_be_bytes(options_length_bytes)
372        };
373
374        if options_length > MAX_OPTIONS_LEN {
375            return Err(SdReadError::SdOptionsArrayLengthTooLarge(options_length));
376        }
377
378        let mut options = Vec::new();
379        // pessimistically reserve memory so if we trigger an
380        // allocation failure we trigger it here.
381        // (minimum size of an option is 4 bytes)
382        options.try_reserve((options_length as usize) / 4)?;
383
384        while options_length > 0 {
385            let (read_bytes, option) = SdOption::read_with_flag(reader, discard_unknown_option)?;
386            options.push(option);
387            options_length -= read_bytes as u32;
388        }
389
390        //return result
391        use sd_flags::*;
392        Ok(Self {
393            flags: SdHeaderFlags {
394                reboot: 0 != header_bytes[0] & REBOOT_FLAG,
395                unicast: 0 != header_bytes[0] & UNICAST_FLAG,
396                explicit_initial_data_control: 0
397                    != header_bytes[0] & EXPLICIT_INITIAL_DATA_CONTROL_FLAG,
398            },
399            entries,
400            options,
401        })
402    }
403
404    /// Writes the header to the given writer.
405    #[inline]
406    pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), SdWriteError> {
407        writer.write_all(&self.to_bytes_vec()?)?;
408        Ok(())
409    }
410
411    /// Writes the header to a slice.
412    #[inline]
413    pub fn write_to_slice(&self, slice: &mut [u8]) -> Result<(), SdWriteError> {
414        let buffer = self.to_bytes_vec()?;
415        if slice.len() < buffer.len() {
416            use crate::err::SdWriteError::*;
417            Err(UnexpectedEndOfSlice(buffer.len()))
418        } else {
419            // TODO figure out a better way
420            for (idx, b) in buffer.iter().enumerate() {
421                slice[idx] = *b;
422            }
423            Ok(())
424        }
425    }
426
427    /// Length of the serialized header in bytes.
428    #[inline]
429    pub fn header_len(&self) -> usize {
430        // 4*3 (flags, entries len & options len)
431        let options_len: usize = self.options.iter().map(|o| o.header_len()).sum();
432        4 * 3 + self.entries.len() * ENTRY_LEN + options_len
433    }
434
435    /// Writes the header to a slice without checking the slice length.
436    #[inline]
437    pub fn to_bytes_vec(&self) -> Result<Vec<u8>, SdValueError> {
438        // calculate memory usage
439        let entries_len = self.entries.len() * ENTRY_LEN;
440        let options_len: usize = self.options.iter().map(|o| o.header_len()).sum();
441
442        // pre-allocate the resulting buffer (4*3 for flags, entries len & options len)
443        let mut bytes = Vec::with_capacity(4 * 3 + entries_len + options_len);
444
445        // flags & reserved
446        bytes.extend_from_slice(&self.flags.to_bytes());
447        // entries len
448        bytes.extend_from_slice(&(entries_len as u32).to_be_bytes());
449
450        // entries
451        for e in &self.entries {
452            bytes.extend_from_slice(&e.to_bytes());
453        }
454
455        // options len
456        bytes.extend_from_slice(&(options_len as u32).to_be_bytes());
457        for o in &self.options {
458            o.append_bytes_to_vec(&mut bytes)?;
459        }
460
461        Ok(bytes)
462    }
463}
464
465#[derive(Clone, Debug, Eq, PartialEq)]
466pub enum SdEntry {
467    /// SOMEIP service discovery entry for a service.
468    Service(ServiceEntry),
469
470    /// SOMEIP service discovery entry for an eventgroup.
471    Eventgroup(EventgroupEntry),
472}
473
474impl From<ServiceEntry> for SdEntry {
475    #[inline]
476    fn from(e: ServiceEntry) -> Self {
477        SdEntry::Service(e)
478    }
479}
480
481impl From<EventgroupEntry> for SdEntry {
482    #[inline]
483    fn from(o: EventgroupEntry) -> Self {
484        SdEntry::Eventgroup(o)
485    }
486}
487
488impl SdEntry {
489    #[allow(clippy::too_many_arguments)]
490    pub fn new_service_entry(
491        _type: SdServiceEntryType,
492        index_first_option_run: u8,
493        index_second_option_run: u8,
494        number_of_options_1: u8,
495        number_of_options_2: u8,
496        service_id: u16,
497        instance_id: u16,
498        major_version: u8,
499        ttl: u32,
500        minor_version: u32,
501    ) -> Result<Self, SdValueError> {
502        if ttl > 0x00FF_FFFF {
503            Err(SdValueError::TtlTooLarge(ttl))
504        } else if number_of_options_1 > 0x0F {
505            Err(SdValueError::NumberOfOption1TooLarge(number_of_options_1))
506        } else if number_of_options_2 > 0x0F {
507            Err(SdValueError::NumberOfOption2TooLarge(number_of_options_2))
508        } else {
509            Ok(Self::Service(ServiceEntry {
510                _type,
511                index_first_option_run,
512                index_second_option_run,
513                number_of_options_1,
514                number_of_options_2,
515                service_id,
516                instance_id,
517                major_version,
518                ttl,
519                minor_version,
520            }))
521        }
522    }
523
524    /// Find service instances. Only use when the state of the given service is unknown.
525    /// * `service_id` - Set to 0xFFFF if all service instances should be returned.
526    /// * `instance_id` - Set to 0xFFFF if all instances should be returned.
527    /// * `major_version` - Set to 0xFF if any version should be returned.
528    /// * `minor_version` - Set to 0xFFFF_FFFF if any version should be returned.
529    /// * `ttl` - Must not be 0 as this indicates a "stop offering".
530    #[allow(clippy::too_many_arguments)]
531    pub fn new_find_service_entry(
532        index_first_option_run: u8,
533        index_second_option_run: u8,
534        number_of_options_1: u8,
535        number_of_options_2: u8,
536        service_id: u16,
537        instance_id: u16,
538        major_version: u8,
539        ttl: u32,
540        minor_version: u32,
541    ) -> Result<Self, SdValueError> {
542        if ttl == 0 {
543            Err(SdValueError::TtlZeroIndicatesStopOffering)
544        } else {
545            Self::new_service_entry(
546                SdServiceEntryType::FindService,
547                index_first_option_run,
548                index_second_option_run,
549                number_of_options_1,
550                number_of_options_2,
551                service_id,
552                instance_id,
553                major_version,
554                ttl,
555                minor_version,
556            )
557        }
558    }
559
560    /// Createa a service offer entry.
561    ///
562    /// # Errors:
563    ///
564    /// `ttl` must not be 0 as this indicates a "stop offering". If ttl
565    /// 0 is passed [`SdValueError::TtlZeroIndicatesStopOffering`] as an error
566    /// is returned.
567    #[allow(clippy::too_many_arguments)]
568    pub fn new_offer_service_entry(
569        index_first_option_run: u8,
570        index_second_option_run: u8,
571        number_of_options_1: u8,
572        number_of_options_2: u8,
573        service_id: u16,
574        instance_id: u16,
575        major_version: u8,
576        ttl: u32,
577        minor_version: u32,
578    ) -> Result<Self, SdValueError> {
579        if ttl == 0 {
580            Err(SdValueError::TtlZeroIndicatesStopOffering)
581        } else {
582            Self::new_service_entry(
583                SdServiceEntryType::OfferService,
584                index_first_option_run,
585                index_second_option_run,
586                number_of_options_1,
587                number_of_options_2,
588                service_id,
589                instance_id,
590                major_version,
591                ttl,
592                minor_version,
593            )
594        }
595    }
596
597    /// Stop offering a given service.
598    #[allow(clippy::too_many_arguments)]
599    pub fn new_stop_offer_service_entry(
600        index_first_option_run: u8,
601        index_second_option_run: u8,
602        number_of_options_1: u8,
603        number_of_options_2: u8,
604        service_id: u16,
605        instance_id: u16,
606        major_version: u8,
607        minor_version: u32,
608    ) -> Result<Self, SdValueError> {
609        Self::new_service_entry(
610            SdServiceEntryType::OfferService,
611            index_first_option_run,
612            index_second_option_run,
613            number_of_options_1,
614            number_of_options_2,
615            service_id,
616            instance_id,
617            major_version,
618            0x00,
619            minor_version,
620        )
621    }
622
623    #[allow(clippy::too_many_arguments)]
624    pub fn new_eventgroup(
625        _type: SdEventGroupEntryType,
626        index_first_option_run: u8,
627        index_second_option_run: u8,
628        number_of_options_1: u8,
629        number_of_options_2: u8,
630        service_id: u16,
631        instance_id: u16,
632        major_version: u8,
633        ttl: u32,
634        initial_data_requested: bool,
635        counter: u8,
636        eventgroup_id: u16,
637    ) -> Result<Self, SdValueError> {
638        if counter > 0x0F {
639            Err(SdValueError::CounterTooLarge(counter))
640        } else if ttl > 0x00FF_FFFF {
641            Err(SdValueError::TtlTooLarge(ttl))
642        } else if number_of_options_1 > 0x0F {
643            Err(SdValueError::NumberOfOption1TooLarge(number_of_options_1))
644        } else if number_of_options_2 > 0x0F {
645            Err(SdValueError::NumberOfOption2TooLarge(number_of_options_2))
646        } else {
647            Ok(Self::Eventgroup(EventgroupEntry {
648                _type,
649                index_first_option_run,
650                index_second_option_run,
651                number_of_options_1,
652                number_of_options_2,
653                service_id,
654                instance_id,
655                major_version,
656                ttl,
657                initial_data_requested,
658                counter,
659                eventgroup_id,
660            }))
661        }
662    }
663
664    #[inline]
665    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Self, SdReadError> {
666        let mut entry_bytes: [u8; sd_entries::ENTRY_LEN] = [0; sd_entries::ENTRY_LEN];
667        reader.read_exact(&mut entry_bytes)?;
668
669        let _type_raw = entry_bytes[0];
670        match _type_raw {
671            0x00 => Self::read_service(SdServiceEntryType::FindService, entry_bytes),
672            0x01 => Self::read_service(SdServiceEntryType::OfferService, entry_bytes),
673            0x06 => Self::read_entry_group(SdEventGroupEntryType::Subscribe, entry_bytes),
674            0x07 => Self::read_entry_group(SdEventGroupEntryType::SubscribeAck, entry_bytes),
675            _ => Err(SdReadError::UnknownSdServiceEntryType(_type_raw)),
676        }
677    }
678
679    /// Read a service entry from a byte array.
680    #[inline]
681    pub fn read_service(
682        _type: SdServiceEntryType,
683        entry_bytes: [u8; sd_entries::ENTRY_LEN],
684    ) -> Result<Self, SdReadError> {
685        //return result
686        Ok(Self::Service(ServiceEntry {
687            _type,
688            index_first_option_run: entry_bytes[1],
689            index_second_option_run: entry_bytes[2],
690            number_of_options_1: entry_bytes[3] >> 4,
691            number_of_options_2: entry_bytes[3] & 0x0F,
692            service_id: u16::from_be_bytes([entry_bytes[4], entry_bytes[5]]),
693            instance_id: u16::from_be_bytes([entry_bytes[6], entry_bytes[7]]),
694            major_version: entry_bytes[8],
695            ttl: u32::from_be_bytes([0x00, entry_bytes[9], entry_bytes[10], entry_bytes[11]]),
696            minor_version: u32::from_be_bytes([
697                entry_bytes[12],
698                entry_bytes[13],
699                entry_bytes[14],
700                entry_bytes[15],
701            ]),
702        }))
703    }
704
705    /// Read an entry group from byte array.
706    #[inline]
707    pub fn read_entry_group(
708        _type: SdEventGroupEntryType,
709        entry_bytes: [u8; sd_entries::ENTRY_LEN],
710    ) -> Result<Self, SdReadError> {
711        Ok(Self::Eventgroup(EventgroupEntry {
712            _type,
713            index_first_option_run: entry_bytes[1],
714            index_second_option_run: entry_bytes[2],
715            number_of_options_1: entry_bytes[3] >> 4,
716            number_of_options_2: entry_bytes[3] & 0x0F,
717            service_id: u16::from_be_bytes([entry_bytes[4], entry_bytes[5]]),
718            instance_id: u16::from_be_bytes([entry_bytes[6], entry_bytes[7]]),
719            major_version: entry_bytes[8],
720            ttl: u32::from_be_bytes([0x00, entry_bytes[9], entry_bytes[10], entry_bytes[11]]),
721            // skip reserved byte, TODO: should this be verified to be 0x00 ?
722            initial_data_requested: 0 != entry_bytes[13] & EVENT_ENTRY_INITIAL_DATA_REQUESTED_FLAG,
723            // ignore reserved bits, TODO: should this be verified to be 0x00 ?
724            counter: entry_bytes[13] & 0x0F,
725            eventgroup_id: u16::from_be_bytes([entry_bytes[14], entry_bytes[15]]),
726        }))
727    }
728
729    /// Writes the eventgroup entry to the given writer.
730    #[inline]
731    pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), SdWriteError> {
732        writer.write_all(&self.to_bytes())?;
733        Ok(())
734    }
735
736    ///Writes the eventgroup entry to a slice without checking the slice length.
737    #[inline]
738    pub fn to_bytes(&self) -> [u8; sd_entries::ENTRY_LEN] {
739        match self {
740            SdEntry::Eventgroup(e) => {
741                let mut result = [0x00; sd_entries::ENTRY_LEN];
742
743                result[0] = e._type.clone() as u8;
744                result[1] = e.index_first_option_run;
745                result[2] = e.index_second_option_run;
746                result[3] = (e.number_of_options_1 << 4) | (e.number_of_options_2 & 0x0F);
747
748                let service_id_bytes = e.service_id.to_be_bytes();
749                result[4] = service_id_bytes[0];
750                result[5] = service_id_bytes[1];
751
752                let instance_id_bytes = e.instance_id.to_be_bytes();
753                result[6] = instance_id_bytes[0];
754                result[7] = instance_id_bytes[1];
755
756                result[8] = e.major_version;
757
758                let ttl_bytes = e.ttl.to_be_bytes();
759                result[9] = ttl_bytes[1];
760                result[10] = ttl_bytes[2];
761                result[11] = ttl_bytes[3];
762
763                // skip reserved byte, already initialized as 0x00
764                if e.initial_data_requested {
765                    result[13] |= EVENT_ENTRY_INITIAL_DATA_REQUESTED_FLAG;
766                }
767                result[13] |= e.counter & 0x0F;
768
769                let eventgroup_id_bytes = e.eventgroup_id.to_be_bytes();
770                result[14] = eventgroup_id_bytes[0];
771                result[15] = eventgroup_id_bytes[1];
772
773                result
774            }
775            SdEntry::Service(e) => {
776                let mut result = [0x00; sd_entries::ENTRY_LEN];
777
778                result[0] = e._type.clone() as u8;
779                result[1] = e.index_first_option_run;
780                result[2] = e.index_second_option_run;
781                result[3] = (e.number_of_options_1 << 4) | (e.number_of_options_2 & 0x0F);
782
783                let service_id_bytes = e.service_id.to_be_bytes();
784                result[4] = service_id_bytes[0];
785                result[5] = service_id_bytes[1];
786
787                let instance_id_bytes = e.instance_id.to_be_bytes();
788                result[6] = instance_id_bytes[0];
789                result[7] = instance_id_bytes[1];
790
791                result[8] = e.major_version;
792
793                let ttl_bytes = e.ttl.to_be_bytes();
794                result[9] = ttl_bytes[1];
795                result[10] = ttl_bytes[2];
796                result[11] = ttl_bytes[3];
797
798                let minor_version_bytes = e.minor_version.to_be_bytes();
799                result[12] = minor_version_bytes[0];
800                result[13] = minor_version_bytes[1];
801                result[14] = minor_version_bytes[2];
802                result[15] = minor_version_bytes[3];
803
804                result
805            }
806        }
807    }
808
809    /// Length of the serialized header in bytes.
810    pub fn header_len(&self) -> usize {
811        4 * 4
812    }
813}
814
815#[derive(Clone, Debug, Eq, PartialEq)]
816pub enum SdServiceEntryType {
817    FindService = 0x00,
818    OfferService = 0x01,
819}
820
821#[derive(Clone, Debug, Eq, PartialEq)]
822pub enum SdEventGroupEntryType {
823    Subscribe = 0x06,
824    SubscribeAck = 0x07,
825}
826
827#[derive(Clone, Debug, Eq, PartialEq)]
828pub enum SdOptionType {
829    Configuration = 0x01,
830    LoadBalancing = 0x02,
831    Ipv4Endpoint = 0x04,
832    Ipv6Endpoint = 0x06,
833    Ipv4Multicast = 0x14,
834    Ipv6Multicast = 0x16,
835    Ipv4SdEndpoint = 0x24,
836    Ipv6SdEndpoint = 0x26,
837}
838
839/// Protocol numbers based on IANA/IETF
840#[derive(Copy, Clone, Debug, Eq, PartialEq)]
841pub enum TransportProtocol {
842    Tcp,
843    Udp,
844    Generic(u8),
845}
846
847impl From<TransportProtocol> for u8 {
848    fn from(tp: TransportProtocol) -> u8 {
849        match tp {
850            TransportProtocol::Tcp => 0x06,
851            TransportProtocol::Udp => 0x11,
852            TransportProtocol::Generic(tp) => tp,
853        }
854    }
855}
856
857#[cfg(test)]
858mod test_transport_protocol {
859    use proptest::prelude::*;
860    proptest! {
861        #[test]
862        fn from_u8(argu8 in any::<u8>()) {
863            use super::TransportProtocol::*;
864            assert_eq!(u8::from(Tcp), 0x06);
865            assert_eq!(u8::from(Udp), 0x11);
866            assert_eq!(u8::from(Generic(argu8)), argu8);
867        }
868    }
869}
870
871#[derive(Clone, Debug, Eq, PartialEq)]
872pub enum SdOption {
873    ///Arbitrary configuration strings.
874    Configuration(ConfigurationOption),
875    LoadBalancing(LoadBalancingOption),
876    Ipv4Endpoint(Ipv4EndpointOption),
877    Ipv6Endpoint(Ipv6EndpointOption),
878    Ipv4Multicast(Ipv4MulticastOption),
879    Ipv6Multicast(Ipv6MulticastOption),
880    Ipv4SdEndpoint(Ipv4SdEndpointOption),
881    Ipv6SdEndpoint(Ipv6SdEndpointOption),
882    /// An unknown option that is flagged as "discardable" and
883    /// should be ignored by the receiver if not supported.
884    ///
885    /// This option is only intended to be used for reading,
886    /// to ensure the option indices are still matching. In case
887    /// this option is passed to a write function an error will be
888    /// triggered.
889    UnknownDiscardable(UnknownDiscardableOption),
890}
891
892impl From<ConfigurationOption> for SdOption {
893    #[inline]
894    fn from(o: ConfigurationOption) -> Self {
895        SdOption::Configuration(o)
896    }
897}
898
899impl From<LoadBalancingOption> for SdOption {
900    #[inline]
901    fn from(o: LoadBalancingOption) -> Self {
902        SdOption::LoadBalancing(o)
903    }
904}
905
906impl From<Ipv4EndpointOption> for SdOption {
907    #[inline]
908    fn from(o: Ipv4EndpointOption) -> Self {
909        SdOption::Ipv4Endpoint(o)
910    }
911}
912
913impl From<Ipv6EndpointOption> for SdOption {
914    #[inline]
915    fn from(o: Ipv6EndpointOption) -> Self {
916        SdOption::Ipv6Endpoint(o)
917    }
918}
919
920impl From<Ipv4MulticastOption> for SdOption {
921    #[inline]
922    fn from(o: Ipv4MulticastOption) -> Self {
923        SdOption::Ipv4Multicast(o)
924    }
925}
926
927impl From<Ipv6MulticastOption> for SdOption {
928    #[inline]
929    fn from(o: Ipv6MulticastOption) -> Self {
930        SdOption::Ipv6Multicast(o)
931    }
932}
933
934impl From<Ipv4SdEndpointOption> for SdOption {
935    #[inline]
936    fn from(o: Ipv4SdEndpointOption) -> Self {
937        SdOption::Ipv4SdEndpoint(o)
938    }
939}
940
941impl From<Ipv6SdEndpointOption> for SdOption {
942    #[inline]
943    fn from(o: Ipv6SdEndpointOption) -> Self {
944        SdOption::Ipv6SdEndpoint(o)
945    }
946}
947
948impl From<UnknownDiscardableOption> for SdOption {
949    #[inline]
950    fn from(o: UnknownDiscardableOption) -> Self {
951        SdOption::UnknownDiscardable(o)
952    }
953}
954
955impl SdOption {
956    /// Read the value from a [`std::io::Read`] source.
957    #[inline]
958    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<(u16, Self), SdReadError> {
959        SdOption::read_with_flag(reader, false)
960    }
961
962    /// Read the value from a [`std::io::Read`] source.
963    #[inline]
964    pub fn read_with_flag<T: Read + Seek>(
965        reader: &mut T,
966        discard_unknown_option: bool,
967    ) -> Result<(u16, Self), SdReadError> {
968        use self::sd_options::*;
969        use self::SdOption::*;
970        use SdReadError::*;
971
972        let mut option_bytes: [u8; 4] = [0; 4];
973        reader.read_exact(&mut option_bytes)?;
974
975        let length = u16::from_be_bytes([option_bytes[0], option_bytes[1]]);
976        if length < 1 {
977            return Err(SdOptionLengthZero);
978        }
979
980        let type_raw = option_bytes[2];
981        // reserved byte
982        let discardable = 0 != option_bytes[3] & DISCARDABLE_FLAG;
983
984        // Helper function that returns an SdOptionUnexpectedLen error
985        // when the expected_len does not match the len.
986        let expect_len = |expected_len: u16| -> Result<(), SdReadError> {
987            if expected_len == length {
988                Ok(())
989            } else {
990                Err(SdOptionUnexpectedLen {
991                    expected_len,
992                    actual_len: length,
993                    option_type: type_raw,
994                })
995            }
996        };
997
998        let option = match type_raw {
999            // Configuration
1000            CONFIGURATION_TYPE => {
1001                let length_array = (length - 1) as usize;
1002                let mut configuration_string = Vec::with_capacity(length_array);
1003                reader
1004                    .take(length_array as u64)
1005                    .read_to_end(&mut configuration_string)?;
1006                Configuration(ConfigurationOption {
1007                    discardable,
1008                    configuration_string,
1009                })
1010            }
1011            LOAD_BALANCING_TYPE => {
1012                expect_len(LOAD_BALANCING_LEN)?;
1013
1014                let mut load_balancing_bytes: [u8; 4] = [0; 4];
1015                reader.read_exact(&mut load_balancing_bytes)?;
1016                LoadBalancing(LoadBalancingOption {
1017                    discardable,
1018                    priority: u16::from_be_bytes([
1019                        load_balancing_bytes[0],
1020                        load_balancing_bytes[1],
1021                    ]),
1022                    weight: u16::from_be_bytes([load_balancing_bytes[2], load_balancing_bytes[3]]),
1023                })
1024            }
1025            IPV4_ENDPOINT_TYPE => {
1026                expect_len(IPV4_ENDPOINT_LEN)?;
1027
1028                let (ipv4_address, transport_protocol, port) = Self::read_ip4_option(reader)?;
1029                Ipv4Endpoint(Ipv4EndpointOption {
1030                    ipv4_address,
1031                    transport_protocol,
1032                    port,
1033                })
1034            }
1035            IPV6_ENDPOINT_TYPE => {
1036                expect_len(IPV6_ENDPOINT_LEN)?;
1037
1038                let (ipv6_address, transport_protocol, port) = Self::read_ip6_option(reader)?;
1039                Ipv6Endpoint(Ipv6EndpointOption {
1040                    ipv6_address,
1041                    transport_protocol,
1042                    port,
1043                })
1044            }
1045            IPV4_MULTICAST_TYPE => {
1046                expect_len(IPV4_MULTICAST_LEN)?;
1047
1048                let (ipv4_address, transport_protocol, port) = Self::read_ip4_option(reader)?;
1049                Ipv4Multicast(Ipv4MulticastOption {
1050                    ipv4_address,
1051                    transport_protocol,
1052                    port,
1053                })
1054            }
1055            IPV6_MULTICAST_TYPE => {
1056                expect_len(IPV6_MULTICAST_LEN)?;
1057
1058                let (ipv6_address, transport_protocol, port) = Self::read_ip6_option(reader)?;
1059                Ipv6Multicast(Ipv6MulticastOption {
1060                    ipv6_address,
1061                    transport_protocol,
1062                    port,
1063                })
1064            }
1065            IPV4_SD_ENDPOINT_TYPE => {
1066                expect_len(IPV4_SD_ENDPOINT_LEN)?;
1067
1068                let (ipv4_address, transport_protocol, port) = Self::read_ip4_option(reader)?;
1069                Ipv4SdEndpoint(Ipv4SdEndpointOption {
1070                    ipv4_address,
1071                    transport_protocol,
1072                    port,
1073                })
1074            }
1075            IPV6_SD_ENDPOINT_TYPE => {
1076                expect_len(IPV6_SD_ENDPOINT_LEN)?;
1077
1078                let (ipv6_address, transport_protocol, port) = Self::read_ip6_option(reader)?;
1079                Ipv6SdEndpoint(Ipv6SdEndpointOption {
1080                    ipv6_address,
1081                    transport_protocol,
1082                    port,
1083                })
1084            }
1085            option_type => {
1086                if discardable || discard_unknown_option {
1087                    // skip unknown options payload if "discardable"
1088                    // if length is greater then 1 then we need to skip the rest of the option
1089                    // (note that we already read length 1 as this contains the "discardable"
1090                    // flag)
1091                    if length > 1 {
1092                        // first seek past the payload (except for one byte)
1093                        if length > 2 {
1094                            reader.seek(std::io::SeekFrom::Current(i64::from(length) - 2))?;
1095                        }
1096                        // do a final read to trigger io errors in case they occur
1097                        //
1098                        // NOTE: Seek does not trigger io errors if the end of the file
1099                        // is reached. Instead it silently fails and just sits there.
1100                        // We still want to trigger io::Errors so don't remove this read.
1101                        let mut buf = [0; 1];
1102                        reader.read_exact(&mut buf)?;
1103                    }
1104
1105                    // return a dummy entry so the option indices are not shifted
1106                    UnknownDiscardable(UnknownDiscardableOption {
1107                        length,
1108                        option_type,
1109                    })
1110                } else {
1111                    return Err(UnknownSdOptionType(option_type));
1112                }
1113            }
1114        };
1115        Ok((3 + length, option))
1116    }
1117
1118    #[inline]
1119    fn read_ip4_option<T: Read>(
1120        reader: &mut T,
1121    ) -> Result<([u8; 4], TransportProtocol, u16), SdReadError> {
1122        let mut ipv4endpoint_bytes: [u8; 8] = [0; 8];
1123        reader.read_exact(&mut ipv4endpoint_bytes)?;
1124
1125        // ignore reserved byte
1126        let ipv4_address = [
1127            ipv4endpoint_bytes[0],
1128            ipv4endpoint_bytes[1],
1129            ipv4endpoint_bytes[2],
1130            ipv4endpoint_bytes[3],
1131        ];
1132        // ignore reserved byte
1133        let transport_protocol_raw = ipv4endpoint_bytes[5];
1134        let transport_protocol = match transport_protocol_raw {
1135            0x06 => TransportProtocol::Tcp,
1136            0x11 => TransportProtocol::Udp,
1137            other => TransportProtocol::Generic(other),
1138        };
1139
1140        let transport_protocol_number =
1141            u16::from_be_bytes([ipv4endpoint_bytes[6], ipv4endpoint_bytes[7]]);
1142
1143        Ok((ipv4_address, transport_protocol, transport_protocol_number))
1144    }
1145
1146    #[inline]
1147    fn read_ip6_option<T: Read>(
1148        reader: &mut T,
1149    ) -> Result<([u8; 16], TransportProtocol, u16), SdReadError> {
1150        let mut ipv6endpoint_bytes: [u8; 20] = [0; 20];
1151        reader.read_exact(&mut ipv6endpoint_bytes)?;
1152
1153        // ignore reserved byte
1154        let ipv6_address = [
1155            ipv6endpoint_bytes[0],
1156            ipv6endpoint_bytes[1],
1157            ipv6endpoint_bytes[2],
1158            ipv6endpoint_bytes[3],
1159            ipv6endpoint_bytes[4],
1160            ipv6endpoint_bytes[5],
1161            ipv6endpoint_bytes[6],
1162            ipv6endpoint_bytes[7],
1163            ipv6endpoint_bytes[8],
1164            ipv6endpoint_bytes[9],
1165            ipv6endpoint_bytes[10],
1166            ipv6endpoint_bytes[11],
1167            ipv6endpoint_bytes[12],
1168            ipv6endpoint_bytes[13],
1169            ipv6endpoint_bytes[14],
1170            ipv6endpoint_bytes[15],
1171        ];
1172        // ignore reserved byte
1173        let transport_protocol_raw = ipv6endpoint_bytes[17];
1174        let transport_protocol = match transport_protocol_raw {
1175            0x06 => TransportProtocol::Tcp,
1176            0x11 => TransportProtocol::Udp,
1177            other => TransportProtocol::Generic(other),
1178        };
1179
1180        let transport_protocol_number =
1181            u16::from_be_bytes([ipv6endpoint_bytes[18], ipv6endpoint_bytes[19]]);
1182
1183        Ok((ipv6_address, transport_protocol, transport_protocol_number))
1184    }
1185
1186    /// Writes the eventgroup entry to the given writer.
1187    #[inline]
1188    pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), SdWriteError> {
1189        use self::sd_options::*;
1190        use self::SdOption::*;
1191
1192        fn write_ipv4<R: Write>(
1193            writer: &mut R,
1194            len: u16,
1195            t: u8,
1196            addr: [u8; 4],
1197            tp: TransportProtocol,
1198            port: u16,
1199        ) -> Result<(), SdWriteError> {
1200            let len_be = len.to_be_bytes();
1201            let port_be = port.to_be_bytes();
1202            writer.write_all(&[
1203                len_be[0],
1204                len_be[1],
1205                t,
1206                0,
1207                addr[0],
1208                addr[1],
1209                addr[2],
1210                addr[3],
1211                0,
1212                tp.into(),
1213                port_be[0],
1214                port_be[1],
1215            ])?;
1216            Ok(())
1217        }
1218
1219        fn write_ipv6<R: Write>(
1220            writer: &mut R,
1221            len: u16,
1222            t: u8,
1223            addr: [u8; 16],
1224            tp: TransportProtocol,
1225            port: u16,
1226        ) -> Result<(), SdWriteError> {
1227            let len_be = len.to_be_bytes();
1228            let port_be = port.to_be_bytes();
1229            writer.write_all(&[
1230                len_be[0],
1231                len_be[1],
1232                t,
1233                0,
1234                addr[0],
1235                addr[1],
1236                addr[2],
1237                addr[3],
1238                addr[4],
1239                addr[5],
1240                addr[6],
1241                addr[7],
1242                addr[8],
1243                addr[9],
1244                addr[10],
1245                addr[11],
1246                addr[12],
1247                addr[13],
1248                addr[14],
1249                addr[15],
1250                0,
1251                tp.into(),
1252                port_be[0],
1253                port_be[1],
1254            ])?;
1255            Ok(())
1256        }
1257
1258        match self {
1259            Configuration(c) => {
1260                let len_be = (1u16 + c.configuration_string.len() as u16).to_be_bytes();
1261                writer.write_all(&[
1262                    len_be[0],
1263                    len_be[1],
1264                    CONFIGURATION_TYPE,
1265                    if c.discardable { DISCARDABLE_FLAG } else { 0 },
1266                ])?;
1267                writer.write_all(&c.configuration_string)?;
1268                Ok(())
1269            }
1270            LoadBalancing(o) => {
1271                let len_be = LOAD_BALANCING_LEN.to_be_bytes();
1272                let prio_be = o.priority.to_be_bytes();
1273                let weight_be = o.weight.to_be_bytes();
1274
1275                writer.write_all(&[
1276                    len_be[0],
1277                    len_be[1],
1278                    LOAD_BALANCING_TYPE,
1279                    if o.discardable { DISCARDABLE_FLAG } else { 0 },
1280                    prio_be[0],
1281                    prio_be[1],
1282                    weight_be[0],
1283                    weight_be[1],
1284                ])?;
1285                Ok(())
1286            }
1287            Ipv4Endpoint(o) => write_ipv4(
1288                writer,
1289                IPV4_ENDPOINT_LEN,
1290                IPV4_ENDPOINT_TYPE,
1291                o.ipv4_address,
1292                o.transport_protocol,
1293                o.port,
1294            ),
1295            Ipv6Endpoint(o) => write_ipv6(
1296                writer,
1297                IPV6_ENDPOINT_LEN,
1298                IPV6_ENDPOINT_TYPE,
1299                o.ipv6_address,
1300                o.transport_protocol,
1301                o.port,
1302            ),
1303            Ipv4Multicast(o) => write_ipv4(
1304                writer,
1305                IPV4_MULTICAST_LEN,
1306                IPV4_MULTICAST_TYPE,
1307                o.ipv4_address,
1308                o.transport_protocol,
1309                o.port,
1310            ),
1311            Ipv6Multicast(o) => write_ipv6(
1312                writer,
1313                IPV6_MULTICAST_LEN,
1314                IPV6_MULTICAST_TYPE,
1315                o.ipv6_address,
1316                o.transport_protocol,
1317                o.port,
1318            ),
1319            Ipv4SdEndpoint(o) => write_ipv4(
1320                writer,
1321                IPV4_SD_ENDPOINT_LEN,
1322                IPV4_SD_ENDPOINT_TYPE,
1323                o.ipv4_address,
1324                o.transport_protocol,
1325                o.port,
1326            ),
1327            Ipv6SdEndpoint(o) => write_ipv6(
1328                writer,
1329                IPV6_SD_ENDPOINT_LEN,
1330                IPV6_SD_ENDPOINT_TYPE,
1331                o.ipv6_address,
1332                o.transport_protocol,
1333                o.port,
1334            ),
1335            UnknownDiscardable(o) => Err(SdWriteError::ValueError(
1336                SdValueError::SdUnknownDiscardableOption(o.option_type),
1337            )),
1338        }
1339    }
1340
1341    /// Serializes option and append data to a vec
1342    pub fn append_bytes_to_vec(&self, buffer: &mut Vec<u8>) -> Result<(), SdValueError> {
1343        use self::sd_options::*;
1344        use self::SdOption::*;
1345
1346        fn append_ip4(
1347            buffer: &mut Vec<u8>,
1348            ipv4_address: [u8; 4],
1349            transport_protocol: TransportProtocol,
1350            port: u16,
1351        ) {
1352            buffer.extend_from_slice(&ipv4_address);
1353            buffer.push(0x00); // reserved
1354            buffer.push(transport_protocol.into());
1355            buffer.extend_from_slice(&port.to_be_bytes());
1356        }
1357
1358        fn append_ip6(
1359            buffer: &mut Vec<u8>,
1360            ipv6_address: [u8; 16],
1361            transport_protocol: TransportProtocol,
1362            port: u16,
1363        ) {
1364            buffer.extend_from_slice(&ipv6_address);
1365            buffer.push(0x00); // reserved
1366            buffer.push(transport_protocol.into());
1367            buffer.extend_from_slice(&port.to_be_bytes());
1368        }
1369
1370        match self {
1371            Configuration(o) => {
1372                // + 1 for reserved byte
1373                let length_bytes = (1u16 + o.configuration_string.len() as u16).to_be_bytes();
1374                buffer.extend_from_slice(&length_bytes);
1375                buffer.push(CONFIGURATION_TYPE);
1376                buffer.push(if o.discardable { DISCARDABLE_FLAG } else { 0 });
1377                buffer.extend_from_slice(&o.configuration_string);
1378            }
1379            LoadBalancing(o) => {
1380                buffer.extend_from_slice(&LOAD_BALANCING_LEN.to_be_bytes());
1381                buffer.push(LOAD_BALANCING_TYPE);
1382                buffer.push(if o.discardable { DISCARDABLE_FLAG } else { 0 });
1383                buffer.extend_from_slice(&o.priority.to_be_bytes());
1384                buffer.extend_from_slice(&o.weight.to_be_bytes());
1385            }
1386            Ipv4Endpoint(o) => {
1387                buffer.extend_from_slice(&IPV4_ENDPOINT_LEN.to_be_bytes());
1388                buffer.push(IPV4_ENDPOINT_TYPE);
1389                buffer.push(0x00u8); // Reserved byte
1390                append_ip4(buffer, o.ipv4_address, o.transport_protocol, o.port);
1391            }
1392            Ipv6Endpoint(o) => {
1393                buffer.extend_from_slice(&IPV6_ENDPOINT_LEN.to_be_bytes());
1394                buffer.push(IPV6_ENDPOINT_TYPE); // Type
1395                buffer.push(0x00u8); // Reserved byte
1396                append_ip6(buffer, o.ipv6_address, o.transport_protocol, o.port);
1397            }
1398            Ipv4Multicast(o) => {
1399                buffer.extend_from_slice(&IPV4_MULTICAST_LEN.to_be_bytes());
1400                buffer.push(IPV4_MULTICAST_TYPE); // Type
1401                buffer.push(0x00u8); // Reserved byte
1402                append_ip4(buffer, o.ipv4_address, o.transport_protocol, o.port);
1403            }
1404            Ipv6Multicast(o) => {
1405                buffer.extend_from_slice(&IPV6_MULTICAST_LEN.to_be_bytes());
1406                buffer.push(IPV6_MULTICAST_TYPE); // Type
1407                buffer.push(0x00u8); // Reserved byte
1408                append_ip6(buffer, o.ipv6_address, o.transport_protocol, o.port);
1409            }
1410            Ipv4SdEndpoint(o) => {
1411                buffer.extend_from_slice(&IPV4_SD_ENDPOINT_LEN.to_be_bytes());
1412                buffer.push(IPV4_SD_ENDPOINT_TYPE);
1413                buffer.push(0x00u8); // Reserved byte
1414                append_ip4(buffer, o.ipv4_address, o.transport_protocol, o.port);
1415            }
1416            Ipv6SdEndpoint(o) => {
1417                buffer.extend_from_slice(&IPV6_SD_ENDPOINT_LEN.to_be_bytes());
1418                buffer.push(IPV6_SD_ENDPOINT_TYPE); // Type
1419                buffer.push(0x00u8); // Reserved byte
1420                append_ip6(buffer, o.ipv6_address, o.transport_protocol, o.port);
1421            }
1422            UnknownDiscardable(o) => {
1423                return Err(SdValueError::SdUnknownDiscardableOption(o.option_type));
1424            }
1425        }
1426        Ok(())
1427    }
1428
1429    /// Length of the serialized header in bytes.
1430    #[inline]
1431    pub fn header_len(&self) -> usize {
1432        use self::sd_options::*;
1433        use self::SdOption::*;
1434
1435        3 + match self {
1436            Configuration(o) => 1 + o.configuration_string.len(),
1437            LoadBalancing(_) => usize::from(LOAD_BALANCING_LEN),
1438            Ipv4Endpoint(_) => usize::from(IPV4_ENDPOINT_LEN),
1439            Ipv6Endpoint(_) => usize::from(IPV6_ENDPOINT_LEN),
1440            Ipv4Multicast(_) => usize::from(IPV4_MULTICAST_LEN),
1441            Ipv6Multicast(_) => usize::from(IPV6_MULTICAST_LEN),
1442            Ipv4SdEndpoint(_) => usize::from(IPV4_SD_ENDPOINT_LEN),
1443            Ipv6SdEndpoint(_) => usize::from(IPV6_SD_ENDPOINT_LEN),
1444            UnknownDiscardable(o) => usize::from(o.length),
1445        }
1446    }
1447}
1448
1449#[cfg(test)]
1450mod tests_sd_header {
1451
1452    use super::*;
1453    use crate::proptest_generators::*;
1454    use assert_matches::*;
1455    use proptest::prelude::*;
1456    use std::io::Cursor;
1457
1458    proptest! {
1459        #[test]
1460        fn write_read(header in sd_header_any()) {
1461
1462            //non error case
1463            {
1464                //serialize
1465                let mut buffer: [u8; 10000] = [0; 10000];
1466                header.write_to_slice(&mut buffer).unwrap();
1467
1468                //deserialize
1469                let mut cursor = Cursor::new(&buffer);
1470                let result = SdHeader::read(&mut cursor).unwrap();
1471                assert_eq!(header, result);
1472            }
1473        }
1474    }
1475
1476    #[test]
1477    fn read() {
1478        // entries array length too large error
1479        for len in [sd_entries::MAX_ENTRIES_LEN + 1, u32::MAX] {
1480            let len_be = len.to_be_bytes();
1481            let buffer = [
1482                0, 0, 0, 0, // flags
1483                len_be[0], len_be[1], len_be[2], len_be[3], 0, 0, 0, 0,
1484            ];
1485            let mut cursor = Cursor::new(&buffer);
1486            assert_matches!(
1487                SdHeader::read(&mut cursor),
1488                Err(SdReadError::SdEntriesArrayLengthTooLarge(_))
1489            );
1490        }
1491
1492        // options array length too large error
1493        for len in [sd_options::MAX_OPTIONS_LEN + 1, u32::MAX] {
1494            let len_be = len.to_be_bytes();
1495            let buffer = [
1496                0, 0, 0, 0, // flags
1497                0, 0, 0, 0, // entries array length
1498                len_be[0], len_be[1], len_be[2], len_be[3], 0, 0, 0, 0,
1499            ];
1500            let mut cursor = Cursor::new(&buffer);
1501            assert_matches!(
1502                SdHeader::read(&mut cursor),
1503                Err(SdReadError::SdOptionsArrayLengthTooLarge(_))
1504            );
1505        }
1506    }
1507}
1508
1509#[cfg(test)]
1510mod tests_sd_entry {
1511
1512    use super::*;
1513    use crate::proptest_generators::*;
1514    use proptest::prelude::*;
1515    use std::io::Cursor;
1516
1517    proptest! {
1518        #[test]
1519        fn write_read(service_entry in someip_sd_entry_any()) {
1520
1521            //write
1522            let mut buffer = Vec::new();
1523            service_entry.write(&mut buffer).unwrap();
1524
1525            //read
1526            let mut cursor = Cursor::new(&buffer);
1527            let result = SdEntry::read(&mut cursor).unwrap();
1528            assert_eq!(service_entry, result);
1529        }
1530    }
1531}
1532
1533#[cfg(test)]
1534mod tests_sd_option {
1535
1536    use super::*;
1537    use crate::proptest_generators::*;
1538    use assert_matches::*;
1539    use proptest::prelude::*;
1540    use std::io::Cursor;
1541
1542    proptest! {
1543        #[test]
1544        fn write_read(option in someip_sd_option_any()) {
1545
1546            //write
1547            let mut buffer = Vec::with_capacity(option.header_len());
1548            option.write(&mut buffer).unwrap();
1549
1550            //read
1551            let mut cursor = Cursor::new(&buffer);
1552            let (read_len, result) = SdOption::read(&mut cursor).unwrap();
1553            assert_eq!(buffer.len() as u16, read_len);
1554            assert_eq!(option, result);
1555        }
1556    }
1557
1558    #[test]
1559    fn read() {
1560        use sd_options::*;
1561        // too small length error
1562        {
1563            let buffer = [0x00, 0x00, IPV4_ENDPOINT_TYPE, 0x00];
1564            let mut cursor = std::io::Cursor::new(buffer);
1565            let result = SdOption::read(&mut cursor);
1566            assert_matches!(result, Err(SdReadError::SdOptionLengthZero));
1567        }
1568        // ipv4 length check errors
1569        for t in [
1570            IPV4_ENDPOINT_TYPE,
1571            IPV4_MULTICAST_TYPE,
1572            IPV4_SD_ENDPOINT_TYPE,
1573        ] {
1574            let buffer = [0x00, 0x01, t, 0x00];
1575            let mut cursor = std::io::Cursor::new(buffer);
1576            let result = SdOption::read(&mut cursor);
1577            assert_matches!(
1578                result,
1579                Err(SdReadError::SdOptionUnexpectedLen {
1580                    expected_len: 0x9,
1581                    actual_len: 0x1,
1582                    option_type: _,
1583                })
1584            );
1585        }
1586        // ipv6 length check errors
1587        for t in [
1588            IPV6_ENDPOINT_TYPE,
1589            IPV6_MULTICAST_TYPE,
1590            IPV6_SD_ENDPOINT_TYPE,
1591        ] {
1592            let buffer = [0x00, 0x01, t, 0x00];
1593            let mut cursor = std::io::Cursor::new(buffer);
1594            let result = SdOption::read(&mut cursor);
1595            assert_matches!(
1596                result,
1597                Err(SdReadError::SdOptionUnexpectedLen {
1598                    expected_len: 0x15,
1599                    actual_len: 0x1,
1600                    option_type: _,
1601                })
1602            );
1603        }
1604        // unknown option type (non discardable)
1605        {
1606            let buffer = [0x00, 0x01, 0xff, 0x00];
1607            let mut cursor = std::io::Cursor::new(buffer);
1608            let result = SdOption::read(&mut cursor);
1609            assert_matches!(result, Err(SdReadError::UnknownSdOptionType(0xFF)));
1610        }
1611        // unknown option type (non discardable, discard option set)
1612        {
1613            let buffer = [0x00, 0x01, 0xff, 0x00];
1614            let mut cursor = std::io::Cursor::new(buffer);
1615            let (len, header) = SdOption::read_with_flag(&mut cursor, true).unwrap();
1616            assert_eq!(
1617                header,
1618                UnknownDiscardableOption {
1619                    length: 1,
1620                    option_type: 0xff,
1621                }
1622                .into()
1623            );
1624            assert_eq!(4, len);
1625        }
1626        // unknown option type (discardable)
1627        {
1628            let buffer = [0x00, 0x01, 0xff, 0b1000_0000];
1629            let mut cursor = std::io::Cursor::new(buffer);
1630            let (len, header) = SdOption::read(&mut cursor).unwrap();
1631            assert_eq!(
1632                header,
1633                UnknownDiscardableOption {
1634                    length: 1,
1635                    option_type: 0xff,
1636                }
1637                .into()
1638            );
1639            assert_eq!(4, len);
1640        }
1641    }
1642}
1643
1644#[test]
1645fn sd_header_write_unexpected_end_of_slice() {
1646    use assert_matches::*;
1647
1648    let header = SdHeader::default();
1649    let result = header.write_to_slice(&mut []);
1650    assert_matches!(result, Err(SdWriteError::UnexpectedEndOfSlice(_)));
1651}
1652
1653#[test]
1654fn service_entry_read_unknown_service_entry_type() {
1655    use assert_matches::*;
1656
1657    let mut buffer = [0x00; sd_entries::ENTRY_LEN];
1658    buffer[0] = 0xFF; // Unknown Type
1659    let mut cursor = std::io::Cursor::new(buffer);
1660    let result = SdEntry::read(&mut cursor);
1661    assert_matches!(result, Err(SdReadError::UnknownSdServiceEntryType(0xFF)));
1662}
1663
1664#[test]
1665fn new_service_entry_ttl_too_large() {
1666    use assert_matches::*;
1667
1668    let result = SdEntry::new_service_entry(
1669        SdServiceEntryType::OfferService,
1670        0,
1671        0,
1672        0,
1673        0,
1674        0,
1675        0,
1676        0,
1677        0xFFFF_FFFF,
1678        0,
1679    );
1680    assert_matches!(result, Err(SdValueError::TtlTooLarge(0xFFFF_FFFF)));
1681}
1682
1683#[test]
1684fn new_service_entry_number_option1_too_large() {
1685    use assert_matches::*;
1686
1687    let result = SdEntry::new_service_entry(
1688        SdServiceEntryType::OfferService,
1689        0,
1690        0,
1691        0xFF,
1692        0,
1693        0,
1694        0,
1695        0,
1696        0,
1697        0,
1698    );
1699    assert_matches!(result, Err(SdValueError::NumberOfOption1TooLarge(0xFF)));
1700}
1701
1702#[test]
1703fn new_service_entry_number_option2_too_large() {
1704    use assert_matches::*;
1705
1706    let result = SdEntry::new_service_entry(
1707        SdServiceEntryType::OfferService,
1708        0,
1709        0,
1710        0,
1711        0xFF,
1712        0,
1713        0,
1714        0,
1715        0,
1716        0,
1717    );
1718    assert_matches!(result, Err(SdValueError::NumberOfOption2TooLarge(0xFF)));
1719}
1720
1721#[test]
1722fn new_service_find_service_entry_zero_ttl() {
1723    use assert_matches::*;
1724
1725    let result = SdEntry::new_find_service_entry(0, 0, 0, 0, 0, 0, 0, 0, 0);
1726    assert_matches!(result, Err(SdValueError::TtlZeroIndicatesStopOffering));
1727}
1728
1729#[test]
1730fn new_service_offer_service_entry_zero_ttl() {
1731    use assert_matches::*;
1732
1733    let result = SdEntry::new_offer_service_entry(0, 0, 0, 0, 0, 0, 0, 0, 0);
1734    assert_matches!(result, Err(SdValueError::TtlZeroIndicatesStopOffering));
1735}