1use std::time::Duration;
16
17use crate::error::ConnectError;
18
19pub fn crc32_ieee(data: &[u8]) -> u32 {
21 const POLY: u32 = 0xedb88320;
22 let mut crc: u32 = 0xffffffff;
23 for &byte in data {
24 let mut b = byte as u32;
25 for _ in 0..8 {
26 let mix = (crc ^ b) & 1;
27 crc >>= 1;
28 if mix != 0 {
29 crc ^= POLY;
30 }
31 b >>= 1;
32 }
33 }
34 crc ^ 0xffffffff
35}
36
37pub const COMPRESSION_THRESHOLD: usize = 512;
39
40const ID_GZIP_PACKED: u32 = 0x3072cfa1;
41const ID_MSGS_ACK: u32 = 0x62d6b459;
42const ID_MSG_CONTAINER: u32 = 0x73f1f8dc;
43
44pub fn random_i64() -> i64 {
47 let mut b = [0u8; 8];
48 ferogram_crypto::fill_random(&mut b);
49 i64::from_le_bytes(b)
50}
51
52pub fn jitter_delay(base_ms: u64) -> Duration {
56 let mut b = [0u8; 2];
58 ferogram_crypto::fill_random(&mut b);
59 let rand_frac = u16::from_le_bytes(b) as f64 / 65535.0; let factor = 0.80 + rand_frac * 0.40; Duration::from_millis((base_ms as f64 * factor) as u64)
62}
63
64pub fn tl_read_bytes(data: &[u8]) -> Option<Vec<u8>> {
69 if data.is_empty() {
70 return Some(vec![]);
71 }
72 let (len, start) = if data[0] < 254 {
73 (data[0] as usize, 1)
74 } else if data.len() >= 4 {
75 (
76 data[1] as usize | (data[2] as usize) << 8 | (data[3] as usize) << 16,
77 4,
78 )
79 } else {
80 return None;
81 };
82 if data.len() < start + len {
83 return None;
84 }
85 Some(data[start..start + len].to_vec())
86}
87
88pub fn tl_read_string(data: &[u8]) -> Option<String> {
91 tl_read_bytes(data).map(|b| String::from_utf8_lossy(&b).into_owned())
92}
93
94pub fn gz_inflate(data: &[u8]) -> Result<Vec<u8>, ConnectError> {
98 use std::io::Read;
99 let mut out = Vec::new();
100 if flate2::read::GzDecoder::new(data)
101 .read_to_end(&mut out)
102 .is_ok()
103 && !out.is_empty()
104 {
105 return Ok(out);
106 }
107 out.clear();
108 flate2::read::ZlibDecoder::new(data)
109 .read_to_end(&mut out)
110 .map_err(|_| ConnectError::other("decompression failed"))?;
111 Ok(out)
112}
113
114pub fn maybe_gz_decompress(body: Vec<u8>) -> Result<Vec<u8>, ConnectError> {
117 const ID_GZIP_PACKED_LOCAL: u32 = 0x3072cfa1;
118 if body.len() >= 4 && u32::from_le_bytes(body[0..4].try_into().unwrap()) == ID_GZIP_PACKED_LOCAL
119 {
120 let bytes = tl_read_bytes(&body[4..]).unwrap_or_default();
121 gz_inflate(&bytes)
122 } else {
123 Ok(body)
124 }
125}
126
127pub fn tl_write_bytes(data: &[u8]) -> Vec<u8> {
129 let len = data.len();
130 let mut out = Vec::with_capacity(4 + len);
131 if len < 254 {
132 out.push(len as u8);
133 out.extend_from_slice(data);
134 let pad = (4 - (1 + len) % 4) % 4;
135 out.extend(std::iter::repeat_n(0u8, pad));
136 } else {
137 out.push(0xfe);
138 out.extend_from_slice(&(len as u32).to_le_bytes()[..3]);
139 out.extend_from_slice(data);
140 let pad = (4 - (4 + len) % 4) % 4;
141 out.extend(std::iter::repeat_n(0u8, pad));
142 }
143 out
144}
145
146pub fn gz_pack_body(data: &[u8]) -> Vec<u8> {
148 use std::io::Write;
149 let mut enc = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
150 let _ = enc.write_all(data);
151 let compressed = enc.finish().unwrap_or_default();
152 let mut out = Vec::with_capacity(4 + 4 + compressed.len());
153 out.extend_from_slice(&ID_GZIP_PACKED.to_le_bytes());
154 out.extend(tl_write_bytes(&compressed));
155 out
156}
157
158pub fn maybe_gz_pack(data: &[u8]) -> Vec<u8> {
161 if data.len() <= COMPRESSION_THRESHOLD {
162 return data.to_vec();
163 }
164 let packed = gz_pack_body(data);
165 if packed.len() < data.len() {
166 packed
167 } else {
168 data.to_vec()
169 }
170}
171
172pub fn build_msgs_ack_body(msg_ids: &[i64]) -> Vec<u8> {
176 let mut out = Vec::with_capacity(4 + 4 + 4 + msg_ids.len() * 8);
179 out.extend_from_slice(&ID_MSGS_ACK.to_le_bytes());
180 out.extend_from_slice(&0x1cb5c415_u32.to_le_bytes()); out.extend_from_slice(&(msg_ids.len() as u32).to_le_bytes());
182 for &id in msg_ids {
183 out.extend_from_slice(&id.to_le_bytes());
184 }
185 out
186}
187
188pub fn build_container_body(messages: &[(i64, i32, &[u8])]) -> Vec<u8> {
194 let total_body: usize = messages.iter().map(|(_, _, b)| 16 + b.len()).sum();
195 let mut out = Vec::with_capacity(8 + total_body);
196 out.extend_from_slice(&ID_MSG_CONTAINER.to_le_bytes());
197 out.extend_from_slice(&(messages.len() as u32).to_le_bytes());
198 for &(msg_id, seqno, body) in messages {
199 out.extend_from_slice(&msg_id.to_le_bytes());
200 out.extend_from_slice(&seqno.to_le_bytes());
201 out.extend_from_slice(&(body.len() as u32).to_le_bytes());
202 out.extend_from_slice(body);
203 }
204 out
205}