1use crate::*;
2
3#[derive(Clone, Eq, PartialEq)]
5pub struct TcpOptionsIterator<'a> {
6 pub(crate) options: &'a [u8],
7}
8
9impl<'a> TcpOptionsIterator<'a> {
10 pub fn from_slice(options: &'a [u8]) -> TcpOptionsIterator<'a> {
12 TcpOptionsIterator { options }
13 }
14
15 pub fn rest(&self) -> &'a [u8] {
17 self.options
18 }
19}
20
21impl Iterator for TcpOptionsIterator<'_> {
22 type Item = Result<TcpOptionElement, TcpOptionReadError>;
23
24 fn next(&mut self) -> Option<Self::Item> {
25 use crate::TcpOptionElement::*;
26 use crate::TcpOptionReadError::*;
27
28 let expect_specific_size =
29 |expected_size: u8, slice: &[u8]| -> Result<(), TcpOptionReadError> {
30 let id = slice[0];
31 if slice.len() < expected_size as usize {
32 Err(UnexpectedEndOfSlice {
33 option_id: id,
34 expected_len: expected_size,
35 actual_len: slice.len(),
36 })
37 } else if slice[1] != expected_size {
38 Err(UnexpectedSize {
39 option_id: slice[0],
40 size: slice[1],
41 })
42 } else {
43 Ok(())
44 }
45 };
46
47 if self.options.is_empty() {
48 None
49 } else {
50 use tcp_option::*;
52 let result = match self.options[0] {
53 KIND_END => None,
55 KIND_NOOP => {
56 self.options = &self.options[1..];
57 Some(Ok(Noop))
58 }
59 KIND_MAXIMUM_SEGMENT_SIZE => {
60 match expect_specific_size(LEN_MAXIMUM_SEGMENT_SIZE, self.options) {
61 Err(value) => Some(Err(value)),
62 _ => {
63 let value =
67 unsafe { get_unchecked_be_u16(self.options.as_ptr().add(2)) };
68 self.options = &self.options[4..];
69 Some(Ok(MaximumSegmentSize(value)))
70 }
71 }
72 }
73 KIND_WINDOW_SCALE => match expect_specific_size(LEN_WINDOW_SCALE, self.options) {
74 Err(value) => Some(Err(value)),
75 _ => {
76 let value = self.options[2];
77 self.options = &self.options[3..];
78 Some(Ok(WindowScale(value)))
79 }
80 },
81 KIND_SELECTIVE_ACK_PERMITTED => {
82 match expect_specific_size(LEN_SELECTIVE_ACK_PERMITTED, self.options) {
83 Err(value) => Some(Err(value)),
84 _ => {
85 self.options = &self.options[2..];
86 Some(Ok(SelectiveAcknowledgementPermitted))
87 }
88 }
89 }
90 KIND_SELECTIVE_ACK => {
91 if self.options.len() < 2 {
93 Some(Err(UnexpectedEndOfSlice {
94 option_id: self.options[0],
95 expected_len: 2,
96 actual_len: self.options.len(),
97 }))
98 } else {
99 let len = self.options[1];
101 if len != 10 && len != 18 && len != 26 && len != 34 {
102 Some(Err(UnexpectedSize {
103 option_id: self.options[0],
104 size: len,
105 }))
106 } else if self.options.len() < (len as usize) {
107 Some(Err(UnexpectedEndOfSlice {
108 option_id: self.options[0],
109 expected_len: len,
110 actual_len: self.options.len(),
111 }))
112 } else {
113 let mut acks: [Option<(u32, u32)>; 3] = [None; 3];
114 let first = unsafe {
119 (
120 get_unchecked_be_u32(self.options.as_ptr().add(2)),
121 get_unchecked_be_u32(self.options.as_ptr().add(6)),
122 )
123 };
124 for (i, item) in acks.iter_mut().enumerate().take(3) {
125 let offset = 2 + 8 + (i * 8);
126 unsafe {
131 if offset < (len as usize) {
132 *item = Some((
133 get_unchecked_be_u32(self.options.as_ptr().add(offset)),
134 get_unchecked_be_u32(
135 self.options.as_ptr().add(offset + 4),
136 ),
137 ));
138 }
139 }
140 }
141 self.options = &self.options[len as usize..];
143 Some(Ok(SelectiveAcknowledgement(first, acks)))
144 }
145 }
146 }
147 KIND_TIMESTAMP => {
148 match expect_specific_size(LEN_TIMESTAMP, self.options) {
149 Err(value) => Some(Err(value)),
150
151 _ => unsafe {
152 let t = Timestamp(
153 get_unchecked_be_u32(self.options.as_ptr().add(2)),
157 get_unchecked_be_u32(self.options.as_ptr().add(6)),
158 );
159 self.options = &self.options[10..];
160 Some(Ok(t))
161 },
162 }
163 }
164
165 _ => Some(Err(UnknownId(self.options[0]))),
167 };
168
169 match result {
171 None | Some(Err(_)) => {
172 let len = self.options.len();
173 self.options = &self.options[len..len];
174 }
175 _ => {}
176 }
177
178 result
180 }
181 }
182}
183
184impl core::fmt::Debug for TcpOptionsIterator<'_> {
185 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
186 let mut list = fmt.debug_list();
187
188 for it in self.clone() {
190 match it {
191 Ok(e) => {
192 list.entry(&e);
193 }
194 Err(e) => {
195 list.entry(&Result::<(), TcpOptionReadError>::Err(e.clone()));
196 }
197 }
198 }
199
200 list.finish()
201 }
202}
203
204#[cfg(test)]
205mod test {
206 use crate::{tcp_option::*, *};
207 use alloc::format;
208
209 #[test]
210 fn debug() {
211 use tcp_option::*;
212 #[rustfmt::skip]
213 assert_eq!(
214 "[MaximumSegmentSize(0), WindowScale(0)]",
215 format!(
216 "{:?}",
217 TcpOptionsIterator::from_slice(&[
218 KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
219 KIND_WINDOW_SCALE, 3, 0,
220 KIND_END,
221 ])
222 )
223 );
224 #[rustfmt::skip]
225 assert_eq!(
226 "[MaximumSegmentSize(0), Err(UnexpectedSize { option_id: 3, size: 0 })]",
227 format!(
228 "{:?}",
229 TcpOptionsIterator::from_slice(&[
230 KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
231 KIND_WINDOW_SCALE, 0, 0, 0,
232 ])
233 )
234 );
235 }
236
237 #[test]
238 fn clone_eq() {
239 use tcp_option::*;
240 let it = TcpOptionsIterator::from_slice(&[KIND_END]);
241 assert_eq!(it, it.clone());
242 }
243
244 #[test]
245 fn from_slice_and_rest() {
246 let buffer = [KIND_NOOP, KIND_NOOP, KIND_MAXIMUM_SEGMENT_SIZE, 4];
247 let it = TcpOptionsIterator::from_slice(&buffer);
248 assert_eq!(it.rest(), &buffer[..]);
249 }
250
251 #[test]
252 #[rustfmt::skip]
253 fn next() {
254 use crate::TcpOptionElement::*;
255
256 {
258 fn expect_elements(buffer: &[u8], expected: &[TcpOptionElement]) {
259 let mut it = TcpOptionsIterator::from_slice(buffer);
261 for element in expected.iter() {
262 assert_eq!(element, &it.next().unwrap().unwrap());
263 }
264
265 assert_eq!(None, it.next());
267 assert_eq!(0, it.rest().len());
268 }
269
270 #[rustfmt::skip]
272 expect_elements(&[
273 KIND_NOOP,
274 KIND_NOOP,
275 KIND_MAXIMUM_SEGMENT_SIZE, 4,
276 0, 1,
277 KIND_WINDOW_SCALE, 3, 2,
278 KIND_SELECTIVE_ACK_PERMITTED, 2,
279 KIND_SELECTIVE_ACK, 10,
280 0, 0, 0, 10,
281 0, 0, 0, 11,
282 KIND_SELECTIVE_ACK, 18,
283 0, 0, 0, 12,
284 0, 0, 0, 13,
285 0, 0, 0, 14,
286 0, 0, 0, 15,
287 KIND_SELECTIVE_ACK, 26,
288 0, 0, 0, 16,
289 0, 0, 0, 17,
290 0, 0, 0, 18,
291 0, 0, 0, 19,
292 0, 0, 0, 20,
293 0, 0, 0, 21,
294 KIND_SELECTIVE_ACK, 34,
295 0, 0, 0, 22,
296 0, 0, 0, 23,
297 0, 0, 0, 24,
298 0, 0, 0, 25,
299 0, 0, 0, 26,
300 0, 0, 0, 27,
301 0, 0, 0, 28,
302 0, 0, 0, 29,
303 KIND_TIMESTAMP, 10,
304 0, 0, 0, 30,
305 0, 0, 0, 31,
306 KIND_END, 0, 0, 0, 0
307 ],
308 &[
309 Noop,
310 Noop,
311 MaximumSegmentSize(1),
312 WindowScale(2),
313 SelectiveAcknowledgementPermitted,
314 SelectiveAcknowledgement((10,11), [None, None, None]),
315 SelectiveAcknowledgement((12,13), [Some((14,15)), None, None]),
316 SelectiveAcknowledgement((16,17), [Some((18,19)), Some((20,21)), None]),
317 SelectiveAcknowledgement((22,23), [Some((24,25)), Some((26,27)), Some((28,29))]),
318 Timestamp(30,31)
319 ]
320 );
321 }
322
323 {
325 let data = [255, 2, 0, 0, 0,
326 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
328 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330 0, 0, 0, 0, 0, 0, 0, 0, 0];
332 let mut it = TcpOptionsIterator::from_slice(&data);
333 assert_eq!(Some(Err(TcpOptionReadError::UnknownId(255))), it.next());
334
335 assert_eq!(0, it.rest().len());
337 assert_eq!(None, it.next());
338 assert_eq!(0, it.rest().len());
339 }
340
341 {
343 fn expect_unexpected_eos(slice: &[u8]) {
344 for i in 1..slice.len()-1 {
345 let mut it = TcpOptionsIterator::from_slice(&slice[..i]);
346 assert_eq!(
347 Some(
348 Err(
349 TcpOptionReadError::UnexpectedEndOfSlice{
350 option_id: slice[0],
351 expected_len: match slice[0] {
352 KIND_MAXIMUM_SEGMENT_SIZE => 4,
353 KIND_WINDOW_SCALE => 3,
354 KIND_SELECTIVE_ACK_PERMITTED => 2,
355 KIND_SELECTIVE_ACK => if i < 2 {
356 2
359 } else {
360 slice[1]
361 },
362 KIND_TIMESTAMP => 10,
363 _ => panic!("not part of the tests"),
364 },
365 actual_len: i
366 }
367 )
368 ),
369 it.next()
370 );
371 assert_eq!(0, it.rest().len());
373 assert_eq!(None, it.next());
374 }
375 }
376
377 expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
378 expect_unexpected_eos(&[KIND_WINDOW_SCALE, 3, 0]);
379 expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
380 expect_unexpected_eos(&[KIND_SELECTIVE_ACK_PERMITTED, 2]);
381 expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 10, 0, 0, 0,
382 0, 0, 0, 0, 0]);
383 expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 18, 0, 0, 0,
384 0, 0, 0, 0, 0,
385 0, 0, 0, 0, 0,
386 0, 0, 0]);
387 expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 26, 0, 0, 0,
388 0, 0, 0, 0, 0,
389 0, 0, 0, 0, 0,
390 0, 0, 0, 0, 0,
391 0, 0, 0, 0, 0,
392 0]);
393 expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 34, 0, 0, 0,
394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0]);
400 expect_unexpected_eos(&[KIND_TIMESTAMP, 10, 0, 0, 0,
401 0, 0, 0, 0, 0]);
402 }
403
404 {
406 fn expect_unexpected_size(id: u8, size: u8) {
407 let data = [
408 id, size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
412 ];
413 let mut it = TcpOptionsIterator::from_slice(&data);
414 assert_eq!(
415 Some(Err(TcpOptionReadError::UnexpectedSize {
416 option_id: data[0],
417 size: data[1]
418 })),
419 it.next()
420 );
421 assert_eq!(0, it.rest().len());
423 assert_eq!(None, it.next());
424 assert_eq!(0, it.rest().len());
425 }
426 expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
427 expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
428
429 expect_unexpected_size(KIND_WINDOW_SCALE, 2);
430 expect_unexpected_size(KIND_WINDOW_SCALE, 4);
431
432 expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
433 expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
434
435 expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 1);
436 expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 3);
437
438 expect_unexpected_size(KIND_SELECTIVE_ACK, 9);
439 expect_unexpected_size(KIND_SELECTIVE_ACK, 11);
440
441 expect_unexpected_size(KIND_SELECTIVE_ACK, 17);
442 expect_unexpected_size(KIND_SELECTIVE_ACK, 19);
443
444 expect_unexpected_size(KIND_SELECTIVE_ACK, 25);
445 expect_unexpected_size(KIND_SELECTIVE_ACK, 27);
446
447 expect_unexpected_size(KIND_SELECTIVE_ACK, 33);
448 expect_unexpected_size(KIND_SELECTIVE_ACK, 35);
449
450 expect_unexpected_size(KIND_TIMESTAMP, 9);
451 expect_unexpected_size(KIND_TIMESTAMP, 11);
452 }
453 }
454}