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