Skip to main content

chunkedge_protocol/
decode.rs

1#[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/// The AES block cipher with a 128 bit key, using the CFB-8 mode of
12/// operation.
13#[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            // Not enough data arrived yet.
48            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            // Is this packet compressed?
72            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                // TODO: use libdeflater or zune-inflate?
85                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        // Decode the leading packet ID.
126        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        // Don't forget to decrypt the data we already have.
156        Self::decrypt_bytes(&mut cipher, &mut self.buf);
157
158        self.cipher = Some(cipher);
159    }
160
161    /// Decrypts the provided byte slice in place using the cipher, without
162    /// consuming the cipher.
163    #[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    /// The ID of the decoded packet.
204    pub id: i32,
205    /// The contents of the packet after the leading `VarInt` ID.
206    pub body: BytesMut,
207}
208
209impl PacketFrame {
210    /// Attempts to decode this packet as type `P`. An error is returned if the
211    /// packet ID does not match, the body of the packet failed to decode, or
212    /// some input was missed.
213    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        // packet_len = 2 encoded in two bytes, then packet_id = 0 encoded in two bytes.
249        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        // packet_len = 4 encoded in two bytes, then uncompressed data_len = 0 encoded in two bytes, then packet_id = 0 encoded in two bytes.
265        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}