plabble-codec 0.1.0

Plabble Transport Protocol codec
Documentation
use crate::{
    abstractions::MAC_SIZE,
    codec::{header::RequestHeader, ptp_packet::PtpPacket},
};

use super::RequestBody;

/// The request packet
///
/// # Fields
///
/// * `header` - the header of the packet
/// * `body` - the body of the packet
/// * `mac` - the mac of the packet (optional)
pub struct RequestPacket {
    pub header: RequestHeader,
    pub body: RequestBody,
    pub mac: Option<[u8; MAC_SIZE]>,
}

impl PtpPacket<RequestHeader, RequestBody> for RequestPacket {
    fn get_header(&self) -> &RequestHeader {
        &self.header
    }

    fn get_body(&self) -> &RequestBody {
        &self.body
    }

    fn new(header: RequestHeader, body: RequestBody, mac: Option<[u8; MAC_SIZE]>) -> Self {
        /*if body.get_type() != header.packet_type() {
            // TODO: return error?
        }*/

        Self { header, body, mac }
    }

    fn get_mac(&self) -> Option<&[u8; MAC_SIZE]> {
        self.mac.as_ref()
    }
}

#[cfg(test)]
mod parse_test {
    use crate::{
        abstractions::{SerializationError, SerializationInfo},
        codec::common::SlotRange,
    };

    use super::*;

    #[test]
    fn cant_deserialize_nothing() {
        let bytes = &[];
        let packet = RequestPacket::from_bytes(bytes, SerializationInfo::PacketType(0));
        assert_eq!(SerializationError::TooFewBytes(17), packet.err().unwrap()); // 17 is minimum request size
    }

    #[test]
    fn cant_deserialize_connect_without_key() {
        let bytes = &[
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0x01,
        ];
        let packet = RequestPacket::from_bytes(bytes, SerializationInfo::PacketType(0));
        assert_eq!(SerializationError::TooFewBytes(16), packet.err().unwrap()); // because header is already sliced off in ptp_packet::from_bytes method
    }

    #[test]
    fn can_deserialize_plain_packet() {
        let data = &[
            0x01, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 5, 0, 10,
        ];
        let packet = RequestPacket::from_bytes(data, SerializationInfo::None).unwrap();
        if let RequestBody::CREATE(SlotRange { from, to }) = packet.body {
            assert_eq!(Some(5), from);
            assert_eq!(Some(10), to);
        } else {
            panic!("Not a create");
        }
    }
}

#[cfg(test)]
mod serialization_test {
    use std::collections::HashMap;

    use crate::{
        abstractions::{Serializable, SerializationInfo},
        codec::{
            common::SlotRange,
            objects::BucketId,
            ptp_packet::{PtpBody, PtpHeader},
        },
    };

    use super::*;

    #[test]
    fn can_serialize_plain_packet() {
        let body = RequestBody::CREATE(SlotRange {
            from: Some(5),
            to: Some(10),
        });
        let id = BucketId::from_bytes(
            &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
            None,
        )
        .unwrap();

        let header = RequestHeader::new(body.packet_type(), Some(id));
        let packet = RequestPacket::new(header, body, None);

        assert_eq!(
            vec!(21, 0x01, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 5, 0, 10),
            packet.get_bytes(SerializationInfo::None, true).unwrap()
        );
    }

    #[test]
    fn can_serialize_simple_packet_with_authentication() {
        let key = &[1u8; 32];
        let body = RequestBody::CREATE(SlotRange {
            from: Some(5),
            to: Some(10),
        });
        let id = BucketId::from_bytes(
            &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
            None,
        )
        .unwrap();

        let mut header = RequestHeader::new(body.packet_type(), Some(id));
        header.set_mac(true);
        let packet = RequestPacket::new(header, body, None);

        let bytes = packet
            .get_bytes(
                SerializationInfo::UseAuthentication(key.clone(), None),
                false,
            )
            .unwrap();
        assert_eq!(
            vec![
                17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 5, 0, 10, 34, 167,
                182, 64, 46, 228, 223, 54, 255, 240, 62, 82, 191, 236, 68, 50
            ],
            bytes
        );

        let packet = RequestPacket::from_bytes(
            &bytes,
            SerializationInfo::UseAuthentication(key.clone(), None),
        )
        .unwrap();
        assert_eq!(
            bytes,
            packet
                .get_bytes(
                    SerializationInfo::UseAuthentication(key.clone(), None),
                    false
                )
                .unwrap()
        );
    }

    #[test]
    fn can_serialize_complex_packet_with_authentication() {
        let key = &[1u8; 32];
        let body = RequestBody::PUT {
            slots: HashMap::from([
                (5, vec![1, 2, 3, 4, 5, 6, 7, 8]),
                (19412, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
            ]),
        };
        let id = BucketId::from_bytes(
            &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
            None,
        )
        .unwrap();

        let mut header = RequestHeader::new(body.packet_type(), Some(id));
        header.set_mac(true);
        let packet = RequestPacket::new(header, body, None);

        let bytes = packet
            .get_bytes(
                SerializationInfo::UseAuthentication(key.clone(), None),
                false,
            )
            .unwrap();
        assert_eq!(
            vec![
                18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 5, 8, 1, 2, 3, 4, 5,
                6, 7, 8, 75, 212, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 74, 151, 106, 78, 124, 179,
                92, 165, 78, 72, 27, 181, 100, 37, 243, 29
            ],
            bytes
        );

        let packet = RequestPacket::from_bytes(
            &bytes,
            SerializationInfo::UseAuthentication(key.clone(), None),
        )
        .unwrap();
        assert_eq!(
            bytes,
            packet
                .get_bytes(
                    SerializationInfo::UseAuthentication(key.clone(), None),
                    false
                )
                .unwrap()
        );
    }
}