over_there/core/transport/wire/output/
encoder.rs1use crate::core::transport::{
2 auth::Signer,
3 wire::packet::{Metadata, Packet, PacketEncryption, PacketType},
4};
5use derive_more::{Display, Error};
6use std::collections::HashMap;
7
8pub(crate) struct EncodeArgs<'d, 's, S: Signer> {
9 pub id: u32,
11
12 pub encryption: PacketEncryption,
14
15 pub max_packet_size: usize,
17
18 pub signer: &'s S,
20
21 pub data: &'d [u8],
24}
25
26#[derive(Debug, Display, Error)]
27pub enum EncoderError {
28 MaxPacketSizeTooSmall,
29 FailedToEstimateDataSize,
30 FailedToSignPacket,
31}
32
33#[derive(Debug, Clone)]
34pub(crate) struct Encoder {
35 max_data_size_cache: HashMap<String, usize>,
38
39 packet_size_cache: HashMap<String, usize>,
42}
43
44impl Encoder {
45 pub fn encode<S: Signer>(
46 &mut self,
47 info: EncodeArgs<S>,
48 ) -> Result<Vec<Packet>, EncoderError> {
49 let EncodeArgs {
50 id,
51 encryption,
52 max_packet_size,
53 signer,
54 data,
55 } = info;
56
57 let not_final_max_data_size = self
60 .find_optimal_max_data_size(
61 max_packet_size,
62 PacketType::NotFinal,
63 signer,
64 )
65 .map_err(|_| EncoderError::FailedToEstimateDataSize)?;
66 let final_max_data_size = self
67 .find_optimal_max_data_size(
68 max_packet_size,
69 PacketType::Final { encryption },
70 signer,
71 )
72 .map_err(|_| EncoderError::FailedToEstimateDataSize)?;
73
74 if not_final_max_data_size == 0 || final_max_data_size == 0 {
77 return Err(EncoderError::MaxPacketSizeTooSmall);
78 }
79
80 let mut packets = Vec::new();
84 let mut i = 0;
85 while i < data.len() {
86 let remaining_data_size = data.len() - i;
97 let can_fit_all_in_final_packet =
98 i + final_max_data_size >= data.len();
99 let can_fit_all_in_not_final_packet =
100 i + not_final_max_data_size >= data.len();
101 let data_size = if can_fit_all_in_final_packet {
102 final_max_data_size
103 } else if can_fit_all_in_not_final_packet {
104 remaining_data_size - 1
105 } else {
106 not_final_max_data_size
107 };
108
109 let data_size = std::cmp::min(data_size, remaining_data_size);
111
112 let chunk = &data[i..i + data_size];
114
115 let packet = Self::make_new_packet(
117 id,
118 packets.len() as u32,
119 if can_fit_all_in_final_packet {
120 PacketType::Final { encryption }
121 } else {
122 PacketType::NotFinal
123 },
124 chunk,
125 signer,
126 )
127 .map_err(|_| EncoderError::FailedToSignPacket)?;
128
129 packets.push(packet);
131
132 i += data_size;
134 }
135
136 Ok(packets)
137 }
138
139 fn make_new_packet<S: Signer>(
141 id: u32,
142 index: u32,
143 r#type: PacketType,
144 data: &[u8],
145 signer: &S,
146 ) -> Result<Packet, serde_cbor::Error> {
147 let metadata = Metadata { id, index, r#type };
148 metadata.to_vec().map(|md| {
149 let sig = signer.sign(&[md, data.to_vec()].concat());
150 Packet::new(metadata, sig, data.to_vec())
151 })
152 }
153
154 fn find_optimal_max_data_size<S: Signer>(
158 &mut self,
159 max_packet_size: usize,
160 r#type: PacketType,
161 signer: &S,
162 ) -> Result<usize, serde_cbor::Error> {
163 let key = format!("{}{:?}", max_packet_size, r#type);
165
166 if let Some(value) = self.max_data_size_cache.get(&key) {
168 return Ok(*value);
169 }
170
171 let mut best_data_size = 0;
173 let mut data_size = (max_packet_size / 2) + 1;
174 loop {
175 let packet_size =
176 self.estimate_packet_size(data_size, r#type, signer)?;
177
178 if packet_size == max_packet_size {
181 best_data_size = data_size;
182 break;
183 } else if packet_size > max_packet_size {
185 let overflow_size = packet_size - max_packet_size;
186
187 if overflow_size >= data_size {
190 data_size /= 2;
191
192 if data_size == 0 {
194 break;
195 }
196
197 } else {
199 data_size -= overflow_size;
200 }
201
202 } else if data_size > best_data_size {
206 best_data_size = data_size;
207 } else {
210 break;
211 }
212 }
213
214 self.max_data_size_cache.insert(key, best_data_size);
216 Ok(best_data_size)
217 }
218
219 pub(crate) fn estimate_packet_size<S: Signer>(
222 &mut self,
223 data_size: usize,
224 r#type: PacketType,
225 signer: &S,
226 ) -> Result<usize, serde_cbor::Error> {
227 let key = format!("{}{:?}", data_size, r#type);
229
230 if let Some(value) = self.packet_size_cache.get(&key) {
232 return Ok(*value);
233 }
234
235 let fake_data: Vec<u8> =
237 (0..data_size).map(|_| rand::random::<u8>()).collect();
238
239 let packet_size = Encoder::make_new_packet(
246 u32::max_value(),
247 u32::max_value(),
248 r#type,
249 &fake_data,
250 signer,
251 )?
252 .to_vec()?
253 .len();
254
255 self.packet_size_cache.insert(key, packet_size);
257 Ok(packet_size)
258 }
259}
260
261impl Default for Encoder {
262 fn default() -> Self {
263 Self {
264 max_data_size_cache: HashMap::new(),
265 packet_size_cache: HashMap::new(),
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use crate::core::transport::auth::NoopAuthenticator;
274 use crate::core::transport::crypto::{nonce, Nonce};
275
276 #[test]
277 fn fails_if_max_packet_size_is_too_low() {
278 let chunk_size = 1;
280 let err = Encoder::default()
281 .encode(EncodeArgs {
282 id: 0,
283 encryption: PacketEncryption::None,
284 data: &vec![1, 2, 3],
285 max_packet_size: chunk_size,
286 signer: &NoopAuthenticator,
287 })
288 .unwrap_err();
289
290 match err {
291 EncoderError::MaxPacketSizeTooSmall => (),
292 x => panic!("Unexpected error: {:?}", x),
293 }
294 }
295
296 #[test]
297 fn produces_single_packet_with_data() {
298 let id = 12345;
299 let data: Vec<u8> = vec![1, 2];
300 let encryption =
301 PacketEncryption::from(Nonce::from(nonce::new_128bit_nonce()));
302
303 let chunk_size = 1000;
305
306 let packets = Encoder::default()
307 .encode(EncodeArgs {
308 id,
309 encryption,
310 data: &data,
311 max_packet_size: chunk_size,
312 signer: &NoopAuthenticator,
313 })
314 .unwrap();
315 assert_eq!(packets.len(), 1, "More than one packet produced");
316
317 let p = &packets[0];
318 assert_eq!(p.id(), id, "ID not properly set on packet");
319 assert_eq!(p.index(), 0, "Unexpected index for single packet");
320 assert_eq!(
321 p.is_final(),
322 true,
323 "Single packet not marked as last packet"
324 );
325 assert_eq!(p.data(), &data);
326 }
327
328 #[test]
329 fn produces_multiple_packets_with_data() {
330 let id = 67890;
331 let data: Vec<u8> = vec![1, 2, 3];
332 let nonce = Nonce::from(nonce::new_128bit_nonce());
333 let mut encoder = Encoder::default();
334
335 let max_packet_size = encoder
339 .estimate_packet_size(
340 1,
341 PacketType::Final {
342 encryption: PacketEncryption::from(nonce),
343 },
344 &NoopAuthenticator,
345 )
346 .unwrap();
347
348 let packets = encoder
349 .encode(EncodeArgs {
350 id,
351 encryption: PacketEncryption::from(nonce),
352 data: &data,
353 max_packet_size,
354 signer: &NoopAuthenticator,
355 })
356 .unwrap();
357 assert_eq!(packets.len(), 2, "Unexpected number of packets");
358
359 let p1 = packets.get(0).unwrap();
361 assert_eq!(p1.id(), id, "ID not properly set on first packet");
362 assert_eq!(p1.index(), 0, "First packet not marked with index 0");
363 assert_eq!(
364 p1.is_final(),
365 false,
366 "Non-final packet unexpectedly marked as last"
367 );
368 assert_eq!(&p1.data()[..], &data[0..2]);
369
370 let p2 = packets.get(1).unwrap();
372 assert_eq!(p2.id(), id, "ID not properly set on second packet");
373 assert_eq!(p2.index(), 1, "Last packet not marked with correct index");
374 assert_eq!(p2.is_final(), true, "Last packet not marked as final");
375 assert_eq!(&p2.data()[..], &data[2..]);
376 }
377
378 #[test]
379 fn produces_multiple_packets_respecting_size_constraints() {
380 let id = 67890;
381 let encryption =
382 PacketEncryption::from(Nonce::from(nonce::new_128bit_nonce()));
383
384 let data: Vec<u8> = [0; 100000].to_vec();
391 let chunk_size = 512;
392
393 let packets = Encoder::default()
394 .encode(EncodeArgs {
395 id,
396 encryption,
397 data: &data,
398 max_packet_size: chunk_size,
399 signer: &NoopAuthenticator,
400 })
401 .unwrap();
402
403 for (i, p) in packets.iter().enumerate() {
405 let actual_size = p.to_vec().unwrap().len();
406 assert!(
407 actual_size <= chunk_size,
408 "Serialized packet {}/{} was {} bytes instead of max size of {}",
409 i + 1,
410 packets.len(),
411 actual_size,
412 chunk_size
413 );
414 }
415 }
416}