Skip to main content

simoom_quic/
stream.rs

1//! Streams (RFC 9000 §2–4): send and receive buffers, stream and connection flow control,
2//! stream limits, STOP_SENDING and RESET_STREAM.
3
4use crate::coding::varint_len;
5use crate::error::*;
6use crate::frame::{self, MAX_STREAMS_LIMIT};
7use crate::ranges::RangeSet;
8use std::collections::{BTreeMap, HashMap, VecDeque};
9use std::hash::{BuildHasherDefault, Hasher};
10
11/// A fast hasher for integer keys (stream IDs). Not DoS-relevant: stream IDs are bounded by
12/// the stream limits we grant.
13#[derive(Default)]
14pub struct IdHasher(u64);
15
16impl Hasher for IdHasher {
17    fn finish(&self) -> u64 {
18        self.0
19    }
20    fn write(&mut self, bytes: &[u8]) {
21        for &b in bytes {
22            self.0 = (self.0.rotate_left(5) ^ b as u64).wrapping_mul(0x51_7cc1_b727_220a_95);
23        }
24    }
25    fn write_u64(&mut self, n: u64) {
26        self.0 = (n ^ (n >> 32)).wrapping_mul(0x9e37_79b9_7f4a_7c15);
27    }
28}
29
30pub type IdMap<V> = HashMap<u64, V, BuildHasherDefault<IdHasher>>;
31
32#[inline]
33pub fn is_bidi(id: u64) -> bool {
34    id & 2 == 0
35}
36#[inline]
37pub fn is_server_initiated(id: u64) -> bool {
38    id & 1 == 1
39}
40
41/// Stream limits and windows configured locally.
42#[derive(Clone, Debug)]
43pub struct StreamConfig {
44    pub max_streams_bidi: u64,
45    pub max_streams_uni: u64,
46    pub stream_window_bidi_local: u64,
47    pub stream_window_bidi_remote: u64,
48    pub stream_window_uni: u64,
49    pub conn_window: u64,
50    /// Unacknowledged bytes buffered per send stream.
51    pub send_buffer: u64,
52}
53
54/// A frame that must be (re)sent for stream bookkeeping.
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum Control {
57    MaxData,
58    MaxStreamData(u64),
59    MaxStreams(bool),
60    DataBlocked,
61    StreamDataBlocked(u64),
62    StreamsBlocked(bool),
63    ResetStream(u64),
64    StopSending(u64),
65}
66
67#[derive(Default)]
68pub struct SendStream {
69    buf: VecDeque<u8>,
70    /// Stream offset of `buf[0]`.
71    base: u64,
72    /// Next offset never sent.
73    sent: u64,
74    retransmit: RangeSet,
75    acked: RangeSet,
76    /// Peer's MAX_STREAM_DATA.
77    max_data: u64,
78    fin: bool,
79    fin_sent: bool,
80    fin_acked: bool,
81    reset: Option<(u64, u64)>,
82    reset_acked: bool,
83    stopped: Option<u64>,
84    blocked_at: Option<u64>,
85    want_writable: bool,
86    queued: bool,
87}
88
89impl SendStream {
90    fn end(&self) -> u64 {
91        self.base + self.buf.len() as u64
92    }
93    fn has_pending(&self) -> bool {
94        self.reset.is_none()
95            && (!self.retransmit.is_empty() || self.sent < self.end() || (self.fin && !self.fin_sent))
96    }
97    fn is_done(&self) -> bool {
98        if self.reset.is_some() {
99            return self.reset_acked;
100        }
101        self.fin_acked && self.buf.is_empty()
102    }
103}
104
105#[derive(Default)]
106pub struct RecvStream {
107    data: VecDeque<u8>,
108    /// Offset of `data[0]`: everything below was read by the application.
109    read: u64,
110    ooo: BTreeMap<u64, Vec<u8>>,
111    max_data: u64,
112    window: u64,
113    highest: u64,
114    final_size: Option<u64>,
115    reset: Option<u64>,
116    reset_delivered: bool,
117    stop: Option<u64>,
118    fin_delivered: bool,
119    notified: bool,
120}
121
122impl RecvStream {
123    fn contiguous_end(&self) -> u64 {
124        self.read + self.data.len() as u64
125    }
126    fn is_done(&self) -> bool {
127        self.fin_delivered || self.reset_delivered || (self.stop.is_some() && self.final_size.is_some())
128    }
129    /// Inserts `[off, off+len)` keeping `ooo` non-overlapping.
130    fn insert(&mut self, mut off: u64, mut d: &[u8]) {
131        let cend = self.contiguous_end();
132        if off < cend {
133            let skip = (cend - off).min(d.len() as u64) as usize;
134            d = &d[skip..];
135            off += skip as u64;
136        }
137        if d.is_empty() {
138            return;
139        }
140        if off == cend {
141            self.data.extend(d);
142            // Pull in out-of-order chunks that became contiguous.
143            while let Some((&o, _)) = self.ooo.first_key_value() {
144                let end = self.contiguous_end();
145                if o > end {
146                    break;
147                }
148                let chunk = self.ooo.pop_first().unwrap().1;
149                let skip = (end - o) as usize;
150                if skip < chunk.len() {
151                    self.data.extend(&chunk[skip..]);
152                }
153            }
154            return;
155        }
156        // Out of order: insert only the gaps not already buffered.
157        let end = off + d.len() as u64;
158        let mut cur = off;
159        let mut pieces: Vec<(u64, u64)> = Vec::new();
160        let start_key = self.ooo.range(..off).next_back().map(|(&k, v)| (k, k + v.len() as u64));
161        if let Some((_, e)) = start_key {
162            if e > cur {
163                cur = e;
164            }
165        }
166        for (&k, v) in self.ooo.range(off..end) {
167            if k > cur {
168                pieces.push((cur, k));
169            }
170            cur = cur.max(k + v.len() as u64);
171        }
172        if cur < end {
173            pieces.push((cur, end));
174        }
175        for (s, e) in pieces {
176            let piece = &d[(s - off) as usize..(e - off) as usize];
177            // Coalesce with the chunk ending at `s` and the one starting at `e`, so the map
178            // holds one entry per gap rather than one per frame.
179            let mut key = s;
180            let mut buf = match self.ooo.range(..s).next_back() {
181                Some((&k, v)) if k + v.len() as u64 == s => {
182                    key = k;
183                    let mut v = self.ooo.remove(&k).unwrap();
184                    v.extend_from_slice(piece);
185                    v
186                }
187                _ => piece.to_vec(),
188            };
189            if let Some(next) = self.ooo.remove(&e) {
190                buf.extend_from_slice(&next);
191            }
192            self.ooo.insert(key, buf);
193        }
194    }
195
196    /// Out-of-order chunks (gaps) currently buffered.
197    fn gaps(&self) -> usize {
198        self.ooo.len()
199    }
200}
201
202/// Out-of-order chunks a connection may buffer, over all its streams. Adjacent chunks are
203/// merged, so this bounds the number of holes, not the data: honest loss leaves a few holes per
204/// stream, while a peer that sends one byte at every other offset would otherwise cost a heap
205/// allocation and a tree node per byte of flow-control window. It is counted per connection, so
206/// opening many streams does not multiply it.
207pub const MAX_RECV_GAPS: usize = 1024;
208
209pub struct Stream {
210    pub send: Option<SendStream>,
211    pub recv: Option<RecvStream>,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub enum StreamEvent {
216    Opened(u64),
217    Readable(u64),
218    Writable(u64),
219    Stopped(u64, u64),
220    Reset(u64, u64),
221    Available(bool),
222}
223
224pub struct Streams {
225    is_server: bool,
226    cfg: StreamConfig,
227    map: IdMap<Stream>,
228    // Locally initiated: next index and the peer's limit.
229    next: [u64; 2],
230    peer_max: [u64; 2],
231    blocked_sent: [Option<u64>; 2],
232    // Remotely initiated: opened count, granted limit, closed count.
233    remote_opened: [u64; 2],
234    local_max: [u64; 2],
235    remote_closed: [u64; 2],
236    // Peer's initial per-stream limits.
237    peer_bidi_local: u64,
238    peer_bidi_remote: u64,
239    peer_uni: u64,
240    // Connection flow control: sending.
241    pub send_max_data: u64,
242    written: u64,
243    data_blocked_at: Option<u64>,
244    // Connection flow control: receiving.
245    recv_max_data: u64,
246    recv_highest: u64,
247    recv_consumed: u64,
248    /// Out-of-order chunks buffered over all streams (bounded by [`MAX_RECV_GAPS`]).
249    recv_gaps: usize,
250    send_queue: VecDeque<u64>,
251    pub control: VecDeque<Control>,
252    pub events: VecDeque<StreamEvent>,
253}
254
255/// Index 0 = bidi, 1 = uni.
256#[inline]
257fn dir(id: u64) -> usize {
258    ((id >> 1) & 1) as usize
259}
260
261impl Streams {
262    pub fn new(is_server: bool, cfg: StreamConfig) -> Self {
263        Streams {
264            is_server,
265            map: IdMap::default(),
266            next: [0; 2],
267            peer_max: [0; 2],
268            blocked_sent: [None; 2],
269            remote_opened: [0; 2],
270            local_max: [cfg.max_streams_bidi, cfg.max_streams_uni],
271            remote_closed: [0; 2],
272            peer_bidi_local: 0,
273            peer_bidi_remote: 0,
274            peer_uni: 0,
275            send_max_data: 0,
276            written: 0,
277            data_blocked_at: None,
278            recv_max_data: cfg.conn_window,
279            recv_highest: 0,
280            recv_consumed: 0,
281            recv_gaps: 0,
282            send_queue: VecDeque::new(),
283            control: VecDeque::new(),
284            events: VecDeque::new(),
285            cfg,
286        }
287    }
288
289    /// Applies the peer's transport parameters.
290    pub fn set_peer_params(&mut self, p: &crate::params::TransportParams) {
291        self.peer_max = [p.initial_max_streams_bidi, p.initial_max_streams_uni];
292        self.peer_bidi_local = p.initial_max_stream_data_bidi_local;
293        self.peer_bidi_remote = p.initial_max_stream_data_bidi_remote;
294        self.peer_uni = p.initial_max_stream_data_uni;
295        self.send_max_data = p.initial_max_data;
296    }
297
298    fn local(&self, id: u64) -> bool {
299        is_server_initiated(id) == self.is_server
300    }
301
302    pub fn len(&self) -> usize {
303        self.map.len()
304    }
305    pub fn is_empty(&self) -> bool {
306        self.map.is_empty()
307    }
308
309    fn new_stream(&self, id: u64) -> Stream {
310        let local = self.local(id);
311        let bidi = is_bidi(id);
312        let send = if bidi || local {
313            // Peer's limit for data we send: their "remote" for our streams, "local" for theirs.
314            let max = if !bidi {
315                self.peer_uni
316            } else if local {
317                self.peer_bidi_remote
318            } else {
319                self.peer_bidi_local
320            };
321            Some(SendStream { max_data: max, ..Default::default() })
322        } else {
323            None
324        };
325        let recv = if bidi || !local {
326            let w = if !bidi {
327                self.cfg.stream_window_uni
328            } else if local {
329                self.cfg.stream_window_bidi_local
330            } else {
331                self.cfg.stream_window_bidi_remote
332            };
333            Some(RecvStream { max_data: w, window: w, ..Default::default() })
334        } else {
335            None
336        };
337        Stream { send, recv }
338    }
339
340    /// Opens a locally initiated stream.
341    pub fn open(&mut self, bidi: bool) -> Result<u64, StreamError> {
342        let d = (!bidi) as usize;
343        if self.next[d] >= self.peer_max[d] {
344            if self.blocked_sent[d] != Some(self.peer_max[d]) {
345                self.blocked_sent[d] = Some(self.peer_max[d]);
346                self.control.push_back(Control::StreamsBlocked(bidi));
347            }
348            return Err(StreamError::LimitReached);
349        }
350        let id = self.next[d] << 2 | (d as u64) << 1 | self.is_server as u64;
351        self.next[d] += 1;
352        let s = self.new_stream(id);
353        self.map.insert(id, s);
354        Ok(id)
355    }
356
357    /// Looks up a stream named in a received frame, creating peer-initiated streams (and
358    /// all lower-numbered ones of the same type) as needed. `Ok(None)` means the stream is
359    /// already closed and the frame should be ignored.
360    fn get_or_open(&mut self, id: u64, ty: u64) -> Result<Option<&mut Stream>, TransportError> {
361        let d = dir(id);
362        let idx = id >> 2;
363        if self.local(id) {
364            if idx >= self.next[d] {
365                return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "frame for a stream not yet opened"));
366            }
367        } else if idx >= self.remote_opened[d] {
368            if idx >= self.local_max[d] {
369                return Err(TransportError::frame(STREAM_LIMIT_ERROR, ty, "stream limit exceeded"));
370            }
371            for i in self.remote_opened[d]..=idx {
372                let sid = i << 2 | (d as u64) << 1 | (!self.is_server) as u64;
373                let s = self.new_stream(sid);
374                self.map.insert(sid, s);
375                self.events.push_back(StreamEvent::Opened(sid));
376            }
377            self.remote_opened[d] = idx + 1;
378        }
379        Ok(self.map.get_mut(&id))
380    }
381
382    // ---- received frames ----
383
384    pub fn on_stream(&mut self, id: u64, off: u64, data: &[u8], fin: bool) -> Result<(), TransportError> {
385        let ty = frame::STREAM;
386        if self.local(id) && !is_bidi(id) {
387            return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "STREAM on a send-only stream"));
388        }
389        let conn_max = self.recv_max_data;
390        let mut conn_highest = self.recv_highest;
391        let mut gaps_total = self.recv_gaps;
392        let Some(s) = self.get_or_open(id, ty)? else { return Ok(()) };
393        let r = s.recv.as_mut().unwrap();
394        let end = off + data.len() as u64;
395        if end > r.max_data {
396            return Err(TransportError::frame(FLOW_CONTROL_ERROR, ty, "stream flow control exceeded"));
397        }
398        if let Some(fs) = r.final_size {
399            if end > fs || (fin && end != fs) {
400                return Err(TransportError::frame(FINAL_SIZE_ERROR, ty, "final size changed"));
401            }
402        }
403        if fin {
404            if end < r.highest {
405                return Err(TransportError::frame(FINAL_SIZE_ERROR, ty, "final size below received data"));
406            }
407            r.final_size = Some(end);
408        }
409        if end > r.highest {
410            conn_highest += end - r.highest;
411            if conn_highest > conn_max {
412                return Err(TransportError::frame(FLOW_CONTROL_ERROR, ty, "connection flow control exceeded"));
413            }
414            r.highest = end;
415        }
416        if r.reset.is_some() || r.stop.is_some() {
417            self.recv_highest = conn_highest;
418            return Ok(());
419        }
420        let before = r.contiguous_end();
421        let gaps_before = r.gaps();
422        r.insert(off, data);
423        gaps_total = gaps_total + r.gaps() - gaps_before;
424        if gaps_total > MAX_RECV_GAPS {
425            return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "too many out-of-order stream fragments"));
426        }
427        let readable = r.contiguous_end() > before || (r.final_size == Some(r.contiguous_end()) && !r.fin_delivered);
428        if readable && !r.notified {
429            r.notified = true;
430            self.events.push_back(StreamEvent::Readable(id));
431        }
432        self.recv_highest = conn_highest;
433        self.recv_gaps = gaps_total;
434        Ok(())
435    }
436
437    pub fn on_reset(&mut self, id: u64, code: u64, final_size: u64) -> Result<(), TransportError> {
438        let ty = frame::RESET_STREAM;
439        if self.local(id) && !is_bidi(id) {
440            return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "RESET_STREAM on a send-only stream"));
441        }
442        let conn_max = self.recv_max_data;
443        let mut conn_highest = self.recv_highest;
444        let mut gaps_total = self.recv_gaps;
445        let Some(s) = self.get_or_open(id, ty)? else { return Ok(()) };
446        let r = s.recv.as_mut().unwrap();
447        if let Some(fs) = r.final_size {
448            if fs != final_size {
449                return Err(TransportError::frame(FINAL_SIZE_ERROR, ty, "final size changed"));
450            }
451        }
452        if final_size < r.highest {
453            return Err(TransportError::frame(FINAL_SIZE_ERROR, ty, "final size below received data"));
454        }
455        if final_size > r.max_data {
456            return Err(TransportError::frame(FLOW_CONTROL_ERROR, ty, "final size exceeds flow control"));
457        }
458        conn_highest += final_size - r.highest;
459        if conn_highest > conn_max {
460            return Err(TransportError::frame(FLOW_CONTROL_ERROR, ty, "connection flow control exceeded"));
461        }
462        r.highest = final_size;
463        r.final_size = Some(final_size);
464        let mut released = None;
465        if r.reset.is_none() && !r.fin_delivered {
466            r.reset = Some(code);
467            // Unread bytes no longer count against the connection window.
468            released = Some(final_size - r.read);
469            r.data.clear();
470            gaps_total -= r.gaps();
471            r.ooo.clear();
472        }
473        self.recv_highest = conn_highest;
474        self.recv_gaps = gaps_total;
475        if let Some(rel) = released {
476            self.recv_consumed += rel;
477            self.events.push_back(StreamEvent::Reset(id, code));
478            self.maybe_max_data();
479        }
480        self.maybe_remove(id);
481        Ok(())
482    }
483
484    pub fn on_stop_sending(&mut self, id: u64, code: u64) -> Result<(), TransportError> {
485        let ty = frame::STOP_SENDING;
486        if !self.local(id) && !is_bidi(id) {
487            return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "STOP_SENDING on a receive-only stream"));
488        }
489        let Some(s) = self.get_or_open(id, ty)? else { return Ok(()) };
490        let snd = s.send.as_mut().unwrap();
491        if snd.stopped.is_some() {
492            return Ok(());
493        }
494        snd.stopped = Some(code);
495        // RFC 9000 §3.5: respond with RESET_STREAM.
496        let reset = snd.reset.is_none() && !(snd.fin && snd.fin_acked);
497        if reset {
498            snd.reset = Some((code, snd.end()));
499            snd.retransmit.clear();
500        }
501        self.events.push_back(StreamEvent::Stopped(id, code));
502        if reset {
503            self.control.push_back(Control::ResetStream(id));
504        }
505        Ok(())
506    }
507
508    pub fn on_max_stream_data(&mut self, id: u64, max: u64) -> Result<(), TransportError> {
509        let ty = frame::MAX_STREAM_DATA;
510        if !self.local(id) && !is_bidi(id) {
511            return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "MAX_STREAM_DATA on a receive-only stream"));
512        }
513        let Some(s) = self.get_or_open(id, ty)? else { return Ok(()) };
514        let snd = s.send.as_mut().unwrap();
515        if max > snd.max_data {
516            snd.max_data = max;
517            if snd.want_writable {
518                snd.want_writable = false;
519                self.events.push_back(StreamEvent::Writable(id));
520            }
521        }
522        Ok(())
523    }
524
525    pub fn on_stream_data_blocked(&mut self, id: u64) -> Result<(), TransportError> {
526        let ty = frame::STREAM_DATA_BLOCKED;
527        if self.local(id) && !is_bidi(id) {
528            return Err(TransportError::frame(STREAM_STATE_ERROR, ty, "STREAM_DATA_BLOCKED on a send-only stream"));
529        }
530        self.get_or_open(id, ty)?;
531        Ok(())
532    }
533
534    pub fn on_max_data(&mut self, max: u64) {
535        if max > self.send_max_data {
536            self.send_max_data = max;
537            // Wake every stream that was blocked on connection credit.
538            for (&id, s) in self.map.iter_mut() {
539                if let Some(snd) = s.send.as_mut() {
540                    if snd.want_writable {
541                        snd.want_writable = false;
542                        self.events.push_back(StreamEvent::Writable(id));
543                    }
544                }
545            }
546        }
547    }
548
549    pub fn on_max_streams(&mut self, bidi: bool, max: u64) {
550        let d = (!bidi) as usize;
551        if max > self.peer_max[d] {
552            let was_blocked = self.next[d] >= self.peer_max[d];
553            self.peer_max[d] = max;
554            if was_blocked {
555                self.events.push_back(StreamEvent::Available(bidi));
556            }
557        }
558    }
559
560    pub fn on_streams_blocked(&mut self, bidi: bool, limit: u64) {
561        // The peer wants more streams; MAX_STREAMS is raised as streams close.
562        let _ = (bidi, limit);
563    }
564
565    // ---- application API ----
566
567    /// Buffers `data` for sending; returns how many bytes were accepted.
568    pub fn write(&mut self, id: u64, data: &[u8], fin: bool) -> Result<usize, StreamError> {
569        let conn_room = self.send_max_data - self.written;
570        let cap = self.cfg.send_buffer;
571        let s = self.map.get_mut(&id).ok_or(StreamError::UnknownStream)?;
572        let snd = s.send.as_mut().ok_or(StreamError::InvalidDirection)?;
573        if let Some(code) = snd.stopped {
574            return Err(StreamError::Stopped(code));
575        }
576        if snd.reset.is_some() || snd.fin {
577            return Err(StreamError::Finished);
578        }
579        let end = snd.end();
580        let stream_room = snd.max_data.saturating_sub(end);
581        let buf_room = cap.saturating_sub(snd.buf.len() as u64);
582        let n = (data.len() as u64).min(stream_room).min(conn_room).min(buf_room) as usize;
583        if n == 0 && !data.is_empty() {
584            snd.want_writable = true;
585            if stream_room == 0 && snd.blocked_at != Some(snd.max_data) {
586                snd.blocked_at = Some(snd.max_data);
587                self.control.push_back(Control::StreamDataBlocked(id));
588            }
589            if conn_room == 0 && self.data_blocked_at != Some(self.send_max_data) {
590                self.data_blocked_at = Some(self.send_max_data);
591                self.control.push_back(Control::DataBlocked);
592            }
593            return Err(StreamError::Blocked);
594        }
595        snd.buf.extend(&data[..n]);
596        self.written += n as u64;
597        if n < data.len() {
598            snd.want_writable = true;
599        } else if fin {
600            snd.fin = true;
601        }
602        if !snd.queued && snd.has_pending() {
603            snd.queued = true;
604            self.send_queue.push_back(id);
605        }
606        Ok(n)
607    }
608
609    /// Reads in-order data; returns (bytes, fin reached).
610    pub fn read(&mut self, id: u64, out: &mut [u8]) -> Result<(usize, bool), StreamError> {
611        let s = self.map.get_mut(&id).ok_or(StreamError::UnknownStream)?;
612        let r = s.recv.as_mut().ok_or(StreamError::InvalidDirection)?;
613        if let Some(code) = r.reset {
614            r.reset_delivered = true;
615            self.maybe_remove(id);
616            return Err(StreamError::Reset(code));
617        }
618        let n = out.len().min(r.data.len());
619        let (a, b) = r.data.as_slices();
620        if n <= a.len() {
621            out[..n].copy_from_slice(&a[..n]);
622        } else {
623            out[..a.len()].copy_from_slice(a);
624            out[a.len()..n].copy_from_slice(&b[..n - a.len()]);
625        }
626        r.data.drain(..n);
627        r.read += n as u64;
628        let fin = r.data.is_empty() && r.final_size == Some(r.read);
629        if n == 0 && !fin {
630            r.notified = false;
631            return Err(StreamError::WouldBlock);
632        }
633        if r.data.is_empty() {
634            r.notified = false;
635        }
636        // Stream credit: top up when less than half the window is left.
637        if r.final_size.is_none() && r.max_data - r.read < r.window / 2 {
638            r.max_data = r.read + r.window;
639            self.control.push_back(Control::MaxStreamData(id));
640        }
641        if fin {
642            r.fin_delivered = true;
643        }
644        self.recv_consumed += n as u64;
645        self.maybe_max_data();
646        if fin {
647            self.maybe_remove(id);
648        }
649        Ok((n, fin))
650    }
651
652    fn maybe_max_data(&mut self) {
653        if self.recv_max_data - self.recv_consumed < self.cfg.conn_window / 2 {
654            self.recv_max_data = self.recv_consumed + self.cfg.conn_window;
655            self.control.push_back(Control::MaxData);
656        }
657    }
658
659    /// Abandons sending with RESET_STREAM.
660    pub fn reset(&mut self, id: u64, code: u64) -> Result<(), StreamError> {
661        let s = self.map.get_mut(&id).ok_or(StreamError::UnknownStream)?;
662        let snd = s.send.as_mut().ok_or(StreamError::InvalidDirection)?;
663        if snd.reset.is_some() || (snd.fin && snd.fin_acked) {
664            return Ok(());
665        }
666        snd.reset = Some((code, snd.end()));
667        snd.retransmit.clear();
668        self.control.push_back(Control::ResetStream(id));
669        Ok(())
670    }
671
672    /// Asks the peer to stop sending with STOP_SENDING; buffered data is discarded.
673    pub fn stop(&mut self, id: u64, code: u64) -> Result<(), StreamError> {
674        let s = self.map.get_mut(&id).ok_or(StreamError::UnknownStream)?;
675        let r = s.recv.as_mut().ok_or(StreamError::InvalidDirection)?;
676        if r.stop.is_some() || r.reset.is_some() || r.fin_delivered {
677            return Ok(());
678        }
679        r.stop = Some(code);
680        let unread = r.data.len() as u64;
681        r.data.clear();
682        self.recv_gaps -= r.gaps();
683        r.ooo.clear();
684        r.read = r.highest;
685        self.recv_consumed += unread;
686        if r.final_size.is_none() {
687            self.control.push_back(Control::StopSending(id));
688        }
689        self.maybe_max_data();
690        self.maybe_remove(id);
691        Ok(())
692    }
693
694    // ---- packet assembly ----
695
696    pub fn has_pending_data(&self) -> bool {
697        !self.send_queue.is_empty()
698    }
699
700    /// Writes STREAM frames into `out` while at least `min_room` bytes are left before
701    /// `limit`; records (id, off, len, fin) in `sent`.
702    pub fn write_frames(&mut self, out: &mut Vec<u8>, limit: usize, sent: &mut Vec<crate::recovery::SentFrame>) {
703        let mut rounds = self.send_queue.len();
704        while rounds > 0 && out.len() + 8 < limit {
705            rounds -= 1;
706            let Some(id) = self.send_queue.pop_front() else { break };
707            let Some(snd) = self.map.get_mut(&id).and_then(|s| s.send.as_mut()) else { continue };
708            snd.queued = false;
709            if !snd.has_pending() {
710                continue;
711            }
712            let room = limit - out.len();
713            let (off, avail, is_retx) = if let Some((s, e)) = snd.retransmit.first() {
714                (s, e - s, true)
715            } else {
716                (snd.sent, snd.end() - snd.sent, false)
717            };
718            let hdr = frame::stream_overhead(id, off, room);
719            if room <= hdr {
720                snd.queued = true;
721                self.send_queue.push_front(id);
722                break;
723            }
724            let len = avail.min((room - hdr) as u64) as usize;
725            let end = off + len as u64;
726            let fin = snd.fin && end == snd.end() && (!is_retx || snd.sent == snd.end());
727            if len == 0 && !fin {
728                continue;
729            }
730            frame::put_stream_header(out, id, off, len, fin);
731            let start = (off - snd.base) as usize;
732            copy_range(&snd.buf, start, len, out);
733            if is_retx {
734                snd.retransmit.remove(off, end);
735            } else {
736                snd.sent = end;
737            }
738            if fin {
739                snd.fin_sent = true;
740            }
741            sent.push(crate::recovery::SentFrame::Stream { id, off, len: len as u32, fin });
742            if snd.has_pending() {
743                snd.queued = true;
744                self.send_queue.push_back(id);
745            }
746        }
747    }
748
749    /// Writes one control frame if it fits; returns false when it does not.
750    pub fn write_control(&mut self, c: Control, out: &mut Vec<u8>, limit: usize) -> Option<bool> {
751        let mut tmp = [0u64; 3];
752        let (ty, n) = match c {
753            Control::MaxData => {
754                tmp[0] = self.recv_max_data;
755                (frame::MAX_DATA, 1)
756            }
757            Control::MaxStreamData(id) => {
758                let r = self.map.get(&id).and_then(|s| s.recv.as_ref())?;
759                if r.final_size.is_some() || r.stop.is_some() {
760                    return None;
761                }
762                tmp[0] = id;
763                tmp[1] = r.max_data;
764                (frame::MAX_STREAM_DATA, 2)
765            }
766            Control::MaxStreams(bidi) => {
767                tmp[0] = self.local_max[(!bidi) as usize];
768                (if bidi { frame::MAX_STREAMS_BIDI } else { frame::MAX_STREAMS_UNI }, 1)
769            }
770            Control::DataBlocked => {
771                if self.written < self.send_max_data {
772                    return None;
773                }
774                tmp[0] = self.send_max_data;
775                (frame::DATA_BLOCKED, 1)
776            }
777            Control::StreamDataBlocked(id) => {
778                let snd = self.map.get(&id).and_then(|s| s.send.as_ref())?;
779                if snd.end() < snd.max_data || snd.reset.is_some() {
780                    return None;
781                }
782                tmp[0] = id;
783                tmp[1] = snd.max_data;
784                (frame::STREAM_DATA_BLOCKED, 2)
785            }
786            Control::StreamsBlocked(bidi) => {
787                let d = (!bidi) as usize;
788                if self.next[d] < self.peer_max[d] {
789                    return None;
790                }
791                tmp[0] = self.peer_max[d];
792                (if bidi { frame::STREAMS_BLOCKED_BIDI } else { frame::STREAMS_BLOCKED_UNI }, 1)
793            }
794            Control::ResetStream(id) => {
795                let snd = self.map.get(&id).and_then(|s| s.send.as_ref())?;
796                let (code, fs) = snd.reset?;
797                if snd.reset_acked {
798                    return None;
799                }
800                tmp = [id, code, fs];
801                (frame::RESET_STREAM, 3)
802            }
803            Control::StopSending(id) => {
804                let r = self.map.get(&id).and_then(|s| s.recv.as_ref())?;
805                let code = r.stop?;
806                if r.final_size.is_some() {
807                    return None;
808                }
809                tmp[0] = id;
810                tmp[1] = code;
811                (frame::STOP_SENDING, 2)
812            }
813        };
814        let size = 1 + tmp[..n].iter().map(|&v| varint_len(v)).sum::<usize>();
815        if out.len() + size > limit {
816            return Some(false);
817        }
818        frame::put_simple(out, ty, &tmp[..n]);
819        Some(true)
820    }
821
822    // ---- acknowledgements and loss ----
823
824    pub fn on_stream_acked(&mut self, id: u64, off: u64, len: u64, fin: bool) {
825        let Some(snd) = self.map.get_mut(&id).and_then(|s| s.send.as_mut()) else { return };
826        // Only the part above `base` matters. An acknowledgement of bytes already released
827        // (the original packet and its retransmission both acknowledged, as after a blackout)
828        // must not be recorded: a range below `base` would stay first in `acked` forever, the
829        // prefix check below would never pass again, and the send buffer would stay full.
830        let lo = off.max(snd.base);
831        if off + len > lo {
832            snd.acked.insert(lo, off + len);
833            // Release the acknowledged prefix.
834            if let Some((s, e)) = snd.acked.first() {
835                if s <= snd.base && e > snd.base {
836                    let n = (e - snd.base) as usize;
837                    snd.buf.drain(..n.min(snd.buf.len()));
838                    snd.base = e;
839                    snd.acked.remove_below(e);
840                    snd.retransmit.remove_below(e);
841                    if snd.want_writable {
842                        snd.want_writable = false;
843                        self.events.push_back(StreamEvent::Writable(id));
844                    }
845                }
846            }
847        }
848        if fin {
849            snd.fin_acked = true;
850        }
851        self.maybe_remove(id);
852    }
853
854    pub fn on_stream_lost(&mut self, id: u64, off: u64, len: u64, fin: bool) {
855        let Some(snd) = self.map.get_mut(&id).and_then(|s| s.send.as_mut()) else { return };
856        if snd.reset.is_some() {
857            return;
858        }
859        let end = off + len;
860        let lo = off.max(snd.base);
861        if end > lo {
862            snd.retransmit.insert(lo, end);
863            // Do not resend what has since been acknowledged.
864            for (s, e) in snd.acked.clone().iter() {
865                snd.retransmit.remove(s, e);
866            }
867        }
868        if fin && !snd.fin_acked {
869            snd.fin_sent = false;
870        }
871        if !snd.queued && snd.has_pending() {
872            snd.queued = true;
873            self.send_queue.push_back(id);
874        }
875    }
876
877    pub fn on_reset_acked(&mut self, id: u64) {
878        if let Some(snd) = self.map.get_mut(&id).and_then(|s| s.send.as_mut()) {
879            snd.reset_acked = true;
880        }
881        self.maybe_remove(id);
882    }
883
884    /// Removes a fully closed stream and, for peer streams, raises the stream limit.
885    fn maybe_remove(&mut self, id: u64) {
886        let Some(s) = self.map.get(&id) else { return };
887        let send_done = s.send.as_ref().is_none_or(|x| x.is_done());
888        let recv_done = s.recv.as_ref().is_none_or(|x| x.is_done());
889        if !(send_done && recv_done) {
890            return;
891        }
892        let s = self.map.remove(&id).unwrap();
893        if let Some(snd) = &s.send {
894            // Credit reserved for never-sent bytes stays consumed (it was counted against
895            // the peer's window when written).
896            let _ = snd;
897        }
898        if !self.local(id) {
899            let d = dir(id);
900            self.remote_closed[d] += 1;
901            let max = if d == 0 { self.cfg.max_streams_bidi } else { self.cfg.max_streams_uni };
902            let new = (self.remote_closed[d] + max).min(MAX_STREAMS_LIMIT);
903            if new - self.local_max[d] >= (max / 2).max(1) {
904                self.local_max[d] = new;
905                self.control.push_back(Control::MaxStreams(d == 0));
906            }
907        }
908    }
909
910    /// True if the stream exists.
911    pub fn contains(&self, id: u64) -> bool {
912        self.map.contains_key(&id)
913    }
914
915    /// Bytes buffered and not yet acknowledged on a send stream.
916    pub fn unacked(&self, id: u64) -> Option<u64> {
917        self.map.get(&id)?.send.as_ref().map(|s| s.buf.len() as u64)
918    }
919
920    /// How many more bytes `write` would accept now.
921    pub fn writable(&self, id: u64) -> Option<u64> {
922        let snd = self.map.get(&id)?.send.as_ref()?;
923        if snd.fin || snd.reset.is_some() {
924            return Some(0);
925        }
926        Some(
927            snd.max_data
928                .saturating_sub(snd.end())
929                .min(self.send_max_data - self.written)
930                .min(self.cfg.send_buffer.saturating_sub(snd.buf.len() as u64)),
931        )
932    }
933}
934
935/// Appends `buf[start..start + len]` to `out`.
936fn copy_range(buf: &VecDeque<u8>, start: usize, len: usize, out: &mut Vec<u8>) {
937    let (a, b) = buf.as_slices();
938    if start < a.len() {
939        let n = (a.len() - start).min(len);
940        out.extend_from_slice(&a[start..start + n]);
941        out.extend_from_slice(&b[..len - n]);
942    } else {
943        let s = start - a.len();
944        out.extend_from_slice(&b[s..s + len]);
945    }
946}
947
948#[cfg(test)]
949mod tests {
950    use super::*;
951    use crate::params::TransportParams;
952
953    fn server() -> Streams {
954        let mut s = Streams::new(
955            true,
956            StreamConfig {
957                max_streams_bidi: 2,
958                max_streams_uni: 1,
959                stream_window_bidi_local: 100,
960                stream_window_bidi_remote: 100,
961                stream_window_uni: 100,
962                conn_window: 150,
963                send_buffer: 1000,
964            },
965        );
966        let p = TransportParams {
967            initial_max_data: 50,
968            initial_max_stream_data_bidi_local: 30,
969            initial_max_stream_data_bidi_remote: 30,
970            initial_max_stream_data_uni: 30,
971            initial_max_streams_bidi: 1,
972            initial_max_streams_uni: 1,
973            ..Default::default()
974        };
975        s.set_peer_params(&p);
976        s
977    }
978
979    #[test]
980    fn receive_side_enforcement() {
981        let mut s = server();
982        // Client bidi streams 0 and 4 are allowed, 8 exceeds the limit of 2.
983        s.on_stream(0, 0, b"abc", false).unwrap();
984        assert_eq!(s.on_stream(8, 0, b"x", false).unwrap_err().code, STREAM_LIMIT_ERROR);
985        // Opening stream 4 implicitly is fine; it also announces stream 4.
986        s.on_stream(4, 0, b"", false).unwrap();
987        // Stream flow control (window 100).
988        assert_eq!(s.on_stream(0, 98, b"xyz", false).unwrap_err().code, FLOW_CONTROL_ERROR);
989        // Connection flow control (150 in total across streams).
990        s.on_stream(0, 0, &[0; 100], false).unwrap();
991        assert_eq!(s.on_stream(4, 0, &[0; 51], false).unwrap_err().code, FLOW_CONTROL_ERROR);
992        // Final size rules.
993        let mut s = server();
994        s.on_stream(0, 0, b"hello", true).unwrap();
995        assert_eq!(s.on_stream(0, 0, b"hello!", false).unwrap_err().code, FINAL_SIZE_ERROR);
996        assert_eq!(s.on_stream(0, 0, b"hel", true).unwrap_err().code, FINAL_SIZE_ERROR);
997        assert_eq!(s.on_reset(0, 1, 4).unwrap_err().code, FINAL_SIZE_ERROR);
998        let mut s = server();
999        s.on_stream(0, 0, b"hello", false).unwrap();
1000        assert_eq!(s.on_stream(0, 0, b"he", true).unwrap_err().code, FINAL_SIZE_ERROR);
1001        // Our own streams: unopened ones and send-only directions.
1002        let mut s = server();
1003        assert_eq!(s.on_stream(1, 0, b"x", false).unwrap_err().code, STREAM_STATE_ERROR);
1004        let uni = s.open(false).unwrap();
1005        assert_eq!(uni, 3);
1006        assert_eq!(s.on_stream(3, 0, b"x", false).unwrap_err().code, STREAM_STATE_ERROR);
1007        assert_eq!(s.on_stop_sending(2, 0).unwrap_err().code, STREAM_STATE_ERROR); // client uni
1008        assert_eq!(s.on_max_stream_data(2, 5).unwrap_err().code, STREAM_STATE_ERROR);
1009    }
1010
1011    #[test]
1012    fn reassembly_out_of_order_and_overlapping() {
1013        let mut s = server();
1014        s.on_stream(0, 6, b"ghij", false).unwrap();
1015        s.on_stream(0, 3, b"defgh", false).unwrap();
1016        s.on_stream(0, 8, b"ijkl", true).unwrap();
1017        let mut out = [0u8; 32];
1018        assert_eq!(s.read(0, &mut out), Err(StreamError::WouldBlock));
1019        s.on_stream(0, 0, b"abcd", false).unwrap();
1020        let (n, fin) = s.read(0, &mut out).unwrap();
1021        assert_eq!(&out[..n], b"abcdefghijkl");
1022        assert!(fin);
1023        assert_eq!(s.events.iter().filter(|e| matches!(e, StreamEvent::Readable(0))).count(), 1);
1024    }
1025
1026    fn wide() -> Streams {
1027        let w = 1 << 20;
1028        Streams::new(
1029            true,
1030            StreamConfig {
1031                max_streams_bidi: 4,
1032                max_streams_uni: 4,
1033                stream_window_bidi_local: w,
1034                stream_window_bidi_remote: w,
1035                stream_window_uni: w,
1036                conn_window: w,
1037                send_buffer: 1000,
1038            },
1039        )
1040    }
1041
1042    fn gaps(s: &Streams, id: u64) -> usize {
1043        s.map.get(&id).unwrap().recv.as_ref().unwrap().gaps()
1044    }
1045
1046    #[test]
1047    fn adjacent_out_of_order_chunks_merge_and_reassemble() {
1048        // Chunks of 1..=7 bytes over 0..2000 delivered out of order (odd ones, then even ones,
1049        // then all again as duplicates): adjacent buffered chunks merge, so the map holds one
1050        // entry per gap, and the data comes out intact.
1051        let data: Vec<u8> = (0..2000u32).map(|i| (i * 31 % 251) as u8).collect();
1052        let mut chunks = Vec::new();
1053        let mut off = 0usize;
1054        while off < data.len() {
1055            let end = (off + 1 + off % 7).min(data.len());
1056            chunks.push((off, end));
1057            off = end;
1058        }
1059        let mut st = wide();
1060        let odd = (1..chunks.len()).filter(|i| i % 2 == 1);
1061        let even = (1..chunks.len()).filter(|i| i % 2 == 0);
1062        for i in odd.chain(even).chain(1..chunks.len()) {
1063            let (a, b) = chunks[i];
1064            st.on_stream(0, a as u64, &data[a..b], b == data.len()).unwrap();
1065            assert!(gaps(&st, 0) <= chunks.len() / 2 + 1);
1066        }
1067        assert_eq!(gaps(&st, 0), 1, "everything after the first hole merged into one chunk");
1068        st.on_stream(0, 0, &data[..chunks[0].1], false).unwrap();
1069        let mut out = vec![0u8; 4096];
1070        let (n, fin) = st.read(0, &mut out).unwrap();
1071        assert_eq!(&out[..n], &data[..]);
1072        assert!(fin);
1073    }
1074
1075    #[test]
1076    fn too_many_out_of_order_gaps_is_an_error() {
1077        let mut st = wide();
1078        for i in 0..MAX_RECV_GAPS as u64 {
1079            st.on_stream(0, 2 + 2 * i, b"x", false).unwrap();
1080        }
1081        assert_eq!(gaps(&st, 0), MAX_RECV_GAPS);
1082        let e = st.on_stream(0, 2 + 2 * MAX_RECV_GAPS as u64, b"x", false).unwrap_err();
1083        assert_eq!(e.code, PROTOCOL_VIOLATION);
1084    }
1085
1086    /// The cap is per connection: spreading holes over many streams does not multiply it, and
1087    /// a reset stream gives its holes back.
1088    #[test]
1089    fn out_of_order_gap_cap_is_per_connection() {
1090        let mut st = wide();
1091        let per = (MAX_RECV_GAPS / 4) as u64;
1092        for id in [0u64, 4, 8, 12] {
1093            for i in 0..per {
1094                st.on_stream(id, 2 + 2 * i, b"x", false).unwrap();
1095            }
1096        }
1097        assert_eq!(st.recv_gaps, MAX_RECV_GAPS);
1098        let e = st.on_stream(4, 2 + 2 * per, b"x", false).unwrap_err();
1099        assert_eq!(e.code, PROTOCOL_VIOLATION, "one more hole on any stream is over the connection's cap");
1100        let mut st = wide();
1101        for i in 0..per {
1102            st.on_stream(0, 2 + 2 * i, b"x", false).unwrap();
1103        }
1104        st.on_reset(0, 0, 2 + 2 * per).unwrap();
1105        assert_eq!(st.recv_gaps, 0, "a reset stream's holes no longer count");
1106        // Filling holes merges chunks and lowers the count.
1107        st.on_stream(4, 2, b"x", false).unwrap();
1108        st.on_stream(4, 4, b"x", false).unwrap();
1109        assert_eq!(st.recv_gaps, 2);
1110        st.on_stream(4, 3, b"x", false).unwrap();
1111        assert_eq!(st.recv_gaps, 1, "adjacent chunks merged into one hole");
1112        st.on_stream(4, 0, b"xx", false).unwrap();
1113        assert_eq!(st.recv_gaps, 0);
1114    }
1115
1116    #[test]
1117    fn send_side_credit_and_limits() {
1118        let mut s = server();
1119        let id = s.open(true).unwrap();
1120        assert_eq!(id, 1);
1121        assert_eq!(s.open(true), Err(StreamError::LimitReached));
1122        assert_eq!(s.control.back(), Some(&Control::StreamsBlocked(true)));
1123        // Stream credit 30.
1124        assert_eq!(s.write(id, &[1; 100], false), Ok(30));
1125        assert_eq!(s.write(id, &[1; 1], false), Err(StreamError::Blocked));
1126        assert!(s.control.contains(&Control::StreamDataBlocked(id)));
1127        s.on_max_stream_data(id, 100).unwrap();
1128        assert_eq!(s.events.back(), Some(&StreamEvent::Writable(id)));
1129        // Connection credit 50: 20 more.
1130        assert_eq!(s.write(id, &[1; 100], false), Ok(20));
1131        assert!(s.write(id, &[1; 1], false).is_err());
1132        assert!(s.control.contains(&Control::DataBlocked));
1133        s.on_max_streams(true, 2);
1134        assert_eq!(s.events.back(), Some(&StreamEvent::Available(true)));
1135        // Frames carry the data and acks free the buffer.
1136        let mut out = Vec::new();
1137        let mut sent = Vec::new();
1138        s.write_frames(&mut out, 1000, &mut sent);
1139        assert_eq!(sent, vec![crate::recovery::SentFrame::Stream { id, off: 0, len: 50, fin: false }]);
1140        s.on_stream_lost(id, 10, 20, false);
1141        out.clear();
1142        sent.clear();
1143        s.write_frames(&mut out, 1000, &mut sent);
1144        assert_eq!(sent, vec![crate::recovery::SentFrame::Stream { id, off: 10, len: 20, fin: false }]);
1145        s.on_stream_acked(id, 0, 50, false);
1146        assert_eq!(s.unacked(id), Some(0));
1147        // A late acknowledgement of the retransmission, for bytes already released, must not
1148        // block later releases (found by the interop runner's blackhole case).
1149        s.on_stream_acked(id, 10, 20, false);
1150        s.on_max_data(1000);
1151        s.on_max_stream_data(id, 1000).unwrap();
1152        assert_eq!(s.write(id, &[2; 30], false), Ok(30));
1153        out.clear();
1154        sent.clear();
1155        s.write_frames(&mut out, 1000, &mut sent);
1156        s.on_stream_acked(id, 50, 30, false);
1157        assert_eq!(s.unacked(id), Some(0), "the buffer is released after a stale acknowledgement");
1158    }
1159
1160    #[test]
1161    fn peer_streams_raise_max_streams_when_closed() {
1162        let mut s = server();
1163        s.on_stream(0, 0, b"a", true).unwrap();
1164        let mut b = [0u8; 4];
1165        s.read(0, &mut b).unwrap();
1166        s.write(0, b"", true).unwrap();
1167        let mut out = Vec::new();
1168        let mut sent = Vec::new();
1169        s.write_frames(&mut out, 1000, &mut sent);
1170        s.on_stream_acked(0, 0, 0, true);
1171        assert!(!s.contains(0));
1172        assert!(s.control.contains(&Control::MaxStreams(true)));
1173        // Stream 8 (index 2) is now allowed.
1174        s.on_stream(8, 0, b"x", false).unwrap();
1175    }
1176}