ferogram_connect/
transport_intermediate.rs1use crate::ConnectError;
14use tokio::io::{AsyncReadExt, AsyncWriteExt};
15use tokio::net::TcpStream;
16
17pub struct IntermediateTransport {
26 stream: TcpStream,
27 init_sent: bool,
28}
29
30impl IntermediateTransport {
31 pub async fn connect(addr: &str) -> Result<Self, ConnectError> {
33 let stream = TcpStream::connect(addr).await?;
34 Ok(Self {
35 stream,
36 init_sent: false,
37 })
38 }
39
40 pub fn from_stream(stream: TcpStream) -> Self {
42 Self {
43 stream,
44 init_sent: false,
45 }
46 }
47
48 pub async fn send(&mut self, data: &[u8]) -> Result<(), ConnectError> {
50 if !self.init_sent {
51 self.stream.write_all(&[0xee, 0xee, 0xee, 0xee]).await?;
52 self.init_sent = true;
53 }
54 let len = (data.len() as u32).to_le_bytes();
55 self.stream.write_all(&len).await?;
56 self.stream.write_all(data).await?;
57 Ok(())
58 }
59
60 pub async fn recv(&mut self) -> Result<Vec<u8>, ConnectError> {
62 let mut len_buf = [0u8; 4];
63 self.stream.read_exact(&mut len_buf).await?;
64 let raw = i32::from_le_bytes(len_buf);
65 if raw < 0 {
66 return Err(ConnectError::Io(std::io::Error::new(
67 std::io::ErrorKind::ConnectionRefused,
68 format!("transport error: {raw}"),
69 )));
70 }
71 let len = raw as usize;
72 let mut buf = vec![0u8; len];
73 self.stream.read_exact(&mut buf).await?;
74 Ok(buf)
75 }
76
77 pub fn into_inner(self) -> TcpStream {
80 self.stream
81 }
82}
83
84pub struct PaddedIntermediateTransport {
95 stream: TcpStream,
96 init_sent: bool,
97}
98
99impl PaddedIntermediateTransport {
100 pub async fn connect(addr: &str) -> Result<Self, ConnectError> {
102 let stream = TcpStream::connect(addr).await?;
103 Ok(Self {
104 stream,
105 init_sent: false,
106 })
107 }
108
109 pub fn from_stream(stream: TcpStream) -> Self {
111 Self {
112 stream,
113 init_sent: false,
114 }
115 }
116
117 pub async fn send(&mut self, data: &[u8]) -> Result<(), ConnectError> {
122 if !self.init_sent {
123 self.stream.write_all(&[0xdd, 0xdd, 0xdd, 0xdd]).await?;
124 self.init_sent = true;
125 }
126 let mut pad_len_buf = [0u8; 1];
127 ferogram_crypto::fill_random(&mut pad_len_buf);
128 let pad_len = (pad_len_buf[0] & 0x0f) as usize;
129 let total_len = (data.len() + pad_len) as u32;
130 self.stream.write_all(&total_len.to_le_bytes()).await?;
131 self.stream.write_all(data).await?;
132 if pad_len > 0 {
133 let mut pad = vec![0u8; pad_len];
134 ferogram_crypto::fill_random(&mut pad);
135 self.stream.write_all(&pad).await?;
136 }
137 Ok(())
138 }
139
140 pub async fn recv(&mut self) -> Result<Vec<u8>, ConnectError> {
142 let mut len_buf = [0u8; 4];
143 self.stream.read_exact(&mut len_buf).await?;
144 let raw = i32::from_le_bytes(len_buf);
145 if raw < 0 {
146 return Err(ConnectError::Io(std::io::Error::new(
147 std::io::ErrorKind::ConnectionRefused,
148 format!("transport error: {raw}"),
149 )));
150 }
151 let total_len = raw as usize;
152 let mut buf = vec![0u8; total_len];
153 self.stream.read_exact(&mut buf).await?;
154 if buf.len() >= 24 {
157 let pad = (buf.len() - 24) % 16;
158 buf.truncate(buf.len() - pad);
159 }
160 Ok(buf)
161 }
162
163 pub fn into_inner(self) -> TcpStream {
165 self.stream
166 }
167}
168
169pub struct FullTransport {
183 stream: TcpStream,
184 send_seqno: u32,
185 recv_seqno: u32,
186}
187
188impl FullTransport {
189 pub async fn connect(addr: &str) -> Result<Self, ConnectError> {
193 let stream = TcpStream::connect(addr).await?;
194 Ok(Self {
195 stream,
196 send_seqno: 0,
197 recv_seqno: 0,
198 })
199 }
200
201 pub fn from_stream(stream: TcpStream) -> Self {
205 Self {
206 stream,
207 send_seqno: 0,
208 recv_seqno: 0,
209 }
210 }
211
212 pub async fn send(&mut self, data: &[u8]) -> Result<(), ConnectError> {
214 let total_len = (data.len() + 12) as u32; let seq = self.send_seqno;
216 self.send_seqno = self.send_seqno.wrapping_add(1);
217
218 let mut packet = Vec::with_capacity(total_len as usize);
219 packet.extend_from_slice(&total_len.to_le_bytes());
220 packet.extend_from_slice(&seq.to_le_bytes());
221 packet.extend_from_slice(data);
222
223 let crc = crate::crc32_ieee(&packet);
224 packet.extend_from_slice(&crc.to_le_bytes());
225
226 self.stream.write_all(&packet).await?;
227 Ok(())
228 }
229
230 pub async fn recv(&mut self) -> Result<Vec<u8>, ConnectError> {
232 let mut len_buf = [0u8; 4];
233 self.stream.read_exact(&mut len_buf).await?;
234 let raw = i32::from_le_bytes(len_buf);
236 if raw < 0 {
237 return Err(ConnectError::TransportCode(raw));
238 }
239 let total_len = raw as usize;
240 if total_len < 12 {
241 return Err(ConnectError::Other(
242 "Full transport: packet too short".into(),
243 ));
244 }
245 let mut rest = vec![0u8; total_len - 4];
246 self.stream.read_exact(&mut rest).await?;
247
248 let (body, crc_bytes) = rest.split_at(rest.len() - 4);
250 let expected_crc = u32::from_le_bytes(crc_bytes.try_into().unwrap());
251 let mut check_input = len_buf.to_vec();
252 check_input.extend_from_slice(body);
253 let actual_crc = crate::crc32_ieee(&check_input);
254 if actual_crc != expected_crc {
255 return Err(ConnectError::Other(format!(
256 "Full transport: CRC mismatch (got {actual_crc:#010x}, expected {expected_crc:#010x})"
257 )));
258 }
259
260 let recv_seq = u32::from_le_bytes(body[..4].try_into().unwrap());
262 if recv_seq != self.recv_seqno {
263 return Err(ConnectError::Other(format!(
264 "Full transport: seq_no mismatch (got {recv_seq}, expected {})",
265 self.recv_seqno
266 )));
267 }
268 self.recv_seqno = self.recv_seqno.wrapping_add(1);
269
270 Ok(body[4..].to_vec())
271 }
272
273 pub fn into_inner(self) -> TcpStream {
276 self.stream
277 }
278}