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