• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 ///A slice containing an udp header of a network package. Struct allows the selective read of fields in the header.
5 #[derive(Clone, Debug, Eq, PartialEq)]
6 pub struct UdpHeaderSlice<'a> {
7     pub(crate) slice: &'a [u8],
8 }
9 
10 impl<'a> UdpHeaderSlice<'a> {
11     /// Creates a slice containing an udp header.
12     #[inline]
from_slice(slice: &'a [u8]) -> Result<UdpHeaderSlice<'a>, err::LenError>13     pub fn from_slice(slice: &'a [u8]) -> Result<UdpHeaderSlice<'a>, err::LenError> {
14         //check length
15         if slice.len() < UdpHeader::LEN {
16             return Err(err::LenError {
17                 required_len: UdpHeader::LEN,
18                 len: slice.len(),
19                 len_source: LenSource::Slice,
20                 layer: err::Layer::UdpHeader,
21                 layer_start_offset: 0,
22             });
23         }
24 
25         //done
26         Ok(UdpHeaderSlice {
27             // SAFETY:
28             // Safe as slice length is checked to be at least
29             // UdpHeader::LEN (8) before this.
30             slice: unsafe { from_raw_parts(slice.as_ptr(), UdpHeader::LEN) },
31         })
32     }
33 
34     /// Returns the slice containing the udp header
35     #[inline]
slice(&self) -> &'a [u8]36     pub fn slice(&self) -> &'a [u8] {
37         self.slice
38     }
39 
40     /// Reads the "udp source port" from the slice.
41     #[inline]
source_port(&self) -> u1642     pub fn source_port(&self) -> u16 {
43         // SAFETY:
44         // Safe as the contructor checks that the slice has
45         // at least the length of UdpHeader::LEN (8).
46         unsafe { get_unchecked_be_u16(self.slice.as_ptr()) }
47     }
48 
49     /// Reads the "udp destination port" from the slice.
50     #[inline]
destination_port(&self) -> u1651     pub fn destination_port(&self) -> u16 {
52         // SAFETY:
53         // Safe as the contructor checks that the slice has
54         // at least the length of UdpHeader::LEN (8).
55         unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) }
56     }
57 
58     /// Reads the "length" from the slice.
59     #[inline]
length(&self) -> u1660     pub fn length(&self) -> u16 {
61         // SAFETY:
62         // Safe as the contructor checks that the slice has
63         // at least the length of UdpHeader::LEN (8).
64         unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) }
65     }
66 
67     /// Reads the "checksum" from the slice.
68     #[inline]
checksum(&self) -> u1669     pub fn checksum(&self) -> u16 {
70         // SAFETY:
71         // Safe as the contructor checks that the slice has
72         // at least the length of UdpHeader::LEN (8).
73         unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(6)) }
74     }
75 
76     /// Decode all the fields and copy the results to a UdpHeader struct
77     #[inline]
to_header(&self) -> UdpHeader78     pub fn to_header(&self) -> UdpHeader {
79         UdpHeader {
80             source_port: self.source_port(),
81             destination_port: self.destination_port(),
82             length: self.length(),
83             checksum: self.checksum(),
84         }
85     }
86 }
87 
88 #[cfg(test)]
89 mod test {
90     use crate::{test_gens::*, *};
91     use alloc::{format, vec::Vec};
92     use proptest::prelude::*;
93 
94     proptest! {
95         #[test]
96         fn from_slice(
97             input in udp_any(),
98             dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
99         ) {
100             // serialize
101             let mut buffer: Vec<u8> = Vec::with_capacity(8 + dummy_data.len());
102             input.write(&mut buffer).unwrap();
103             buffer.extend(&dummy_data[..]);
104 
105             // calls with a valid result
106             {
107                 let result = UdpHeaderSlice::from_slice(&buffer[..]).unwrap();
108                 assert_eq!(&buffer[..8], result.slice());
109             }
110 
111             // call with not enough data in the slice
112             for len in 0..8 {
113                 assert_eq!(
114                     UdpHeaderSlice::from_slice(&buffer[0..len]).unwrap_err(),
115                     err::LenError{
116                         required_len: UdpHeader::LEN,
117                         len: len,
118                         len_source: LenSource::Slice,
119                         layer: err::Layer::UdpHeader,
120                         layer_start_offset: 0,
121                     }
122                 );
123             }
124         }
125     }
126 
127     proptest! {
128         #[test]
129         fn getters(input in udp_any()) {
130             let bytes = input.to_bytes();
131             let slice = UdpHeaderSlice::from_slice(&bytes).unwrap();
132 
133             assert_eq!(slice.source_port(), input.source_port);
134             assert_eq!(slice.destination_port(), input.destination_port);
135             assert_eq!(slice.length(), input.length);
136             assert_eq!(slice.checksum(), input.checksum);
137         }
138     }
139 
140     proptest! {
141         #[test]
142         fn to_header(input in udp_any()) {
143             let bytes = input.to_bytes();
144             let slice = UdpHeaderSlice::from_slice(&bytes).unwrap();
145             assert_eq!(input, slice.to_header());
146         }
147     }
148 
149     proptest! {
150         #[test]
151         fn clone_eq(input in udp_any()) {
152             let bytes = input.to_bytes();
153             let slice = UdpHeaderSlice::from_slice(&bytes).unwrap();
154             assert_eq!(slice, slice.clone());
155         }
156     }
157 
158     proptest! {
159         #[test]
160         fn dbg(input in udp_any()) {
161             let bytes = input.to_bytes();
162             let slice = UdpHeaderSlice::from_slice(&bytes).unwrap();
163             assert_eq!(
164                 &format!(
165                     "UdpHeaderSlice {{ slice: {:?} }}",
166                     slice.slice()
167                 ),
168                 &format!("{:?}", slice)
169             );
170         }
171     }
172 }
173