simple_someip/protocol/sd/
header.rs1use crate::protocol::byte_order::WriteBytesExt;
2
3use crate::traits::WireFormat;
4
5use super::{
6 Entry, Flags, Options,
7 entry::{ENTRY_SIZE, EntryIter, EntryType},
8 options::{OptionIter, validate_option},
9};
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub struct Header<'a> {
17 pub flags: Flags,
19 pub entries: &'a [Entry],
21 pub options: &'a [Options],
23}
24
25impl<'a> Header<'a> {
26 #[must_use]
28 pub const fn new(flags: Flags, entries: &'a [Entry], options: &'a [Options]) -> Self {
29 Self {
30 flags,
31 entries,
32 options,
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug)]
43pub struct SdHeaderView<'a> {
44 flags: Flags,
45 entries_buf: &'a [u8],
46 options_buf: &'a [u8],
47}
48
49impl<'a> SdHeaderView<'a> {
50 pub fn parse(buf: &'a [u8]) -> Result<Self, crate::protocol::Error> {
63 if buf.len() < 12 {
65 return Err(crate::protocol::Error::UnexpectedEof);
66 }
67
68 let flags = Flags::from(buf[0]);
69 let entries_size = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]) as usize;
72
73 if !entries_size.is_multiple_of(ENTRY_SIZE) {
74 return Err(super::Error::IncorrectEntriesSize(entries_size).into());
75 }
76
77 if buf.len() < 8 + entries_size + 4 {
79 return Err(crate::protocol::Error::UnexpectedEof);
80 }
81
82 let entries_buf = &buf[8..8 + entries_size];
83
84 let mut offset = 0;
86 while offset < entries_size {
87 EntryType::try_from(entries_buf[offset])?;
88 offset += ENTRY_SIZE;
89 }
90
91 let options_size_offset = 8 + entries_size;
92 let options_size = u32::from_be_bytes([
93 buf[options_size_offset],
94 buf[options_size_offset + 1],
95 buf[options_size_offset + 2],
96 buf[options_size_offset + 3],
97 ]) as usize;
98
99 let options_start = options_size_offset + 4;
100 if buf.len() < options_start + options_size {
101 return Err(crate::protocol::Error::UnexpectedEof);
102 }
103
104 let options_buf = &buf[options_start..options_start + options_size];
105
106 let mut opt_offset = 0;
108 while opt_offset < options_size {
109 let remaining = &options_buf[opt_offset..];
110 let wire_size = validate_option(remaining)?;
111 opt_offset += wire_size;
112 }
113
114 Ok(Self {
115 flags,
116 entries_buf,
117 options_buf,
118 })
119 }
120
121 #[must_use]
123 pub fn flags(&self) -> Flags {
124 self.flags
125 }
126
127 #[must_use]
129 pub fn entries(&self) -> EntryIter<'a> {
130 EntryIter::new(self.entries_buf)
131 }
132
133 #[must_use]
135 pub fn options(&self) -> OptionIter<'a> {
136 OptionIter::new(self.options_buf)
137 }
138
139 #[must_use]
141 pub fn entry_count(&self) -> usize {
142 self.entries_buf.len() / ENTRY_SIZE
143 }
144}
145
146impl WireFormat for Header<'_> {
147 fn required_size(&self) -> usize {
148 let mut size = 12 + self.entries.len() * ENTRY_SIZE;
149 for option in self.options {
150 size += option.size();
151 }
152 size
153 }
154
155 fn encode<T: embedded_io::Write>(
156 &self,
157 writer: &mut T,
158 ) -> Result<usize, crate::protocol::Error> {
159 writer.write_u8(u8::from(self.flags))?;
160 let reserved: [u8; 3] = [0; 3];
161 writer.write_bytes(&reserved)?;
162 let entries_size = u32::try_from(self.entries.len() * 16).expect("entries size fits u32");
163 writer.write_u32_be(entries_size)?;
164 for entry in self.entries {
165 entry.encode(writer)?;
166 }
167 let mut options_size = 0;
168 for option in self.options {
169 options_size += option.size();
170 }
171 writer.write_u32_be(u32::try_from(options_size).expect("options size fits u32"))?;
172 for option in self.options {
173 option.write(writer)?;
174 }
175 Ok(12 + entries_size as usize + options_size)
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use core::net::Ipv4Addr;
182
183 use super::*;
184 use crate::{
185 protocol::sd::{
186 Error as SdError, EventGroupEntry, OptionsCount, ServiceEntry, TransportProtocol,
187 },
188 traits::WireFormat,
189 };
190
191 fn ipv4_endpoint_bytes(ip: [u8; 4], protocol: u8, port: u16) -> [u8; 12] {
192 let mut b = [0u8; 12];
193 b[0] = 0x00;
194 b[1] = 0x09; b[2] = 0x04; b[3] = 0x00; b[4..8].copy_from_slice(&ip);
198 b[8] = 0x00; b[9] = protocol;
200 b[10] = (port >> 8) as u8;
201 b[11] = (port & 0xFF) as u8;
202 b
203 }
204
205 fn raw_header(entries_size: u32, options_size: u32) -> [u8; 12] {
206 let mut b = [0u8; 12];
207 b[4..8].copy_from_slice(&entries_size.to_be_bytes());
209 b[8..12].copy_from_slice(&options_size.to_be_bytes());
210 b
211 }
212
213 #[test]
214 fn header_new_stores_fields() {
215 let flags = Flags::new_sd(true);
216 let entries: &[Entry] = &[];
217 let options: &[Options] = &[];
218 let h = Header::new(flags, entries, options);
219 assert_eq!(h.flags, flags);
220 assert!(h.entries.is_empty());
221 assert!(h.options.is_empty());
222 }
223
224 #[test]
225 fn service_offer_round_trips() {
226 let ip = Ipv4Addr::new(192, 168, 1, 10);
227 let entry = Entry::OfferService(ServiceEntry {
228 service_id: 0x1234,
229 instance_id: 0x0001,
230 major_version: 1,
231 ttl: 0xFFFFFF,
232 index_first_options_run: 0,
233 index_second_options_run: 0,
234 options_count: OptionsCount::new(1, 0),
235 minor_version: 0,
236 });
237 let endpoint = Options::IpV4Endpoint {
238 ip,
239 protocol: TransportProtocol::Udp,
240 port: 30509,
241 };
242 let entries = [entry];
243 let options = [endpoint];
244 let h = Header::new(Flags::new_sd(false), &entries, &options);
245 assert_eq!(h.required_size(), 40);
246 let mut buf = [0u8; 64];
247 h.encode(&mut buf.as_mut_slice()).unwrap();
248 let view = SdHeaderView::parse(&buf[..h.required_size()]).unwrap();
249 assert_eq!(view.entry_count(), 1);
250 let entry_view = view.entries().next().unwrap();
251 assert_eq!(entry_view.service_id(), 0x1234);
252 }
253
254 #[test]
255 fn subscribe_ack_round_trips() {
256 let entry = Entry::SubscribeAckEventGroup(EventGroupEntry::new(
257 0xAAAA, 0x0001, 1, 0xFFFFFF, 0x0010,
258 ));
259 let entries = [entry];
260 let h = Header::new(Flags::new_sd(true), &entries, &[]);
261 assert_eq!(h.required_size(), 28);
262 let mut buf = [0u8; 32];
263 h.encode(&mut buf.as_mut_slice()).unwrap();
264 let view = SdHeaderView::parse(&buf[..h.required_size()]).unwrap();
265 assert_eq!(view.entry_count(), 1);
266 }
267
268 #[test]
269 fn parse_exact_size_slice_succeeds() {
270 let entry = Entry::OfferService(ServiceEntry {
271 service_id: 0x1234,
272 instance_id: 0x0001,
273 major_version: 1,
274 ttl: 0xFFFFFF,
275 index_first_options_run: 0,
276 index_second_options_run: 0,
277 options_count: OptionsCount::new(1, 0),
278 minor_version: 0,
279 });
280 let endpoint = Options::IpV4Endpoint {
281 ip: Ipv4Addr::new(192, 168, 1, 10),
282 protocol: TransportProtocol::Udp,
283 port: 30509,
284 };
285 let entries = [entry];
286 let options = [endpoint];
287 let h = Header::new(Flags::new_sd(false), &entries, &options);
288 let mut buf = [0u8; 64];
289 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
290 let view = SdHeaderView::parse(&buf[..n]).unwrap();
291 assert_eq!(view.entry_count(), 1);
292 }
293
294 #[test]
295 fn parse_options_size_below_minimum_returns_error() {
296 let prefix = raw_header(0, 2);
297 let mut buf = [0u8; 14];
298 buf[..12].copy_from_slice(&prefix);
299 assert!(matches!(
300 SdHeaderView::parse(&buf),
301 Err(crate::protocol::Error::Sd(SdError::IncorrectOptionsSize(2)))
302 ));
303 }
304
305 #[test]
306 fn parse_option_size_exceeds_declared_remaining_returns_error() {
307 let prefix = raw_header(0, 5);
308 let option = ipv4_endpoint_bytes([127, 0, 0, 1], 0x11, 1234);
309 let mut buf = [0u8; 24];
310 buf[..12].copy_from_slice(&prefix);
311 buf[12..24].copy_from_slice(&option);
312 assert!(matches!(
313 SdHeaderView::parse(&buf),
314 Err(crate::protocol::Error::Sd(SdError::IncorrectOptionsSize(5)))
315 ));
316 }
317
318 #[test]
321 fn sd_header_view_entry_count() {
322 let entries = [
323 Entry::FindService(ServiceEntry::find(0x0001)),
324 Entry::FindService(ServiceEntry::find(0x0002)),
325 ];
326 let h = Header::new(Flags::new_sd(false), &entries, &[]);
327 let mut buf = [0u8; 64];
328 h.encode(&mut buf.as_mut_slice()).unwrap();
329 let view = SdHeaderView::parse(&buf[..h.required_size()]).unwrap();
330 assert_eq!(view.entry_count(), 2);
331 }
332
333 #[test]
334 fn sd_header_view_flags() {
335 let h = Header::new(Flags::new_sd(true), &[], &[]);
336 let mut buf = [0u8; 16];
337 h.encode(&mut buf.as_mut_slice()).unwrap();
338 let view = SdHeaderView::parse(&buf[..h.required_size()]).unwrap();
339 assert_eq!(view.flags(), h.flags);
340 }
341
342 #[test]
343 fn parse_incorrect_entries_size_returns_error() {
344 let mut buf = [0u8; 12];
345 buf[4..8].copy_from_slice(&5u32.to_be_bytes());
346 assert!(matches!(
347 SdHeaderView::parse(&buf),
348 Err(crate::protocol::Error::Sd(SdError::IncorrectEntriesSize(5)))
349 ));
350 }
351}