crowdstrike_cloudproto/framing/
packet.rs

1use crate::framing::{CloudProtoError, CloudProtoVersion};
2use crate::services::CloudProtoMagic;
3use byteorder::{ReadBytesExt, BE};
4use std::io::Cursor;
5
6pub(crate) const COMMON_HDR_LEN: usize = 8;
7
8/// The common framing packet structure of the protocol
9#[derive(Eq, PartialEq, Debug, Clone)]
10pub struct CloudProtoPacket {
11    /// One magic value corresponds to one backend service
12    pub magic: CloudProtoMagic,
13    /// Each value can have a different interpretation for each backend service
14    /// There is no common definition of packet kind at the framing level
15    pub kind: u8,
16    pub version: CloudProtoVersion,
17    pub payload: Vec<u8>,
18}
19
20impl CloudProtoPacket {
21    pub(crate) fn from_buf(buf: &[u8]) -> Result<Self, CloudProtoError> {
22        let mut reader = Cursor::new(buf);
23        let magic = reader.read_u8()?.into();
24        let kind = reader.read_u8()?;
25        let version = reader.read_u16::<BE>()?.into();
26        let pkt_size = reader.read_u32::<BE>()? as usize - COMMON_HDR_LEN;
27        let remaining_size = buf.len() - reader.position() as usize;
28        if remaining_size != pkt_size {
29            return Err(CloudProtoError::BadFrameSize(remaining_size, pkt_size));
30        }
31        let payload = buf[reader.position() as usize..].to_vec();
32        Ok(Self {
33            magic,
34            kind,
35            version,
36            payload,
37        })
38    }
39
40    pub(crate) fn to_buf(&self) -> Vec<u8> {
41        use byteorder::WriteBytesExt;
42        use std::io::Write;
43
44        let mut buf = Vec::new();
45        let mut writer = Cursor::new(&mut buf);
46        writer.write_u8(self.magic.into()).unwrap();
47        writer.write_u8(self.kind).unwrap();
48        writer.write_u16::<BE>(self.version.into()).unwrap();
49        writer
50            .write_u32::<BE>((self.payload.len() + COMMON_HDR_LEN) as u32)
51            .unwrap();
52        writer.write_all(&self.payload).unwrap();
53        writer.flush().unwrap();
54        buf
55    }
56}
57
58#[cfg(test)]
59mod test {
60    use crate::framing::packet::CloudProtoPacket;
61    use crate::framing::CloudProtoVersion;
62    use crate::services::CloudProtoMagic;
63    use anyhow::Result;
64
65    #[test_log::test]
66    fn to_from_buf_serialization() -> Result<()> {
67        let pkt = CloudProtoPacket {
68            magic: CloudProtoMagic::Other(0xFF),
69            kind: 0x73,
70            version: CloudProtoVersion::Other(0x10E9),
71            payload: b"Hello world".to_vec(),
72        };
73        let pkt2 = CloudProtoPacket::from_buf(&pkt.to_buf())?;
74        assert_eq!(pkt, pkt2);
75
76        Ok(())
77    }
78}