1use std::io::{self, BufRead};
2
3use bytes::Bytes;
4#[cfg(test)]
5use proptest::prelude::*;
6use rand::{CryptoRng, RngCore};
7
8use crate::{
9 errors::Result,
10 packet::{PacketHeader, PacketTrait},
11 parsing_reader::BufReadParsing,
12 ser::Serialize,
13 types::{PacketHeaderVersion, PacketLength, Tag},
14};
15
16#[derive(derive_more::Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
21pub struct Padding {
22 packet_header: PacketHeader,
23 #[debug("{}", hex::encode(data))]
25 #[cfg_attr(test, proptest(strategy = "any::<Vec<u8>>().prop_map(Into::into)"))]
26 data: Bytes,
27}
28
29impl Padding {
30 pub fn try_from_reader<B: BufRead>(packet_header: PacketHeader, mut input: B) -> Result<Self> {
32 let data = input.rest()?.freeze();
33
34 Ok(Padding {
35 packet_header,
36 data,
37 })
38 }
39
40 pub fn new<R: CryptoRng + RngCore>(
42 mut rng: R,
43 packet_version: PacketHeaderVersion,
44 size: usize,
45 ) -> Result<Self> {
46 let mut data = vec![0u8; size];
47 rng.fill_bytes(&mut data);
48
49 let len = PacketLength::Fixed(data.len().try_into()?);
50 let packet_header = PacketHeader::from_parts(packet_version, Tag::Padding, len)?;
51
52 Ok(Padding {
53 packet_header,
54 data: data.into(),
55 })
56 }
57}
58
59impl Serialize for Padding {
60 fn to_writer<W: io::Write>(&self, writer: &mut W) -> Result<()> {
61 writer.write_all(&self.data)?;
62
63 Ok(())
64 }
65
66 fn write_len(&self) -> usize {
67 self.data.len()
68 }
69}
70
71impl PacketTrait for Padding {
72 fn packet_header(&self) -> &PacketHeader {
73 &self.packet_header
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use proptest::prelude::*;
80 use rand::SeedableRng;
81 use rand_chacha::ChaCha20Rng;
82
83 use super::*;
84 use crate::{
85 packet::{Packet, PacketHeader},
86 types::PacketLength,
87 };
88
89 #[test]
90 fn test_padding_roundtrip() {
91 let packet_raw = hex::decode("d50ec5a293072991628147d72c8f86b7").expect("valid hex");
92 let mut to_parse = std::io::Cursor::new(&packet_raw);
93 let header = PacketHeader::try_from_reader(&mut to_parse).expect("parse");
94
95 let PacketLength::Fixed(_len) = header.packet_length() else {
96 panic!("invalid parse result");
97 };
98
99 let full_packet = Packet::from_reader(header, &mut to_parse).expect("body parse");
100
101 let Packet::Padding(ref packet) = full_packet else {
102 panic!("invalid packet: {full_packet:?}");
103 };
104 assert_eq!(
105 packet.data,
106 hex::decode("c5a293072991628147d72c8f86b7").expect("valid hex")
107 );
108
109 let encoded = full_packet.to_bytes().expect("encode");
111 assert_eq!(encoded, packet_raw);
112 }
113
114 #[test]
115 fn test_padding_new() {
116 let mut rng = ChaCha20Rng::seed_from_u64(1);
117 let packet = Padding::new(&mut rng, PacketHeaderVersion::New, 20).unwrap();
118 assert_eq!(packet.data.len(), 20);
119
120 let encoded = packet.to_bytes().expect("encode");
121 assert_eq!(encoded, packet.data);
122 }
123
124 proptest! {
125 #[test]
126 fn write_len(padding: Padding) {
127 let mut buf = Vec::new();
128 padding.to_writer(&mut buf).unwrap();
129 assert_eq!(buf.len(), padding.write_len());
130 }
131
132
133 #[test]
134 fn packet_roundtrip(padding: Padding) {
135 let mut buf = Vec::new();
136 padding.to_writer(&mut buf).unwrap();
137 let new_padding = Padding::try_from_reader(padding.packet_header, &mut &buf[..]).unwrap();
138 assert_eq!(padding, new_padding);
139 }
140 }
141}