1use crate::coding::{put_varint, varint_len, Reader, VARINT_MAX};
4use crate::error::{TransportError, FRAME_ENCODING_ERROR, PROTOCOL_VIOLATION};
5use crate::ranges::RangeSet;
6
7pub const PADDING: u64 = 0x00;
8pub const PING: u64 = 0x01;
9pub const ACK: u64 = 0x02;
10pub const ACK_ECN: u64 = 0x03;
11pub const RESET_STREAM: u64 = 0x04;
12pub const STOP_SENDING: u64 = 0x05;
13pub const CRYPTO: u64 = 0x06;
14pub const NEW_TOKEN: u64 = 0x07;
15pub const STREAM: u64 = 0x08;
16pub const MAX_DATA: u64 = 0x10;
17pub const MAX_STREAM_DATA: u64 = 0x11;
18pub const MAX_STREAMS_BIDI: u64 = 0x12;
19pub const MAX_STREAMS_UNI: u64 = 0x13;
20pub const DATA_BLOCKED: u64 = 0x14;
21pub const STREAM_DATA_BLOCKED: u64 = 0x15;
22pub const STREAMS_BLOCKED_BIDI: u64 = 0x16;
23pub const STREAMS_BLOCKED_UNI: u64 = 0x17;
24pub const NEW_CONNECTION_ID: u64 = 0x18;
25pub const RETIRE_CONNECTION_ID: u64 = 0x19;
26pub const PATH_CHALLENGE: u64 = 0x1a;
27pub const PATH_RESPONSE: u64 = 0x1b;
28pub const CONNECTION_CLOSE: u64 = 0x1c;
29pub const CONNECTION_CLOSE_APP: u64 = 0x1d;
30pub const HANDSHAKE_DONE: u64 = 0x1e;
31
32pub const MAX_STREAMS_LIMIT: u64 = 1 << 60;
34
35#[derive(Clone, Copy, Debug)]
37pub struct AckRanges<'a> {
38 pub largest: u64,
39 pub first: u64,
40 count: u64,
41 raw: &'a [u8],
42}
43
44impl<'a> AckRanges<'a> {
45 pub fn iter(&self) -> impl Iterator<Item = (u64, u64)> + 'a {
47 let mut r = Reader::new(self.raw);
48 let mut hi = self.largest;
49 let mut lo = self.largest - self.first;
50 let mut left = self.count;
51 let mut first = true;
52 std::iter::from_fn(move || {
53 if first {
54 first = false;
55 return Some((lo, hi));
56 }
57 if left == 0 {
58 return None;
59 }
60 left -= 1;
61 let gap = r.varint()?;
62 let len = r.varint()?;
63 hi = lo - gap - 2;
64 lo = hi - len;
65 Some((lo, hi))
66 })
67 }
68 pub fn smallest(&self) -> u64 {
69 self.iter().last().map(|x| x.0).unwrap_or(0)
70 }
71}
72
73#[derive(Clone, Copy, Debug)]
74pub enum Frame<'a> {
75 Padding,
76 Ping,
77 Ack { ranges: AckRanges<'a>, delay: u64, ecn: Option<[u64; 3]> },
78 ResetStream { id: u64, code: u64, final_size: u64 },
79 StopSending { id: u64, code: u64 },
80 Crypto { offset: u64, data: &'a [u8] },
81 NewToken { token: &'a [u8] },
82 Stream { id: u64, offset: u64, data: &'a [u8], fin: bool },
83 MaxData(u64),
84 MaxStreamData { id: u64, max: u64 },
85 MaxStreams { bidi: bool, max: u64 },
86 DataBlocked(u64),
87 StreamDataBlocked { id: u64, limit: u64 },
88 StreamsBlocked { bidi: bool, limit: u64 },
89 NewConnectionId { seq: u64, retire_prior_to: u64, cid: &'a [u8], reset_token: [u8; 16] },
90 RetireConnectionId { seq: u64 },
91 PathChallenge([u8; 8]),
92 PathResponse([u8; 8]),
93 ConnectionClose { code: u64, frame_type: Option<u64>, reason: &'a [u8] },
94 HandshakeDone,
95}
96
97impl Frame<'_> {
98 pub fn is_ack_eliciting(&self) -> bool {
100 !matches!(self, Frame::Padding | Frame::Ack { .. } | Frame::ConnectionClose { .. })
101 }
102 pub fn is_probing(&self) -> bool {
104 matches!(self, Frame::Padding | Frame::PathChallenge(_) | Frame::PathResponse(_) | Frame::NewConnectionId { .. })
105 }
106}
107
108fn enc(ty: u64) -> TransportError {
109 TransportError::frame(FRAME_ENCODING_ERROR, ty, "malformed frame")
110}
111
112pub fn parse<'a>(r: &mut Reader<'a>) -> Result<(u64, Frame<'a>), TransportError> {
114 let (ty, tlen) = r.varint_with_len().ok_or(enc(0))?;
115 if tlen != varint_len(ty) {
116 return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "non-minimal frame type"));
117 }
118 let e = || enc(ty);
119 let v = |r: &mut Reader<'a>| r.varint().ok_or_else(e);
120 let f = match ty {
121 PADDING => {
122 let rest = r.rest();
124 let n = rest.iter().position(|&b| b != 0).unwrap_or(rest.len());
125 r.bytes(n);
126 Frame::Padding
127 }
128 PING => Frame::Ping,
129 ACK | ACK_ECN => {
130 let largest = v(r)?;
131 let delay = v(r)?;
132 let count = v(r)?;
133 let first = v(r)?;
134 if first > largest {
135 return Err(e());
136 }
137 let start = r.position();
138 let raw_all = r.rest();
139 let mut lo = largest - first;
140 for _ in 0..count {
141 let gap = v(r)?;
142 let len = v(r)?;
143 if lo < gap + 2 || lo - gap - 2 < len {
145 return Err(e());
146 }
147 lo = lo - gap - 2 - len;
148 }
149 let raw = &raw_all[..r.position() - start];
150 let ecn = if ty == ACK_ECN { Some([v(r)?, v(r)?, v(r)?]) } else { None };
151 Frame::Ack { ranges: AckRanges { largest, first, count, raw }, delay, ecn }
152 }
153 RESET_STREAM => Frame::ResetStream { id: v(r)?, code: v(r)?, final_size: v(r)? },
154 STOP_SENDING => Frame::StopSending { id: v(r)?, code: v(r)? },
155 CRYPTO => {
156 let offset = v(r)?;
157 let data = r.vbytes().ok_or_else(e)?;
158 if offset + data.len() as u64 > VARINT_MAX {
159 return Err(TransportError::frame(FRAME_ENCODING_ERROR, ty, "crypto offset overflow"));
160 }
161 Frame::Crypto { offset, data }
162 }
163 NEW_TOKEN => {
164 let token = r.vbytes().ok_or_else(e)?;
165 if token.is_empty() {
166 return Err(e());
167 }
168 Frame::NewToken { token }
169 }
170 0x08..=0x0f => {
171 let id = v(r)?;
172 let offset = if ty & 0x04 != 0 { v(r)? } else { 0 };
173 let data = if ty & 0x02 != 0 {
174 r.vbytes().ok_or_else(e)?
175 } else {
176 let d = r.rest();
177 r.bytes(d.len());
178 d
179 };
180 if offset + data.len() as u64 > VARINT_MAX {
181 return Err(TransportError::frame(FRAME_ENCODING_ERROR, ty, "stream offset overflow"));
182 }
183 Frame::Stream { id, offset, data, fin: ty & 0x01 != 0 }
184 }
185 MAX_DATA => Frame::MaxData(v(r)?),
186 MAX_STREAM_DATA => Frame::MaxStreamData { id: v(r)?, max: v(r)? },
187 MAX_STREAMS_BIDI | MAX_STREAMS_UNI => {
188 let max = v(r)?;
189 if max > MAX_STREAMS_LIMIT {
190 return Err(e());
191 }
192 Frame::MaxStreams { bidi: ty == MAX_STREAMS_BIDI, max }
193 }
194 DATA_BLOCKED => Frame::DataBlocked(v(r)?),
195 STREAM_DATA_BLOCKED => Frame::StreamDataBlocked { id: v(r)?, limit: v(r)? },
196 STREAMS_BLOCKED_BIDI | STREAMS_BLOCKED_UNI => {
197 let limit = v(r)?;
198 if limit > MAX_STREAMS_LIMIT {
199 return Err(e());
200 }
201 Frame::StreamsBlocked { bidi: ty == STREAMS_BLOCKED_BIDI, limit }
202 }
203 NEW_CONNECTION_ID => {
204 let seq = v(r)?;
205 let retire_prior_to = v(r)?;
206 let len = r.u8().ok_or_else(e)? as usize;
207 if len == 0 || len > 20 || retire_prior_to > seq {
208 return Err(e());
209 }
210 let cid = r.bytes(len).ok_or_else(e)?;
211 let reset_token = r.bytes(16).ok_or_else(e)?.try_into().unwrap();
212 Frame::NewConnectionId { seq, retire_prior_to, cid, reset_token }
213 }
214 RETIRE_CONNECTION_ID => Frame::RetireConnectionId { seq: v(r)? },
215 PATH_CHALLENGE => Frame::PathChallenge(r.bytes(8).ok_or_else(e)?.try_into().unwrap()),
216 PATH_RESPONSE => Frame::PathResponse(r.bytes(8).ok_or_else(e)?.try_into().unwrap()),
217 CONNECTION_CLOSE | CONNECTION_CLOSE_APP => {
218 let code = v(r)?;
219 let frame_type = if ty == CONNECTION_CLOSE { Some(v(r)?) } else { None };
220 let reason = r.vbytes().ok_or_else(e)?;
221 Frame::ConnectionClose { code, frame_type, reason }
222 }
223 HANDSHAKE_DONE => Frame::HandshakeDone,
224 _ => return Err(TransportError::frame(FRAME_ENCODING_ERROR, ty, "unknown frame type")),
225 };
226 Ok((ty, f))
227}
228
229pub fn put_ack(out: &mut Vec<u8>, ranges: &RangeSet, delay: u64, max_ranges: usize) -> bool {
234 let mut it = ranges.iter().rev().take(max_ranges.max(1));
235 let Some((s, e)) = it.next() else { return false };
236 let n = ranges.len().min(max_ranges.max(1)) - 1;
237 put_varint(out, ACK);
238 put_varint(out, e - 1);
239 put_varint(out, delay);
240 put_varint(out, n as u64);
241 put_varint(out, e - 1 - s);
242 let mut lo = s;
243 for (s2, e2) in it {
244 put_varint(out, lo - e2 - 1);
246 put_varint(out, e2 - 1 - s2);
247 lo = s2;
248 }
249 true
250}
251
252pub fn put_crypto(out: &mut Vec<u8>, offset: u64, data: &[u8]) {
253 put_varint(out, CRYPTO);
254 put_varint(out, offset);
255 put_varint(out, data.len() as u64);
256 out.extend_from_slice(data);
257}
258
259pub fn crypto_overhead(offset: u64, len: usize) -> usize {
261 1 + varint_len(offset) + varint_len(len as u64)
262}
263
264pub fn put_stream_header(out: &mut Vec<u8>, id: u64, offset: u64, len: usize, fin: bool) {
266 let mut ty = STREAM | 0x02;
267 if offset != 0 {
268 ty |= 0x04;
269 }
270 if fin {
271 ty |= 0x01;
272 }
273 out.push(ty as u8);
274 put_varint(out, id);
275 if offset != 0 {
276 put_varint(out, offset);
277 }
278 put_varint(out, len as u64);
279}
280
281pub fn stream_overhead(id: u64, offset: u64, len: usize) -> usize {
282 1 + varint_len(id) + if offset != 0 { varint_len(offset) } else { 0 } + varint_len(len as u64)
283}
284
285pub fn put_simple(out: &mut Vec<u8>, ty: u64, vals: &[u64]) {
286 put_varint(out, ty);
287 for &v in vals {
288 put_varint(out, v);
289 }
290}
291
292pub fn put_new_connection_id(out: &mut Vec<u8>, seq: u64, retire_prior_to: u64, cid: &[u8], token: &[u8; 16]) {
293 put_varint(out, NEW_CONNECTION_ID);
294 put_varint(out, seq);
295 put_varint(out, retire_prior_to);
296 out.push(cid.len() as u8);
297 out.extend_from_slice(cid);
298 out.extend_from_slice(token);
299}
300
301pub fn put_path(out: &mut Vec<u8>, response: bool, data: &[u8; 8]) {
302 out.push(if response { PATH_RESPONSE } else { PATH_CHALLENGE } as u8);
303 out.extend_from_slice(data);
304}
305
306pub fn put_new_token(out: &mut Vec<u8>, token: &[u8]) {
307 put_varint(out, NEW_TOKEN);
308 put_varint(out, token.len() as u64);
309 out.extend_from_slice(token);
310}
311
312pub fn put_close(out: &mut Vec<u8>, code: u64, frame_type: Option<u64>, reason: &[u8]) {
314 match frame_type {
315 Some(t) => {
316 put_varint(out, CONNECTION_CLOSE);
317 put_varint(out, code);
318 put_varint(out, t);
319 }
320 None => {
321 put_varint(out, CONNECTION_CLOSE_APP);
322 put_varint(out, code);
323 }
324 }
325 put_varint(out, reason.len() as u64);
326 out.extend_from_slice(reason);
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 fn one(b: &[u8]) -> Result<Frame<'_>, TransportError> {
334 let mut r = Reader::new(b);
335 let (_, f) = parse(&mut r)?;
336 assert!(r.is_empty(), "trailing bytes");
337 Ok(f)
338 }
339
340 #[test]
341 fn ack_roundtrip() {
342 let mut s = RangeSet::new();
343 s.insert(0, 3);
344 s.insert(5, 6);
345 s.insert(10, 20);
346 let mut out = Vec::new();
347 assert!(put_ack(&mut out, &s, 7, 32));
348 match one(&out).unwrap() {
349 Frame::Ack { ranges, delay, ecn } => {
350 assert_eq!(delay, 7);
351 assert!(ecn.is_none());
352 assert_eq!(ranges.iter().collect::<Vec<_>>(), vec![(10, 19), (5, 5), (0, 2)]);
353 assert_eq!(ranges.smallest(), 0);
354 }
355 _ => panic!(),
356 }
357 assert_eq!(one(&[0x02, 5, 0, 1, 2, 5, 0]).unwrap_err().code, FRAME_ENCODING_ERROR);
359 assert!(one(&[0x02, 1, 0, 0, 2]).is_err());
360 }
361
362 #[test]
363 fn all_frames_roundtrip() {
364 let mut out = Vec::new();
365 put_simple(&mut out, PING, &[]);
366 put_simple(&mut out, RESET_STREAM, &[4, 9, 100]);
367 put_simple(&mut out, STOP_SENDING, &[4, 9]);
368 put_crypto(&mut out, 7, b"abc");
369 put_new_token(&mut out, b"tok");
370 put_stream_header(&mut out, 8, 0, 2, false);
371 out.extend_from_slice(b"hi");
372 put_stream_header(&mut out, 8, 2, 1, true);
373 out.push(b'!');
374 put_simple(&mut out, MAX_DATA, &[1000]);
375 put_simple(&mut out, MAX_STREAM_DATA, &[4, 1000]);
376 put_simple(&mut out, MAX_STREAMS_BIDI, &[10]);
377 put_simple(&mut out, MAX_STREAMS_UNI, &[3]);
378 put_simple(&mut out, DATA_BLOCKED, &[5]);
379 put_simple(&mut out, STREAM_DATA_BLOCKED, &[4, 5]);
380 put_simple(&mut out, STREAMS_BLOCKED_BIDI, &[2]);
381 put_simple(&mut out, STREAMS_BLOCKED_UNI, &[2]);
382 put_new_connection_id(&mut out, 1, 0, &[1, 2, 3, 4], &[7; 16]);
383 put_simple(&mut out, RETIRE_CONNECTION_ID, &[1]);
384 put_path(&mut out, false, &[1; 8]);
385 put_path(&mut out, true, &[2; 8]);
386 put_close(&mut out, 0xa, Some(0x08), b"bad");
387 put_close(&mut out, 0x100, None, b"");
388 put_simple(&mut out, HANDSHAKE_DONE, &[]);
389 out.extend_from_slice(&[0, 0, 0]);
390 let mut r = Reader::new(&out);
391 let mut n = 0;
392 while !r.is_empty() {
393 parse(&mut r).unwrap();
394 n += 1;
395 }
396 assert_eq!(n, 23);
397 assert!(matches!(one(&[0x0b, 4, 2, b'x', b'y']).unwrap(), Frame::Stream { id: 4, offset: 0, fin: true, .. }));
399 assert!(matches!(one(&[0x0c, 4, 9]).unwrap(), Frame::Stream { id: 4, offset: 9, fin: false, data: &[] }));
400 assert!(one(&[0x18, 1, 2, 4, 1, 2, 3, 4]).is_err()); assert!(one(&[0x18, 1, 0, 21]).is_err()); assert!(one(&[0x07, 0]).is_err()); assert!(one(&[0x12, 0xd0, 0, 0, 0, 0, 0, 0, 1]).is_err()); assert!(one(&[0x1f]).is_err()); assert_eq!(one(&[0x40, 0x01]).unwrap_err().code, PROTOCOL_VIOLATION); assert!(one(&[0x06, 0, 5, 1]).is_err()); assert!(one(&[0x0e, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0]).is_err()); }
410}