Skip to main content

simple_someip/protocol/sd/
header.rs

1use std::net::Ipv4Addr;
2
3use crate::protocol::byte_order::{ReadBytesExt, WriteBytesExt};
4
5use crate::{protocol::Error, traits::WireFormat};
6
7use super::{
8    Entry, EventGroupEntry, Flags, Options, ServiceEntry, TransportProtocol,
9    entry::{ENTRY_SIZE, OptionsCount},
10};
11
12/// Default maximum number of SD entries in a single header.
13pub const MAX_SD_ENTRIES: usize = 1;
14/// Default maximum number of SD options in a single header.
15pub const MAX_SD_OPTIONS: usize = 1;
16
17pub type SdEntries<const N: usize = MAX_SD_ENTRIES> = heapless::Vec<Entry, N>;
18pub type SdOptions<const N: usize = MAX_SD_OPTIONS> = heapless::Vec<Options, N>;
19
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct Header<
22    const MAX_ENTRIES: usize = MAX_SD_ENTRIES,
23    const MAX_OPTIONS: usize = MAX_SD_OPTIONS,
24> {
25    pub flags: Flags,
26    pub entries: SdEntries<MAX_ENTRIES>,
27    pub options: SdOptions<MAX_OPTIONS>,
28}
29
30impl<const E: usize, const O: usize> Header<E, O> {
31    #[must_use]
32    pub fn new(flags: Flags, entries: SdEntries<E>, options: SdOptions<O>) -> Self {
33        Self {
34            flags,
35            entries,
36            options,
37        }
38    }
39
40    #[allow(clippy::too_many_arguments)]
41    #[must_use]
42    pub fn new_service_offer(
43        service_id: u16,
44        instance_id: u16,
45        major_version: u8,
46        minor_version: u32,
47        ttl: u32,
48        client_ip: Ipv4Addr,
49        protocol: TransportProtocol,
50        client_port: u16,
51    ) -> Self {
52        let entry = Entry::OfferService(ServiceEntry {
53            service_id,
54            instance_id,
55            major_version,
56            ttl,
57            index_first_options_run: 0,
58            index_second_options_run: 0,
59            options_count: OptionsCount::new(1, 0),
60            minor_version,
61        });
62        let endpoint = Options::IpV4Endpoint {
63            ip: client_ip,
64            protocol,
65            port: client_port,
66        };
67        let mut entries = SdEntries::new();
68        let mut options = SdOptions::new();
69        entries
70            .push(entry)
71            .expect("single SD entry exceeds capacity");
72        options
73            .push(endpoint)
74            .expect("single SD option exceeds capacity");
75        Self {
76            flags: Flags::new_sd(false),
77            entries,
78            options,
79        }
80    }
81
82    /// # Panics
83    /// Panics if `service_ids` has more than `E` elements.
84    #[must_use]
85    pub fn new_find_services(reboot: bool, service_ids: &[u16]) -> Self {
86        let mut entries = SdEntries::new();
87        for service_id in service_ids {
88            entries
89                .push(Entry::FindService(ServiceEntry::find(*service_id)))
90                .expect("too many service IDs for SD header");
91        }
92        Self {
93            flags: Flags::new_sd(reboot),
94            entries,
95            options: SdOptions::new(),
96        }
97    }
98
99    #[allow(clippy::too_many_arguments)]
100    #[must_use]
101    pub fn new_subscription(
102        service_id: u16,
103        instance_id: u16,
104        major_version: u8,
105        ttl: u32,
106        event_group_id: u16,
107        client_ip: Ipv4Addr,
108        protocol: TransportProtocol,
109        client_port: u16,
110    ) -> Self {
111        let entry = Entry::SubscribeEventGroup(EventGroupEntry::new(
112            service_id,
113            instance_id,
114            major_version,
115            ttl,
116            event_group_id,
117        ));
118        let endpoint = Options::IpV4Endpoint {
119            ip: client_ip,
120            protocol,
121            port: client_port,
122        };
123        let mut entries = SdEntries::new();
124        let mut options = SdOptions::new();
125        entries
126            .push(entry)
127            .expect("single SD entry exceeds capacity");
128        options
129            .push(endpoint)
130            .expect("single SD option exceeds capacity");
131        Self {
132            flags: Flags::new_sd(false),
133            entries,
134            options,
135        }
136    }
137
138    #[must_use]
139    pub fn subscribe_ack(
140        service_id: u16,
141        instance_id: u16,
142        major_version: u8,
143        ttl: u32,
144        event_group_id: u16,
145    ) -> Self {
146        let entry = Entry::SubscribeAckEventGroup(EventGroupEntry::new(
147            service_id,
148            instance_id,
149            major_version,
150            ttl,
151            event_group_id,
152        ));
153        let mut entries = SdEntries::new();
154        entries
155            .push(entry)
156            .expect("single SD entry exceeds capacity");
157        Self {
158            flags: Flags::new_sd(true),
159            entries,
160            options: SdOptions::new(),
161        }
162    }
163}
164
165impl<const E: usize, const O: usize> WireFormat for Header<E, O> {
166    fn decode<T: embedded_io::Read>(reader: &mut T) -> Result<Self, crate::protocol::Error> {
167        const MIN_OPTION_SIZE: usize = 4;
168        let flags = Flags::from(reader.read_u8()?);
169        let mut reserved: [u8; 3] = [0; 3];
170        reader.read_bytes(&mut reserved)?;
171        let entries_size = reader.read_u32_be()?;
172        let entries_count = entries_size / u32::try_from(ENTRY_SIZE).expect("constant fits u32");
173        let mut entries = SdEntries::new();
174        for _i in 0..entries_count {
175            entries
176                .push(Entry::decode(reader)?)
177                .map_err(|_| Error::TooManyEntries)?;
178        }
179
180        let mut remaining_options_size = reader.read_u32_be()? as usize;
181        let mut options = SdOptions::new();
182        // Minimum SD option wire size: length(2) + type(1) + reserved(1) = 4 bytes
183        while remaining_options_size > 0 {
184            if remaining_options_size < MIN_OPTION_SIZE {
185                return Err(Error::IncorrectOptionsSize(remaining_options_size));
186            }
187            let option = Options::read(reader)?;
188            let option_size = option.size();
189            if option_size > remaining_options_size {
190                return Err(Error::IncorrectOptionsSize(remaining_options_size));
191            }
192            remaining_options_size -= option_size;
193            options.push(option).map_err(|_| Error::TooManyOptions)?;
194        }
195        Ok(Self {
196            flags,
197            entries,
198            options,
199        })
200    }
201
202    fn required_size(&self) -> usize {
203        let mut size = 12 + self.entries.len() * ENTRY_SIZE;
204        for option in &self.options {
205            size += option.size();
206        }
207        size
208    }
209
210    fn encode<T: embedded_io::Write>(
211        &self,
212        writer: &mut T,
213    ) -> Result<usize, crate::protocol::Error> {
214        writer.write_u8(u8::from(self.flags))?;
215        let reserved: [u8; 3] = [0; 3];
216        writer.write_bytes(&reserved)?;
217        let entries_size = u32::try_from(self.entries.len() * 16).expect("entries size fits u32");
218        writer.write_u32_be(entries_size)?;
219        for entry in &self.entries {
220            entry.encode(writer)?;
221        }
222        let mut options_size = 0;
223        for option in &self.options {
224            options_size += option.size();
225        }
226        writer.write_u32_be(u32::try_from(options_size).expect("options size fits u32"))?;
227        for option in &self.options {
228            option.write(writer)?;
229        }
230        Ok(12 + entries_size as usize + options_size)
231    }
232}