1use crate::{err::ValueTooBigError, *};
2
3#[derive(Clone, Debug, Eq, PartialEq, Default)]
5pub struct UdpHeader {
6 pub source_port: u16,
8 pub destination_port: u16,
10 pub length: u16,
12 pub checksum: u16,
14}
15
16impl UdpHeader {
17 pub const LEN: usize = 8;
19
20 pub const LEN_U16: u16 = 8;
22
23 #[deprecated(since = "0.14.0", note = "Use `UdpHeader::LEN` instead")]
24 pub const SERIALIZED_SIZE: usize = UdpHeader::LEN;
25
26 pub fn without_ipv4_checksum(
28 source_port: u16,
29 destination_port: u16,
30 payload_length: usize,
31 ) -> Result<UdpHeader, ValueTooBigError<usize>> {
32 const MAX_PAYLOAD_LENGTH: usize = (u16::MAX as usize) - UdpHeader::LEN;
34 if MAX_PAYLOAD_LENGTH < payload_length {
35 return Err(ValueTooBigError {
36 actual: payload_length,
37 max_allowed: MAX_PAYLOAD_LENGTH,
38 value_type: err::ValueType::UdpPayloadLengthIpv4,
39 });
40 }
41
42 Ok(UdpHeader {
43 source_port,
44 destination_port,
45 length: (UdpHeader::LEN + payload_length) as u16, checksum: 0,
47 })
48 }
49
50 pub fn with_ipv4_checksum(
52 source_port: u16,
53 destination_port: u16,
54 ip_header: &Ipv4Header,
55 payload: &[u8],
56 ) -> Result<UdpHeader, ValueTooBigError<usize>> {
57 const MAX_PAYLOAD_LENGTH: usize = (u16::MAX as usize) - UdpHeader::LEN;
59 if MAX_PAYLOAD_LENGTH < payload.len() {
60 return Err(ValueTooBigError {
61 actual: payload.len(),
62 max_allowed: MAX_PAYLOAD_LENGTH,
63 value_type: err::ValueType::UdpPayloadLengthIpv4,
64 });
65 }
66
67 let mut result = UdpHeader {
68 source_port,
69 destination_port,
70 length: (UdpHeader::LEN + payload.len()) as u16, checksum: 0,
72 };
73 result.checksum =
74 result.calc_checksum_ipv4_internal(ip_header.source, ip_header.destination, payload);
75 Ok(result)
76 }
77
78 pub fn calc_checksum_ipv4(
80 &self,
81 ip_header: &Ipv4Header,
82 payload: &[u8],
83 ) -> Result<u16, ValueTooBigError<usize>> {
84 self.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, payload)
85 }
86
87 pub fn calc_checksum_ipv4_raw(
89 &self,
90 source: [u8; 4],
91 destination: [u8; 4],
92 payload: &[u8],
93 ) -> Result<u16, ValueTooBigError<usize>> {
94 const MAX_PAYLOAD_LENGTH: usize = (u16::MAX as usize) - UdpHeader::LEN;
96 if MAX_PAYLOAD_LENGTH < payload.len() {
97 return Err(ValueTooBigError {
98 actual: payload.len(),
99 max_allowed: MAX_PAYLOAD_LENGTH,
100 value_type: err::ValueType::UdpPayloadLengthIpv4,
101 });
102 }
103
104 Ok(self.calc_checksum_ipv4_internal(source, destination, payload))
105 }
106
107 fn calc_checksum_ipv4_internal(
109 &self,
110 source: [u8; 4],
111 destination: [u8; 4],
112 payload: &[u8],
113 ) -> u16 {
114 self.calc_checksum_post_ip(
115 checksum::Sum16BitWords::new()
117 .add_4bytes(source)
118 .add_4bytes(destination)
119 .add_2bytes([0, ip_number::UDP.0])
120 .add_2bytes(self.length.to_be_bytes()),
121 payload,
122 )
123 }
124
125 pub fn with_ipv6_checksum(
127 source_port: u16,
128 destination_port: u16,
129 ip_header: &Ipv6Header,
130 payload: &[u8],
131 ) -> Result<UdpHeader, ValueTooBigError<usize>> {
132 const MAX_PAYLOAD_LENGTH: usize = (u16::MAX as usize) - UdpHeader::LEN;
134 if MAX_PAYLOAD_LENGTH < payload.len() {
135 return Err(ValueTooBigError {
136 actual: payload.len(),
137 max_allowed: MAX_PAYLOAD_LENGTH,
138 value_type: err::ValueType::UdpPayloadLengthIpv6,
139 });
140 }
141
142 let mut result = UdpHeader {
143 source_port,
144 destination_port,
145 length: (UdpHeader::LEN + payload.len()) as u16, checksum: 0,
147 };
148 result.checksum =
149 result.calc_checksum_ipv6_internal(ip_header.source, ip_header.destination, payload);
150 Ok(result)
151 }
152
153 pub fn calc_checksum_ipv6(
155 &self,
156 ip_header: &Ipv6Header,
157 payload: &[u8],
158 ) -> Result<u16, err::ValueTooBigError<usize>> {
159 self.calc_checksum_ipv6_raw(ip_header.source, ip_header.destination, payload)
160 }
161
162 pub fn calc_checksum_ipv6_raw(
164 &self,
165 source: [u8; 16],
166 destination: [u8; 16],
167 payload: &[u8],
168 ) -> Result<u16, err::ValueTooBigError<usize>> {
169 const MAX_PAYLOAD_LENGTH: usize = (u32::MAX as usize) - UdpHeader::LEN;
171 if MAX_PAYLOAD_LENGTH < payload.len() {
172 return Err(err::ValueTooBigError {
173 actual: payload.len(),
174 max_allowed: MAX_PAYLOAD_LENGTH,
175 value_type: err::ValueType::UdpPayloadLengthIpv6,
176 });
177 }
178
179 Ok(self.calc_checksum_ipv6_internal(source, destination, payload))
180 }
181
182 fn calc_checksum_ipv6_internal(
183 &self,
184 source: [u8; 16],
185 destination: [u8; 16],
186 payload: &[u8],
187 ) -> u16 {
188 self.calc_checksum_post_ip(
189 checksum::Sum16BitWords::new()
191 .add_16bytes(source)
192 .add_16bytes(destination)
193 .add_2bytes([0, ip_number::UDP.0])
194 .add_2bytes(self.length.to_be_bytes()),
195 payload,
196 )
197 }
198
199 fn calc_checksum_post_ip(
201 &self,
202 ip_pseudo_header_sum: checksum::Sum16BitWords,
203 payload: &[u8],
204 ) -> u16 {
205 ip_pseudo_header_sum
206 .add_2bytes(self.source_port.to_be_bytes())
207 .add_2bytes(self.destination_port.to_be_bytes())
208 .add_2bytes(self.length.to_be_bytes())
209 .add_slice(payload)
210 .to_ones_complement_with_no_zero()
211 .to_be()
212 }
213
214 #[deprecated(since = "0.10.1", note = "Use UdpHeader::from_slice instead.")]
216 #[inline]
217 pub fn read_from_slice(slice: &[u8]) -> Result<(UdpHeader, &[u8]), err::LenError> {
218 UdpHeader::from_slice(slice)
219 }
220
221 #[inline]
223 pub fn from_slice(slice: &[u8]) -> Result<(UdpHeader, &[u8]), err::LenError> {
224 Ok((
225 UdpHeaderSlice::from_slice(slice)?.to_header(),
226 &slice[UdpHeader::LEN..],
227 ))
228 }
229
230 #[inline]
232 pub fn from_bytes(bytes: [u8; 8]) -> UdpHeader {
233 UdpHeader {
234 source_port: u16::from_be_bytes([bytes[0], bytes[1]]),
235 destination_port: u16::from_be_bytes([bytes[2], bytes[3]]),
236 length: u16::from_be_bytes([bytes[4], bytes[5]]),
237 checksum: u16::from_be_bytes([bytes[6], bytes[7]]),
238 }
239 }
240
241 #[cfg(feature = "std")]
243 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
244 pub fn read<T: std::io::Read + std::io::Seek + Sized>(
245 reader: &mut T,
246 ) -> Result<UdpHeader, std::io::Error> {
247 let bytes = {
248 let mut bytes: [u8; 8] = [0; 8];
249 reader.read_exact(&mut bytes)?;
250 bytes
251 };
252 Ok(UdpHeader::from_bytes(bytes))
253 }
254
255 #[cfg(feature = "std")]
257 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
258 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
259 writer.write_all(&self.to_bytes())?;
260 Ok(())
261 }
262
263 #[inline]
268 pub const fn header_len(&self) -> usize {
269 UdpHeader::LEN
270 }
271
272 #[inline]
277 pub const fn header_len_u16(&self) -> u16 {
278 UdpHeader::LEN_U16
279 }
280
281 #[inline]
284 pub fn to_bytes(&self) -> [u8; 8] {
285 let source_port_be = self.source_port.to_be_bytes();
286 let destination_port_be = self.destination_port.to_be_bytes();
287 let length_be = self.length.to_be_bytes();
288 let checksum = self.checksum.to_be_bytes();
289 [
290 source_port_be[0],
291 source_port_be[1],
292 destination_port_be[0],
293 destination_port_be[1],
294 length_be[0],
295 length_be[1],
296 checksum[0],
297 checksum[1],
298 ]
299 }
300}
301
302#[cfg(test)]
303mod test {
304 use crate::{
305 err::{ValueTooBigError, ValueType},
306 test_gens::*,
307 *,
308 };
309 use alloc::{format, vec::Vec};
310 use proptest::prelude::*;
311 use std::io::Cursor;
312
313 proptest! {
314 #[test]
315 fn without_ipv4_checksum(
316 source_port in any::<u16>(),
317 destination_port in any::<u16>(),
318 good_payload_length in 0..=((core::u16::MAX as usize) - UdpHeader::LEN),
319 bad_payload_length in ((core::u16::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
320 ) {
321
322 {
324 let actual = UdpHeader::without_ipv4_checksum(
325 source_port,
326 destination_port,
327 good_payload_length
328 ).unwrap();
329 assert_eq!(
330 actual,
331 UdpHeader{
332 source_port,
333 destination_port,
334 length: (UdpHeader::LEN + good_payload_length) as u16,
335 checksum: 0
336 }
337 );
338 }
339
340 {
342 let actual = UdpHeader::without_ipv4_checksum(
343 source_port,
344 destination_port,
345 bad_payload_length
346 ).unwrap_err();
347 assert_eq!(
348 actual,
349 ValueTooBigError{
350 actual: bad_payload_length,
351 max_allowed: usize::from(u16::MAX) - UdpHeader::LEN,
352 value_type: err::ValueType::UdpPayloadLengthIpv4,
353 }
354 );
355 }
356 }
357 }
358
359 fn expected_udp_ipv4_checksum(
361 source: [u8; 4],
362 destination: [u8; 4],
363 udp_header: &UdpHeader,
364 payload: &[u8],
365 ) -> u16 {
366 checksum::Sum16BitWords::new()
367 .add_4bytes(source)
369 .add_4bytes(destination)
370 .add_2bytes([0, ip_number::UDP.0])
371 .add_2bytes(udp_header.length.to_be_bytes())
372 .add_2bytes(udp_header.source_port.to_be_bytes())
374 .add_2bytes(udp_header.destination_port.to_be_bytes())
375 .add_2bytes(udp_header.length.to_be_bytes())
376 .add_2bytes([0, 0]) .add_slice(payload)
378 .to_ones_complement_with_no_zero()
379 .to_be()
380 }
381
382 proptest! {
383 #[test]
384 fn with_ipv4_checksum(
385 source_port in any::<u16>(),
386 destination_port in any::<u16>(),
387 ipv4 in ipv4_any(),
388 payload in proptest::collection::vec(any::<u8>(), 0..20),
389 bad_len in ((core::u16::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
390 ) {
391 assert_eq!(
393 UdpHeader::with_ipv4_checksum(
394 source_port,
395 destination_port,
396 &ipv4,
397 &payload
398 ).unwrap(),
399 {
400 let mut expected = UdpHeader {
401 source_port,
402 destination_port,
403 length: (UdpHeader::LEN + payload.len()) as u16,
404 checksum: 0,
405 };
406 let checksum = expected_udp_ipv4_checksum(
407 ipv4.source,
408 ipv4.destination,
409 &expected,
410 &payload
411 );
412 expected.checksum = checksum;
413 expected
414 }
415 );
416
417 {
420 let base = UdpHeader {
421 source_port: 0,
422 destination_port,
423 length: (UdpHeader::LEN + payload.len()) as u16,
424 checksum: 0,
425 };
426 let sourceless_checksum = !(expected_udp_ipv4_checksum(
430 ipv4.source,
431 ipv4.destination,
432 &base,
433 &payload
434 ).to_le());
435
436 assert_eq!(
437 UdpHeader::with_ipv4_checksum(
438 0xffff - sourceless_checksum,
441 destination_port,
442 &ipv4,
443 &payload
444 ).unwrap(),
445 UdpHeader{
446 source_port: 0xffff - sourceless_checksum,
447 destination_port,
448 length: base.length,
449 checksum: 0xffff
450 }
451 );
452 }
453
454 {
456 let too_big_slice = unsafe {
459 use core::ptr::NonNull;
463 core::slice::from_raw_parts(
464 NonNull::<u8>::dangling().as_ptr(),
465 bad_len
466 )
467 };
468 assert_eq!(
469 UdpHeader::with_ipv4_checksum(
470 source_port,
471 destination_port,
472 &ipv4,
473 &too_big_slice
474 ).unwrap_err(),
475 ValueTooBigError{
476 actual: bad_len,
477 max_allowed: usize::from(u16::MAX) - UdpHeader::LEN,
478 value_type: err::ValueType::UdpPayloadLengthIpv4,
479 }
480 );
481 }
482 }
483 }
484
485 proptest! {
486 #[test]
487 fn calc_checksum_ipv4_raw(
488 source_port in any::<u16>(),
489 destination_port in any::<u16>(),
490 dummy_checksum in any::<u16>(),
491 ipv4 in ipv4_any(),
492 payload in proptest::collection::vec(any::<u8>(), 0..20),
493 bad_len in ((core::u16::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
494 ) {
495 {
497 let header = UdpHeader {
498 source_port,
499 destination_port,
500 length: (UdpHeader::LEN + payload.len()) as u16,
501 checksum: dummy_checksum,
502 };
503
504 assert_eq!(
505 header.calc_checksum_ipv4_raw(
506 ipv4.source,
507 ipv4.destination,
508 &payload
509 ).unwrap(),
510 expected_udp_ipv4_checksum(
511 ipv4.source,
512 ipv4.destination,
513 &header,
514 &payload
515 )
516 );
517 }
518
519 {
522 let base = UdpHeader {
523 source_port: 0,
524 destination_port,
525 length: (UdpHeader::LEN + payload.len()) as u16,
526 checksum: dummy_checksum,
527 };
528 let sourceless_checksum = !(expected_udp_ipv4_checksum(
532 ipv4.source,
533 ipv4.destination,
534 &base,
535 &payload
536 ).to_le());
537
538 let header = {
541 let mut header = base.clone();
542 header.source_port = 0xffff - sourceless_checksum;
543 header
544 };
545
546 assert_eq!(
547 0xffff,
548 header.calc_checksum_ipv4_raw(
549 ipv4.source,
550 ipv4.destination,
551 &payload
552 ).unwrap()
553 );
554 }
555
556 {
558 let header = UdpHeader {
559 source_port,
560 destination_port,
561 length: (UdpHeader::LEN + payload.len()) as u16,
563 checksum: dummy_checksum,
564 };
565 let too_big_slice = unsafe {
568 use core::ptr::NonNull;
572 core::slice::from_raw_parts(
573 NonNull::<u8>::dangling().as_ptr(),
574 bad_len
575 )
576 };
577 assert_eq!(
578 header.calc_checksum_ipv4_raw(
579 ipv4.source,
580 ipv4.destination,
581 too_big_slice
582 ).unwrap_err(),
583 ValueTooBigError{
584 actual: bad_len,
585 max_allowed: (core::u16::MAX as usize) - UdpHeader::LEN,
586 value_type: ValueType::UdpPayloadLengthIpv4,
587 }
588 );
589 }
590 }
591 }
592
593 fn expected_udp_ipv6_checksum(
595 source: [u8; 16],
596 destination: [u8; 16],
597 udp_header: &UdpHeader,
598 payload: &[u8],
599 ) -> u16 {
600 checksum::Sum16BitWords::new()
601 .add_16bytes(source)
603 .add_16bytes(destination)
604 .add_2bytes([0, ip_number::UDP.0])
605 .add_4bytes(u32::from(udp_header.length).to_be_bytes())
606 .add_2bytes(udp_header.source_port.to_be_bytes())
608 .add_2bytes(udp_header.destination_port.to_be_bytes())
609 .add_2bytes(udp_header.length.to_be_bytes())
610 .add_2bytes([0, 0]) .add_slice(payload)
612 .to_ones_complement_with_no_zero()
613 .to_be()
614 }
615
616 proptest! {
617 #[test]
618 fn with_ipv6_checksum(
619 source_port in any::<u16>(),
620 destination_port in any::<u16>(),
621 ipv6 in ipv6_any(),
622 payload in proptest::collection::vec(any::<u8>(), 0..20),
623 bad_len in ((core::u16::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
624 ) {
625 assert_eq!(
627 UdpHeader::with_ipv6_checksum(
628 source_port,
629 destination_port,
630 &ipv6,
631 &payload
632 ).unwrap(),
633 {
634 let mut expected = UdpHeader {
635 source_port,
636 destination_port,
637 length: (UdpHeader::LEN + payload.len()) as u16,
638 checksum: 0,
639 };
640 let checksum = expected_udp_ipv6_checksum(
641 ipv6.source,
642 ipv6.destination,
643 &expected,
644 &payload
645 );
646 expected.checksum = checksum;
647 expected
648 }
649 );
650
651 {
654 let base = UdpHeader {
655 source_port: 0,
656 destination_port,
657 length: (UdpHeader::LEN + payload.len()) as u16,
658 checksum: 0,
659 };
660 let sourceless_checksum = !(expected_udp_ipv6_checksum(
664 ipv6.source,
665 ipv6.destination,
666 &base,
667 &payload
668 ).to_le());
669
670 assert_eq!(
671 UdpHeader::with_ipv6_checksum(
672 0xffff - sourceless_checksum,
675 destination_port,
676 &ipv6,
677 &payload
678 ).unwrap(),
679 UdpHeader{
680 source_port: 0xffff - sourceless_checksum,
681 destination_port,
682 length: base.length,
683 checksum: 0xffff
684 }
685 );
686 }
687
688 {
690 let too_big_slice = unsafe {
693 use core::ptr::NonNull;
697 core::slice::from_raw_parts(
698 NonNull::<u8>::dangling().as_ptr(),
699 bad_len
700 )
701 };
702 assert_eq!(
703 UdpHeader::with_ipv6_checksum(
704 source_port,
705 destination_port,
706 &ipv6,
707 &too_big_slice
708 ).unwrap_err(),
709 ValueTooBigError{
710 actual: bad_len,
711 max_allowed: usize::from(u16::MAX) - UdpHeader::LEN,
712 value_type: err::ValueType::UdpPayloadLengthIpv6,
713 }
714 );
715 }
716 }
717 }
718
719 proptest! {
720 #[test]
721 #[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
722 fn calc_checksum_ipv6(
723 source_port in any::<u16>(),
724 destination_port in any::<u16>(),
725 ipv6 in ipv6_any(),
726 payload in proptest::collection::vec(any::<u8>(), 0..20),
727 bad_len in ((core::u32::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
728 ) {
729 assert_eq!(
731 UdpHeader::with_ipv6_checksum(
732 source_port,
733 destination_port,
734 &ipv6,
735 &payload
736 ).unwrap(),
737 {
738 let mut expected = UdpHeader {
739 source_port,
740 destination_port,
741 length: (UdpHeader::LEN + payload.len()) as u16,
742 checksum: 0,
743 };
744 let checksum = expected_udp_ipv6_checksum(
745 ipv6.source,
746 ipv6.destination,
747 &expected,
748 &payload
749 );
750 expected.checksum = checksum;
751 expected
752 }
753 );
754
755 {
758 let base = UdpHeader {
759 source_port: 0,
760 destination_port,
761 length: (UdpHeader::LEN + payload.len()) as u16,
762 checksum: 0,
763 };
764 let sourceless_checksum = !(expected_udp_ipv6_checksum(
768 ipv6.source,
769 ipv6.destination,
770 &base,
771 &payload
772 ).to_le());
773
774 assert_eq!(
775 UdpHeader::with_ipv6_checksum(
776 0xffff - sourceless_checksum,
779 destination_port,
780 &ipv6,
781 &payload
782 ).unwrap(),
783 UdpHeader{
784 source_port: 0xffff - sourceless_checksum,
785 destination_port,
786 length: base.length,
787 checksum: 0xffff
788 }
789 );
790 }
791
792 {
794 let too_big_slice = unsafe {
797 use core::ptr::NonNull;
801 core::slice::from_raw_parts(
802 NonNull::<u8>::dangling().as_ptr(),
803 bad_len
804 )
805 };
806 assert_eq!(
807 UdpHeader::with_ipv6_checksum(
808 source_port,
809 destination_port,
810 &ipv6,
811 &too_big_slice
812 ).unwrap_err(),
813 ValueTooBigError{
814 actual: bad_len,
815 max_allowed: usize::from(u16::MAX) - UdpHeader::LEN,
816 value_type: err::ValueType::UdpPayloadLengthIpv6,
817 }
818 );
819 }
820 }
821 }
822
823 proptest! {
824 #[test]
825 #[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
826 fn calc_checksum_ipv6_raw(
827 source_port in any::<u16>(),
828 destination_port in any::<u16>(),
829 dummy_checksum in any::<u16>(),
830 ipv6 in ipv6_any(),
831 payload in proptest::collection::vec(any::<u8>(), 0..20),
832 bad_len in ((core::u32::MAX as usize) - UdpHeader::LEN + 1)..=(isize::MAX as usize),
833 ) {
834 {
836 let header = UdpHeader {
837 source_port,
838 destination_port,
839 length: (UdpHeader::LEN + payload.len()) as u16,
840 checksum: dummy_checksum,
841 };
842
843 assert_eq!(
844 header.calc_checksum_ipv6_raw(
845 ipv6.source,
846 ipv6.destination,
847 &payload
848 ).unwrap(),
849 expected_udp_ipv6_checksum(
850 ipv6.source,
851 ipv6.destination,
852 &header,
853 &payload
854 )
855 );
856 }
857
858 {
861 let base = UdpHeader {
862 source_port: 0,
863 destination_port,
864 length: (UdpHeader::LEN + payload.len()) as u16,
865 checksum: dummy_checksum,
866 };
867 let sourceless_checksum = !(expected_udp_ipv6_checksum(
871 ipv6.source,
872 ipv6.destination,
873 &base,
874 &payload
875 ).to_le());
876
877 let header = {
880 let mut header = base.clone();
881 header.source_port = 0xffff - sourceless_checksum;
882 header
883 };
884
885 assert_eq!(
886 0xffff,
887 header.calc_checksum_ipv6_raw(
888 ipv6.source,
889 ipv6.destination,
890 &payload
891 ).unwrap()
892 );
893 }
894
895 {
897 let header = UdpHeader {
898 source_port,
899 destination_port,
900 length: (UdpHeader::LEN + payload.len()) as u16,
902 checksum: dummy_checksum,
903 };
904 let too_big_slice = unsafe {
907 use core::ptr::NonNull;
911 core::slice::from_raw_parts(
912 NonNull::<u8>::dangling().as_ptr(),
913 bad_len
914 )
915 };
916 assert_eq!(
917 header.calc_checksum_ipv6_raw(
918 ipv6.source,
919 ipv6.destination,
920 too_big_slice
921 ).unwrap_err(),
922 ValueTooBigError{
923 actual: bad_len,
924 max_allowed: (core::u32::MAX as usize) - UdpHeader::LEN,
925 value_type: ValueType::UdpPayloadLengthIpv6,
926 }
927 );
928 }
929 }
930 }
931
932 proptest! {
933 #[test]
934 fn from_slice(
935 input in udp_any(),
936 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
937 ) {
938 let mut buffer: Vec<u8> = Vec::with_capacity(8 + dummy_data.len());
940 input.write(&mut buffer).unwrap();
941 buffer.extend(&dummy_data[..]);
942
943 {
945 let (result, rest) = UdpHeader::from_slice(&buffer[..]).unwrap();
946 assert_eq!(result, input);
947 assert_eq!(rest, &buffer[8..]);
948 }
949 #[allow(deprecated)]
950 {
951 let (result, rest) = UdpHeader::read_from_slice(&buffer[..]).unwrap();
952 assert_eq!(result, input);
953 assert_eq!(rest, &buffer[8..]);
954 }
955
956 for len in 0..8 {
958 assert_eq!(
959 UdpHeader::from_slice(&buffer[0..len]).unwrap_err(),
960 err::LenError{
961 required_len: UdpHeader::LEN,
962 len: len,
963 len_source: LenSource::Slice,
964 layer: err::Layer::UdpHeader,
965 layer_start_offset: 0,
966 }
967 );
968 }
969 }
970 }
971
972 proptest! {
973 #[test]
974 fn from_bytes(input in udp_any()) {
975 assert_eq!(
976 input,
977 UdpHeader::from_bytes(
978 input.to_bytes()
979 )
980 );
981 }
982 }
983
984 proptest! {
985 #[test]
986 fn read(
987 input in udp_any(),
988 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
989 ) {
990 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len() + dummy_data.len());
992 input.write(&mut buffer).unwrap();
993 buffer.extend(&dummy_data[..]);
994
995 {
997 let mut cursor = Cursor::new(&buffer);
998 let result = UdpHeader::read(&mut cursor).unwrap();
999 assert_eq!(result, input);
1000 assert_eq!(8, cursor.position());
1001 }
1002
1003 for len in 0..8 {
1005 let mut cursor = Cursor::new(&buffer[0..len]);
1006 assert!(
1007 UdpHeader::read(&mut cursor)
1008 .is_err()
1009 );
1010 }
1011 }
1012 }
1013
1014 proptest! {
1015 #[test]
1016 fn write(input in udp_any()) {
1017 {
1019 let mut result = Vec::with_capacity(input.header_len());
1020 input.write(&mut result).unwrap();
1021 assert_eq!(
1022 &result[..],
1023 input.to_bytes()
1024 );
1025 }
1026
1027 for len in 0..8 {
1029 let mut buffer = [0u8; 8];
1030 let mut cursor = Cursor::new(&mut buffer[..len]);
1031 assert!(
1032 input.write(&mut cursor)
1033 .is_err()
1034 );
1035 }
1036 }
1037 }
1038
1039 proptest! {
1040 #[test]
1041 fn to_bytes(input in udp_any()) {
1042 let s_be = input.source_port.to_be_bytes();
1043 let d_be = input.destination_port.to_be_bytes();
1044 let l_be = input.length.to_be_bytes();
1045 let c_be = input.checksum.to_be_bytes();
1046
1047 assert_eq!(
1048 input.to_bytes(),
1049 [
1050 s_be[0],
1051 s_be[1],
1052 d_be[0],
1053 d_be[1],
1054 l_be[0],
1055 l_be[1],
1056 c_be[0],
1057 c_be[1],
1058 ]
1059 );
1060 }
1061 }
1062
1063 #[test]
1064 fn default() {
1065 let actual: UdpHeader = Default::default();
1066 assert_eq!(actual.source_port, 0);
1067 assert_eq!(actual.destination_port, 0);
1068 assert_eq!(actual.length, 0);
1069 assert_eq!(actual.checksum, 0);
1070 }
1071
1072 proptest! {
1073 #[test]
1074 fn clone_eq(input in udp_any()) {
1075 assert_eq!(input, input.clone());
1076 {
1077 let mut other = input.clone();
1078 other.source_port = !input.source_port;
1079 assert!(input != other);
1080 }
1081 }
1082 }
1083
1084 proptest! {
1085 #[test]
1086 fn dbg(input in udp_any()) {
1087 assert_eq!(
1088 &format!(
1089 "UdpHeader {{ source_port: {}, destination_port: {}, length: {}, checksum: {} }}",
1090 input.source_port,
1091 input.destination_port,
1092 input.length,
1093 input.checksum,
1094 ),
1095 &format!("{:?}", input)
1096 );
1097 }
1098 }
1099}