chunkedge_protocol/
decode.rs1#[cfg(feature = "encryption")]
2use aes::cipher::KeyIvInit;
3use anyhow::{Context, bail, ensure};
4use bytes::{Buf, BytesMut};
5use chunkedge_binary::{Decode, VarInt, VarIntDecodeError};
6
7#[cfg(feature = "compression")]
8use crate::CompressionThreshold;
9use crate::{MAX_PACKET_SIZE, Packet};
10
11#[cfg(feature = "encryption")]
14type Cipher = cfb8::Decryptor<aes::Aes128>;
15
16#[derive(Default)]
17pub struct PacketDecoder {
18 buf: BytesMut,
19 #[cfg(feature = "compression")]
20 decompress_buf: BytesMut,
21 #[cfg(feature = "compression")]
22 threshold: CompressionThreshold,
23 #[cfg(feature = "encryption")]
24 cipher: Option<Cipher>,
25}
26
27impl PacketDecoder {
28 pub fn new() -> Self {
29 Self::default()
30 }
31
32 pub fn try_next_packet(&mut self) -> anyhow::Result<Option<PacketFrame>> {
33 let mut r = &self.buf[..];
34
35 let packet_len = match VarInt::decode_partial(&mut r) {
36 Ok(len) => len,
37 Err(VarIntDecodeError::Incomplete) => return Ok(None),
38 Err(VarIntDecodeError::TooLarge) => bail!("malformed packet length VarInt"),
39 };
40
41 ensure!(
42 (0..=MAX_PACKET_SIZE).contains(&packet_len),
43 "packet length of {packet_len} is out of bounds"
44 );
45
46 if r.len() < packet_len as usize {
47 return Ok(None);
49 }
50
51 let packet_len_len = self.buf.len() - r.len();
52
53 let mut data;
54
55 #[cfg(feature = "compression")]
56 if self.threshold.0 >= 0 {
57 use std::io::Write;
58
59 use bytes::BufMut;
60 use flate2::write::ZlibDecoder;
61
62 r = &r[..packet_len as usize];
63
64 let data_len = VarInt::decode(&mut r)?.0;
65
66 ensure!(
67 (0..MAX_PACKET_SIZE).contains(&data_len),
68 "decompressed packet length of {data_len} is out of bounds"
69 );
70
71 if data_len > 0 {
73 ensure!(
74 data_len >= self.threshold.0,
75 "decompressed packet length of {data_len} is below the compression threshold \
76 of {}",
77 self.threshold.0
78 );
79
80 debug_assert!(self.decompress_buf.is_empty());
81
82 self.decompress_buf.put_bytes(0, data_len as usize);
83
84 let mut z = ZlibDecoder::new(&mut self.decompress_buf[..]);
86
87 z.write_all(r)?;
88
89 ensure!(
90 z.finish()?.is_empty(),
91 "decompressed packet length is shorter than expected"
92 );
93
94 self.buf.advance(packet_len_len + packet_len as usize);
95
96 data = self.decompress_buf.split();
97 } else {
98 debug_assert_eq!(data_len, 0);
99
100 ensure!(
101 r.len() < self.threshold.0 as usize,
102 "uncompressed packet length of {} is not below the compression threshold of {}",
103 r.len(),
104 self.threshold.0
105 );
106
107 let data_len_len = packet_len as usize - r.len();
108 let remaining_len = r.len();
109
110 self.buf.advance(packet_len_len + data_len_len);
111
112 data = self.buf.split_to(remaining_len);
113 }
114 } else {
115 self.buf.advance(packet_len_len);
116 data = self.buf.split_to(packet_len as usize);
117 }
118
119 #[cfg(not(feature = "compression"))]
120 {
121 self.buf.advance(packet_len_len);
122 data = self.buf.split_to(packet_len as usize);
123 }
124
125 r = &data[..];
127 let packet_id = VarInt::decode(&mut r)
128 .context("failed to decode packet ID")?
129 .0;
130
131 data.advance(data.len() - r.len());
132
133 Ok(Some(PacketFrame {
134 id: packet_id,
135 body: data,
136 }))
137 }
138
139 #[cfg(feature = "compression")]
140 pub fn compression(&self) -> CompressionThreshold {
141 self.threshold
142 }
143
144 #[cfg(feature = "compression")]
145 pub fn set_compression(&mut self, threshold: CompressionThreshold) {
146 self.threshold = threshold;
147 }
148
149 #[cfg(feature = "encryption")]
150 pub fn enable_encryption(&mut self, key: &[u8; 16]) {
151 assert!(self.cipher.is_none(), "encryption is already enabled");
152
153 let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key");
154
155 Self::decrypt_bytes(&mut cipher, &mut self.buf);
157
158 self.cipher = Some(cipher);
159 }
160
161 #[cfg(feature = "encryption")]
164 fn decrypt_bytes(cipher: &mut Cipher, bytes: &mut [u8]) {
165 cipher.decrypt(bytes);
166 }
167
168 pub fn queue_bytes(&mut self, mut bytes: BytesMut) {
169 #![allow(unused_mut)]
170
171 #[cfg(feature = "encryption")]
172 if let Some(cipher) = &mut self.cipher {
173 Self::decrypt_bytes(cipher, &mut bytes);
174 }
175
176 self.buf.unsplit(bytes);
177 }
178
179 pub fn queue_slice(&mut self, bytes: &[u8]) {
180 #[cfg(feature = "encryption")]
181 let len = self.buf.len();
182
183 self.buf.extend_from_slice(bytes);
184
185 #[cfg(feature = "encryption")]
186 if let Some(cipher) = &mut self.cipher {
187 let slice = &mut self.buf[len..];
188 Self::decrypt_bytes(cipher, slice);
189 }
190 }
191
192 pub fn take_capacity(&mut self) -> BytesMut {
193 self.buf.split_off(self.buf.len())
194 }
195
196 pub fn reserve(&mut self, additional: usize) {
197 self.buf.reserve(additional);
198 }
199}
200
201#[derive(Clone, Debug)]
202pub struct PacketFrame {
203 pub id: i32,
205 pub body: BytesMut,
207}
208
209impl PacketFrame {
210 pub fn decode<'a, P>(&'a self) -> anyhow::Result<P>
214 where
215 P: Packet + Decode<'a>,
216 {
217 ensure!(
218 P::ID == self.id,
219 "packet ID mismatch while decoding '{}': expected {}, got {}",
220 P::NAME,
221 P::ID,
222 self.id
223 );
224
225 let mut r = &self.body[..];
226
227 let pkt = P::decode(&mut r)?;
228
229 ensure!(
230 r.is_empty(),
231 "missed {} bytes while decoding '{}'",
232 r.len(),
233 P::NAME
234 );
235
236 Ok(pkt)
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn accepts_padded_packet_length_and_packet_id() {
246 let mut decoder = PacketDecoder::new();
247
248 decoder.queue_slice(&[0x82, 0x00, 0x80, 0x00]);
250
251 let frame = decoder.try_next_packet().unwrap().unwrap();
252
253 assert_eq!(frame.id, 0);
254 assert!(frame.body.is_empty());
255 assert!(decoder.try_next_packet().unwrap().is_none());
256 }
257
258 #[cfg(feature = "compression")]
259 #[test]
260 fn accepts_padded_uncompressed_data_length_and_packet_id() {
261 let mut decoder = PacketDecoder::new();
262 decoder.set_compression(CompressionThreshold(256));
263
264 decoder.queue_slice(&[0x84, 0x00, 0x80, 0x00, 0x80, 0x00]);
266
267 let frame = decoder.try_next_packet().unwrap().unwrap();
268
269 assert_eq!(frame.id, 0);
270 assert!(frame.body.is_empty());
271 assert!(decoder.try_next_packet().unwrap().is_none());
272 }
273
274 #[cfg(feature = "compression")]
275 #[test]
276 fn accepts_compressed_packet_at_compression_threshold() {
277 use std::io::Read;
278
279 use chunkedge_binary::Encode;
280 use flate2::Compression;
281 use flate2::bufread::ZlibEncoder;
282
283 let threshold = 3;
284 let mut decoder = PacketDecoder::new();
285 decoder.set_compression(CompressionThreshold(threshold));
286
287 let uncompressed_packet = [0x00, 0xab, 0xcd];
288 let mut compressed_packet = vec![];
289 ZlibEncoder::new(&uncompressed_packet[..], Compression::new(4))
290 .read_to_end(&mut compressed_packet)
291 .unwrap();
292
293 let packet_len = VarInt(threshold).written_size() + compressed_packet.len();
294 let mut packet = vec![];
295 VarInt(packet_len as i32).encode(&mut packet).unwrap();
296 VarInt(threshold).encode(&mut packet).unwrap();
297 packet.extend_from_slice(&compressed_packet);
298
299 decoder.queue_slice(&packet);
300
301 let frame = decoder.try_next_packet().unwrap().unwrap();
302
303 assert_eq!(frame.id, 0);
304 assert_eq!(&frame.body[..], [0xab, 0xcd]);
305 assert!(decoder.try_next_packet().unwrap().is_none());
306 }
307}