1use serde::{Deserialize, Serialize};
31
32use crate::constants::protocol_header_value;
33
34pub const FRAME_HELLO: u8 = 0x01;
40pub const FRAME_HELLO_OK: u8 = 0x02;
42pub const FRAME_LIST_REQ: u8 = 0x10;
44pub const FRAME_LIST_REPLY: u8 = 0x11;
46pub const FRAME_META_REQ: u8 = 0x12;
48pub const FRAME_META_REPLY: u8 = 0x13;
50pub const FRAME_START: u8 = 0x20;
52pub const FRAME_READY: u8 = 0x21;
54pub const FRAME_BLOCK: u8 = 0x30;
56pub const FRAME_NAK: u8 = 0x31;
58pub const FRAME_REQ: u8 = 0x32;
61pub const FRAME_WAVE_DONE: u8 = 0x33;
63pub const FRAME_COMPLETE: u8 = 0x34;
65pub const FRAME_ERROR: u8 = 0xFF;
67
68pub fn frame_type(frame: &[u8]) -> Option<u8> {
70 frame.first().copied()
71}
72
73pub fn frame_payload(frame: &[u8]) -> &[u8] {
75 frame.get(1..).unwrap_or(&[])
76}
77
78pub fn control_frame<T: Serialize>(kind: u8, payload: &T) -> Vec<u8> {
84 let json = serde_json::to_vec(payload).unwrap_or_default();
85 let mut out = Vec::with_capacity(1 + json.len());
86 out.push(kind);
87 out.extend_from_slice(&json);
88 out
89}
90
91pub fn parse_control<'a, T: Deserialize<'a>>(frame: &'a [u8], kind: u8) -> Option<T> {
93 if frame.first() != Some(&kind) {
94 return None;
95 }
96 serde_json::from_slice(frame.get(1..)?).ok()
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Hello {
102 pub protocol: String,
104 pub token: String,
106}
107
108impl Hello {
109 pub fn new(token: &str) -> Self {
111 Hello {
112 protocol: protocol_header_value().to_string(),
113 token: token.to_string(),
114 }
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "lowercase")]
121pub enum TransferKind {
122 Upload,
123 Download,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct StartRequest {
129 pub kind: TransferKind,
131 pub path: String,
133 #[serde(default)]
135 pub size: u64,
136 #[serde(default)]
138 pub mtime: u64,
139 #[serde(default)]
142 pub etag: String,
143 #[serde(default)]
145 pub compress: bool,
146 #[serde(default)]
148 pub mode: String,
149 #[serde(default)]
151 pub offset: u64,
152 #[serde(default)]
154 pub block_size: u64,
155 #[serde(default)]
161 pub window: u32,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct ReadyReply {
167 pub kind: TransferKind,
169 pub path: String,
171 #[serde(default)]
173 pub size: u64,
174 #[serde(default)]
176 pub mtime: u64,
177 #[serde(default)]
179 pub etag: String,
180 #[serde(default)]
182 pub compress: bool,
183 pub block_size: u64,
185 pub total_blocks: u32,
187 #[serde(default)]
189 pub offset: u64,
190 #[serde(default)]
193 pub received: Vec<[u64; 2]>,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct CompleteMessage {
199 pub ok: bool,
201 #[serde(default)]
203 pub size: u64,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub error: Option<String>,
207}
208
209impl CompleteMessage {
210 pub fn ok(size: u64) -> Self {
212 CompleteMessage {
213 ok: true,
214 size,
215 error: None,
216 }
217 }
218
219 pub fn err(message: impl Into<String>) -> Self {
221 CompleteMessage {
222 ok: false,
223 size: 0,
224 error: Some(message.into()),
225 }
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct ErrorMessage {
232 pub code: String,
234 pub message: String,
236}
237
238#[derive(Debug, Clone)]
244pub struct Block {
245 pub index: u32,
247 pub crc: u32,
249 pub raw_len: u32,
251 pub data: Vec<u8>,
253}
254
255pub fn block_frame(index: u32, crc: u32, raw_len: u32, data: &[u8]) -> Vec<u8> {
257 let mut out = Vec::with_capacity(1 + 12 + data.len());
258 out.push(FRAME_BLOCK);
259 out.extend_from_slice(&index.to_be_bytes());
260 out.extend_from_slice(&crc.to_be_bytes());
261 out.extend_from_slice(&raw_len.to_be_bytes());
262 out.extend_from_slice(data);
263 out
264}
265
266pub fn parse_block(frame: &[u8]) -> Option<Block> {
268 if frame.first() != Some(&FRAME_BLOCK) || frame.len() < 13 {
269 return None;
270 }
271 Some(Block {
272 index: u32::from_be_bytes(frame[1..5].try_into().ok()?),
273 crc: u32::from_be_bytes(frame[5..9].try_into().ok()?),
274 raw_len: u32::from_be_bytes(frame[9..13].try_into().ok()?),
275 data: frame[13..].to_vec(),
276 })
277}
278
279pub fn nak_frame(index: u32) -> Vec<u8> {
281 let mut out = vec![FRAME_NAK];
282 out.extend_from_slice(&index.to_be_bytes());
283 out
284}
285
286pub fn req_frame(indices: &[u32]) -> Vec<u8> {
288 let mut out = Vec::with_capacity(5 + indices.len() * 4);
289 out.push(FRAME_REQ);
290 out.extend_from_slice(&(indices.len() as u32).to_be_bytes());
291 for i in indices {
292 out.extend_from_slice(&i.to_be_bytes());
293 }
294 out
295}
296
297pub fn parse_req(frame: &[u8]) -> Option<Vec<u32>> {
299 if frame.first() != Some(&FRAME_REQ) || frame.len() < 5 {
300 return None;
301 }
302 let count = u32::from_be_bytes(frame[1..5].try_into().ok()?) as usize;
303 if count > (frame.len() - 5) / 4 {
309 return None;
310 }
311 let mut out = Vec::with_capacity(count);
312 let mut off = 5usize;
313 for _ in 0..count {
314 out.push(u32::from_be_bytes(frame[off..off + 4].try_into().ok()?));
315 off += 4;
316 }
317 Some(out)
318}
319
320pub fn parse_nak(frame: &[u8]) -> Option<u32> {
322 if frame.first() != Some(&FRAME_NAK) || frame.len() < 5 {
323 return None;
324 }
325 Some(u32::from_be_bytes(frame[1..5].try_into().ok()?))
326}
327
328pub fn wave_done_frame() -> Vec<u8> {
330 vec![FRAME_WAVE_DONE]
331}
332
333pub fn crc32(data: &[u8]) -> u32 {
339 crc32fast::hash(data)
340}
341
342pub fn block_count(size: u64, block_size: u64) -> u32 {
348 let bs = block_size.max(1);
349 if size == 0 {
350 1
351 } else {
352 size.div_ceil(bs).min(u32::MAX as u64) as u32
356 }
357}
358
359pub fn block_bounds(index: u32, block_size: u64, size: u64) -> (u64, u64) {
361 let bs = block_size.max(1);
362 let start = index as u64 * bs;
363 if start >= size {
367 return (size, size);
368 }
369 let end = start.saturating_add(bs).min(size);
370 (start, end)
371}
372
373pub fn block_offset(index: u32, block_size: u64, offset: u64) -> u64 {
376 offset.saturating_add(index as u64 * block_size)
377}
378
379#[derive(Debug, Clone, Default)]
389pub struct BlockSet {
390 bits: Vec<u64>,
391 total: u32,
392 count: u32,
393}
394
395impl BlockSet {
396 pub fn new(total: u32) -> Self {
398 BlockSet {
399 bits: vec![0; (total as usize).div_ceil(64)],
400 total,
401 count: 0,
402 }
403 }
404
405 pub fn insert(&mut self, index: u32) {
407 if index >= self.total {
408 return;
409 }
410 let word = (index / 64) as usize;
411 let bit = 1u64 << (index % 64);
412 if self.bits[word] & bit == 0 {
413 self.bits[word] |= bit;
414 self.count += 1;
415 }
416 }
417
418 pub fn contains(&self, index: u32) -> bool {
420 index < self.total && (self.bits[(index / 64) as usize] & (1u64 << (index % 64))) != 0
421 }
422
423 pub fn count(&self) -> u32 {
425 self.count
426 }
427
428 pub fn total(&self) -> u32 {
430 self.total
431 }
432
433 pub fn missing(&self) -> Vec<u32> {
435 let mut out = Vec::new();
436 for i in 0..self.total {
437 if !self.contains(i) {
438 out.push(i);
439 }
440 }
441 out
442 }
443
444 pub fn seed_from_ranges(&mut self, block_size: u64, ranges: &[(u64, u64)]) {
447 let bs = block_size.max(1);
448 for &(start, end) in ranges {
449 if end <= start {
450 continue;
451 }
452 let first = (start / bs) as u32;
453 let last = ((end - 1) / bs) as u32; for i in first..=last {
455 self.insert(i);
456 }
457 }
458 }
459}
460
461pub fn missing_blocks(size: u64, block_size: u64, received: &[(u64, u64)]) -> Vec<u32> {
465 let total = block_count(size, block_size);
466 let mut set = BlockSet::new(total);
467 set.seed_from_ranges(block_size, received);
468 set.missing()
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474
475 #[test]
476 fn block_count_and_bounds() {
477 assert_eq!(block_count(0, 4), 1);
478 assert_eq!(block_count(10, 4), 3);
479 assert_eq!(block_count(8, 4), 2);
480 assert_eq!(block_bounds(1, 4, 10), (4, 8));
481 assert_eq!(block_bounds(2, 4, 10), (8, 10));
482 assert_eq!(block_offset(2, 4, 100), 108);
483 }
484
485 #[test]
486 fn block_math_is_saturating_for_adversarial_inputs() {
487 assert_eq!(block_bounds(u32::MAX, 1, 10), (10, 10));
489 assert_eq!(block_bounds(5, 4, 10), (10, 10));
490 assert_eq!(block_count(u64::MAX, 1), u32::MAX);
493 assert_eq!(block_count(4u64 * 1024 * 1024 * 1024, 1), u32::MAX);
494 }
495
496 #[test]
497 fn crc_roundtrip_detects_corruption() {
498 let data = b"hello libfw block";
499 let crc = crc32(data);
500 let mut bad = data.to_vec();
501 bad[0] ^= 0xFF;
502 assert_ne!(crc, crc32(&bad));
503 assert_eq!(crc, crc32(data));
504 }
505
506 #[test]
507 fn block_frame_roundtrip() {
508 let data = vec![7u8; 100];
509 let frame = block_frame(42, 12345, 100, &data);
510 let parsed = parse_block(&frame).unwrap();
511 assert_eq!(parsed.index, 42);
512 assert_eq!(parsed.crc, 12345);
513 assert_eq!(parsed.raw_len, 100);
514 assert_eq!(parsed.data, data);
515 assert_eq!(frame_type(&frame), Some(FRAME_BLOCK));
516 }
517
518 #[test]
519 fn req_and_nak_roundtrip() {
520 let req = req_frame(&[0, 3, 7, 9]);
521 assert_eq!(parse_req(&req), Some(vec![0, 3, 7, 9]));
522 let nak = nak_frame(5);
523 assert_eq!(parse_nak(&nak), Some(5));
524 }
525
526 #[test]
527 fn parse_req_rejects_oversized_count_before_allocating() {
528 let mut frame = vec![FRAME_REQ];
532 frame.extend_from_slice(&10_000_000u32.to_be_bytes());
533 for i in 0..3u32 {
534 frame.extend_from_slice(&i.to_be_bytes());
535 }
536 assert_eq!(parse_req(&frame), None);
537
538 let mut good = vec![FRAME_REQ];
540 good.extend_from_slice(&2u32.to_be_bytes());
541 good.extend_from_slice(&7u32.to_be_bytes());
542 good.extend_from_slice(&9u32.to_be_bytes());
543 assert_eq!(parse_req(&good), Some(vec![7, 9]));
544
545 assert_eq!(parse_req(&[FRAME_REQ]), None);
547 assert_eq!(parse_req(&[FRAME_REQ, 0, 0, 0, 1]), None);
548 }
549
550 #[test]
551 fn block_set_tracks_verified_and_missing() {
552 let mut set = BlockSet::new(10);
553 assert_eq!(set.total(), 10);
554 set.insert(0);
555 set.insert(3);
556 set.insert(3); assert_eq!(set.count(), 2);
558 assert!(set.contains(0));
559 assert!(!set.contains(1));
560 assert_eq!(set.missing(), vec![1, 2, 4, 5, 6, 7, 8, 9]);
561 }
562
563 #[test]
564 fn seed_from_ranges_marks_overlapping_blocks() {
565 let mut set = BlockSet::new(3);
567 set.seed_from_ranges(4, &[(0, 4)]);
568 assert!(set.contains(0));
569 assert!(!set.contains(1));
570 let mut set = BlockSet::new(3);
571 set.seed_from_ranges(4, &[(4, 10)]);
572 assert!(set.contains(1));
573 assert!(set.contains(2));
574 assert!(!set.contains(0));
575 }
576
577 #[test]
578 fn missing_blocks_from_received_ranges() {
579 assert_eq!(missing_blocks(10, 4, &[(0, 4)]), vec![1, 2]);
581 assert_eq!(missing_blocks(10, 4, &[]), vec![0, 1, 2]);
583 assert_eq!(missing_blocks(10, 4, &[(0, 10)]), Vec::<u32>::new());
585 }
586
587 #[test]
588 fn control_frame_roundtrip() {
589 let hello = Hello::new("tok");
590 let frame = control_frame(FRAME_HELLO, &hello);
591 assert_eq!(frame_type(&frame), Some(FRAME_HELLO));
592 let parsed: Hello = parse_control(&frame, FRAME_HELLO).unwrap();
593 assert_eq!(parsed.token, "tok");
594 assert_eq!(parsed.protocol, protocol_header_value());
595 }
596}