melin_wire_protocol/
blocking.rs1use std::io::{self, BufReader, BufWriter, Read, Write};
8
9pub const MAX_FRAME_SIZE: usize = 1024;
15
16pub struct BlockingFrameReader<R> {
27 reader: BufReader<R>,
28 buf: [u8; MAX_FRAME_SIZE],
31 frame_len: usize,
33}
34
35impl<R: Read> BlockingFrameReader<R> {
36 pub fn new(reader: R) -> Self {
37 Self {
38 reader: BufReader::new(reader),
39 buf: [0u8; MAX_FRAME_SIZE],
40 frame_len: 0,
41 }
42 }
43
44 pub fn read_frame(&mut self) -> io::Result<Option<&[u8]>> {
48 let mut len_buf = [0u8; 4];
50 match self.reader.read_exact(&mut len_buf) {
51 Ok(()) => {}
52 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),
53 Err(e) => return Err(e),
54 }
55
56 let len = u32::from_le_bytes(len_buf) as usize;
57 if len > MAX_FRAME_SIZE {
58 return Err(io::Error::new(
59 io::ErrorKind::InvalidData,
60 format!("frame too large: {len} bytes (max {MAX_FRAME_SIZE})"),
61 ));
62 }
63
64 self.reader.read_exact(&mut self.buf[..len])?;
65 self.frame_len = len;
66
67 Ok(Some(&self.buf[..len]))
68 }
69
70 pub fn frame(&self) -> &[u8] {
75 &self.buf[..self.frame_len]
76 }
77
78 pub fn get_ref(&self) -> &R {
83 self.reader.get_ref()
84 }
85}
86
87pub struct BlockingFrameWriter<W: Write> {
92 writer: BufWriter<W>,
93}
94
95impl<W: Write> BlockingFrameWriter<W> {
96 pub fn new(writer: W) -> Self {
97 Self {
98 writer: BufWriter::new(writer),
99 }
100 }
101
102 pub fn write_frame(&mut self, data: &[u8]) -> io::Result<()> {
104 self.write_frame_parts(&[data])
105 }
106
107 pub fn write_frame_parts(&mut self, parts: &[&[u8]]) -> io::Result<()> {
121 let len: usize = parts.iter().map(|part| part.len()).sum();
122 if len > MAX_FRAME_SIZE {
123 return Err(io::Error::new(
124 io::ErrorKind::InvalidInput,
125 format!("frame too large: {len} bytes (max {MAX_FRAME_SIZE})"),
126 ));
127 }
128 self.writer.write_all(&(len as u32).to_le_bytes())?;
129 for part in parts {
130 self.writer.write_all(part)?;
131 }
132 Ok(())
133 }
134
135 pub fn flush(&mut self) -> io::Result<()> {
137 self.writer.flush()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use std::net::{TcpListener, TcpStream};
145
146 #[test]
147 fn frame_round_trip_blocking() {
148 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
149 let addr = listener.local_addr().unwrap();
150
151 let client = TcpStream::connect(addr).unwrap();
152 let (server, _) = listener.accept().unwrap();
153
154 let mut writer = BlockingFrameWriter::new(client);
155 let mut reader = BlockingFrameReader::new(server);
156
157 let data = b"hello melin";
158 writer.write_frame(data).unwrap();
159 writer.flush().unwrap();
160
161 let received = reader.read_frame().unwrap().unwrap();
162 assert_eq!(received, data);
163 }
164
165 #[test]
166 fn frame_parts_arrive_as_one_frame() {
167 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
168 let addr = listener.local_addr().unwrap();
169
170 let client = TcpStream::connect(addr).unwrap();
171 let (server, _) = listener.accept().unwrap();
172
173 let mut writer = BlockingFrameWriter::new(client);
174 let mut reader = BlockingFrameReader::new(server);
175
176 writer
177 .write_frame_parts(&[&7u64.to_le_bytes(), &[0x10], b"body"])
178 .unwrap();
179 writer.write_frame_parts(&[]).unwrap();
180 writer.flush().unwrap();
181
182 let expected = [&7u64.to_le_bytes()[..], &[0x10], b"body"].concat();
183 assert_eq!(reader.read_frame().unwrap().unwrap(), expected);
184 assert_eq!(reader.read_frame().unwrap().unwrap(), b"");
185 }
186
187 #[test]
188 fn an_oversized_frame_is_refused_before_anything_is_written() {
189 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
190 let addr = listener.local_addr().unwrap();
191
192 let client = TcpStream::connect(addr).unwrap();
193 let (server, _) = listener.accept().unwrap();
194
195 let mut writer = BlockingFrameWriter::new(client);
196 let mut reader = BlockingFrameReader::new(server);
197
198 let body = vec![0xAB; MAX_FRAME_SIZE];
201 let err = writer.write_frame_parts(&[&[0x01], &body]).unwrap_err();
202 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
203
204 writer.write_frame(&body).unwrap();
207 writer.flush().unwrap();
208 assert_eq!(reader.read_frame().unwrap().unwrap(), &body[..]);
209 }
210
211 #[test]
212 fn clean_disconnect_returns_none() {
213 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
214 let addr = listener.local_addr().unwrap();
215
216 let client = TcpStream::connect(addr).unwrap();
217 let (server, _) = listener.accept().unwrap();
218
219 drop(client);
220
221 let mut reader = BlockingFrameReader::new(server);
222 let result = reader.read_frame().unwrap();
223 assert!(result.is_none());
224 }
225
226 #[test]
227 fn oversized_frame_rejected() {
228 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
229 let addr = listener.local_addr().unwrap();
230
231 let mut client = TcpStream::connect(addr).unwrap();
232 let (server, _) = listener.accept().unwrap();
233
234 let fake_len = 2_000_000u32;
236 client.write_all(&fake_len.to_le_bytes()).unwrap();
237
238 let mut reader = BlockingFrameReader::new(server);
239 let result = reader.read_frame();
240 assert!(result.is_err());
241 }
242
243 #[test]
244 fn multiple_frames_in_sequence() {
245 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
246 let addr = listener.local_addr().unwrap();
247
248 let client = TcpStream::connect(addr).unwrap();
249 let (server, _) = listener.accept().unwrap();
250
251 let mut writer = BlockingFrameWriter::new(client);
252 let mut reader = BlockingFrameReader::new(server);
253
254 for i in 0u32..100 {
255 writer.write_frame(&i.to_le_bytes()).unwrap();
256 }
257 writer.flush().unwrap();
258
259 for i in 0u32..100 {
260 let frame = reader.read_frame().unwrap().unwrap();
261 assert_eq!(frame, i.to_le_bytes());
262 }
263 }
264}