network_protocol/core/
codec.rs1use crate::config::{MAGIC_BYTES, MAX_PAYLOAD_SIZE, PROTOCOL_VERSION};
23use crate::core::packet::{Packet, HEADER_SIZE};
24use crate::error::{ProtocolError, Result};
25use bytes::{BufMut, BytesMut};
26use tokio_util::codec::{Decoder, Encoder};
27pub struct PacketCodec;
30
31impl Decoder for PacketCodec {
32 type Item = Packet;
33 type Error = ProtocolError;
34
35 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Packet>> {
49 if src.len() < HEADER_SIZE {
50 return Ok(None);
51 }
52
53 if src[0..4] != MAGIC_BYTES {
54 return Err(ProtocolError::InvalidHeader);
55 }
56 if src[4] != PROTOCOL_VERSION {
57 return Err(ProtocolError::UnsupportedVersion(src[4]));
58 }
59 let len = u32::from_be_bytes([src[5], src[6], src[7], src[8]]) as usize;
60 if len > MAX_PAYLOAD_SIZE {
61 return Err(ProtocolError::OversizedPacket(len));
62 }
63 let total_len = HEADER_SIZE + len;
64
65 if src.len() < total_len {
66 return Ok(None); }
68
69 let buf = src.split_to(total_len).freeze();
70 Packet::from_bytes(&buf).map(Some)
71 }
72}
73
74impl Encoder<Packet> for PacketCodec {
75 type Error = ProtocolError;
76
77 fn encode(&mut self, packet: Packet, dst: &mut BytesMut) -> Result<()> {
83 if packet.payload.len() > MAX_PAYLOAD_SIZE {
84 return Err(ProtocolError::OversizedPacket(packet.payload.len()));
85 }
86
87 let total_size = HEADER_SIZE + packet.payload.len();
89 dst.reserve(total_size);
90
91 dst.put_slice(&MAGIC_BYTES);
93 dst.put_u8(PROTOCOL_VERSION);
94 dst.put_u32(packet.payload.len() as u32);
95
96 dst.put_slice(&packet.payload);
98
99 Ok(())
100 }
101}
102
103#[cfg(test)]
104#[allow(clippy::unwrap_used, clippy::expect_used)]
105mod tests {
106 use super::*;
107
108 fn header(magic: [u8; 4], version: u8, len: u32) -> BytesMut {
109 let mut buf = BytesMut::new();
110 buf.put_slice(&magic);
111 buf.put_u8(version);
112 buf.put_u32(len);
113 buf
114 }
115
116 #[test]
117 fn oversized_length_is_rejected_from_the_header_alone() {
118 let mut buf = header(MAGIC_BYTES, PROTOCOL_VERSION, (MAX_PAYLOAD_SIZE + 1) as u32);
119 assert!(matches!(
120 PacketCodec.decode(&mut buf),
121 Err(ProtocolError::OversizedPacket(_))
122 ));
123 let mut buf = header(MAGIC_BYTES, PROTOCOL_VERSION, u32::MAX);
124 assert!(matches!(
125 PacketCodec.decode(&mut buf),
126 Err(ProtocolError::OversizedPacket(_))
127 ));
128 }
129
130 #[test]
131 fn bad_magic_or_version_is_rejected_from_the_header_alone() {
132 let mut buf = header(*b"HTTP", PROTOCOL_VERSION, 4);
133 assert!(matches!(
134 PacketCodec.decode(&mut buf),
135 Err(ProtocolError::InvalidHeader)
136 ));
137 let mut buf = header(MAGIC_BYTES, PROTOCOL_VERSION.wrapping_add(1), 4);
138 assert!(matches!(
139 PacketCodec.decode(&mut buf),
140 Err(ProtocolError::UnsupportedVersion(_))
141 ));
142 }
143
144 #[test]
145 fn valid_header_waits_for_the_payload() {
146 let mut buf = header(MAGIC_BYTES, PROTOCOL_VERSION, 4);
147 assert!(PacketCodec.decode(&mut buf).unwrap().is_none());
148 buf.put_slice(b"ping");
149 let packet = PacketCodec.decode(&mut buf).unwrap().unwrap();
150 assert_eq!(packet.payload, b"ping");
151 assert!(buf.is_empty());
152 }
153
154 #[test]
155 fn largest_allowed_payload_round_trips_and_larger_is_not_sent() {
156 let mut buf = BytesMut::new();
157 let packet = Packet {
158 version: PROTOCOL_VERSION,
159 payload: vec![7u8; MAX_PAYLOAD_SIZE],
160 };
161 PacketCodec.encode(packet, &mut buf).unwrap();
162 let decoded = PacketCodec.decode(&mut buf).unwrap().unwrap();
163 assert_eq!(decoded.payload.len(), MAX_PAYLOAD_SIZE);
164
165 let mut buf = BytesMut::new();
166 let too_big = Packet {
167 version: PROTOCOL_VERSION,
168 payload: vec![0u8; MAX_PAYLOAD_SIZE + 1],
169 };
170 assert!(matches!(
171 PacketCodec.encode(too_big, &mut buf),
172 Err(ProtocolError::OversizedPacket(_))
173 ));
174 assert!(buf.is_empty(), "nothing is written for a rejected packet");
175 }
176}