Skip to main content

h2/proto/streams/
prioritize.rs

1use super::store::Resolve;
2use super::*;
3
4use crate::frame::Reason;
5
6use crate::codec::UserError;
7use crate::codec::UserError::*;
8
9use bytes::buf::Take;
10use std::{
11    cmp::{self, Ordering},
12    fmt, io, mem,
13    task::Waker,
14};
15
16/// # Warning
17///
18/// Queued streams are ordered by stream ID, as we need to ensure that
19/// lower-numbered streams are sent headers before higher-numbered ones.
20/// This is because "idle" stream IDs – those which have been initiated but
21/// have yet to receive frames – will be implicitly closed on receipt of a
22/// frame on a higher stream ID. If these queues was not ordered by stream
23/// IDs, some mechanism would be necessary to ensure that the lowest-numbered]
24/// idle stream is opened first.
25#[derive(Debug)]
26pub(super) struct Prioritize {
27    /// Queue of streams waiting for socket capacity to send a frame.
28    pending_send: store::Queue<stream::NextSend>,
29
30    /// Queue of streams waiting for window capacity to produce data.
31    pending_capacity: store::Queue<stream::NextSendCapacity>,
32
33    /// Streams waiting for capacity due to max concurrency
34    ///
35    /// The `SendRequest` handle is `Clone`. This enables initiating requests
36    /// from many tasks. However, offering this capability while supporting
37    /// backpressure at some level is tricky. If there are many `SendRequest`
38    /// handles and a single stream becomes available, which handle gets
39    /// assigned that stream? Maybe that handle is no longer ready to send a
40    /// request.
41    ///
42    /// The strategy used is to allow each `SendRequest` handle one buffered
43    /// request. A `SendRequest` handle is ready to send a request if it has no
44    /// associated buffered requests. This is the same strategy as `mpsc` in the
45    /// futures library.
46    pending_open: store::Queue<stream::NextOpen>,
47
48    /// Connection level flow control governing sent data
49    flow: FlowControl,
50
51    /// Stream ID of the last stream opened.
52    last_opened_id: StreamId,
53
54    /// What `DATA` frame is currently being sent in the codec.
55    in_flight_data_frame: InFlightData,
56
57    /// The maximum amount of bytes a stream should buffer.
58    max_buffer_size: usize,
59}
60
61#[derive(Debug, Eq, PartialEq)]
62enum InFlightData {
63    /// There is no `DATA` frame in flight.
64    Nothing,
65    /// There is a `DATA` frame in flight belonging to the given stream.
66    DataFrame(store::Key),
67    /// There was a `DATA` frame, but the stream's queue was since cleared.
68    Drop,
69}
70
71pub(crate) struct Prioritized<B> {
72    // The buffer
73    inner: Take<B>,
74
75    end_of_stream: bool,
76
77    // The stream that this is associated with
78    stream: store::Key,
79}
80
81// ===== impl Prioritize =====
82
83impl Prioritize {
84    pub fn new(config: &Config) -> Prioritize {
85        let mut flow = FlowControl::new();
86
87        flow.inc_window(config.remote_init_window_sz)
88            .expect("invalid initial window size");
89
90        // TODO: proper error handling
91        let _res = flow.assign_capacity(config.remote_init_window_sz);
92        debug_assert!(_res.is_ok());
93
94        tracing::trace!("Prioritize::new; flow={:?}", flow);
95
96        Prioritize {
97            pending_send: store::Queue::new(),
98            pending_capacity: store::Queue::new(),
99            pending_open: store::Queue::new(),
100            flow,
101            last_opened_id: StreamId::ZERO,
102            in_flight_data_frame: InFlightData::Nothing,
103            max_buffer_size: config.local_max_buffer_size,
104        }
105    }
106
107    pub(crate) fn max_buffer_size(&self) -> usize {
108        self.max_buffer_size
109    }
110
111    /// Queue a frame to be sent to the remote
112    pub fn queue_frame<B>(
113        &mut self,
114        frame: Frame<B>,
115        buffer: &mut Buffer<Frame<B>>,
116        stream: &mut store::Ptr,
117        task: &mut Option<Waker>,
118    ) {
119        let span = tracing::trace_span!("Prioritize::queue_frame", ?stream.id);
120        let _e = span.enter();
121        // Queue the frame in the buffer
122        stream.pending_send.push_back(buffer, frame);
123        self.schedule_send(stream, task);
124    }
125
126    pub fn schedule_send(&mut self, stream: &mut store::Ptr, task: &mut Option<Waker>) {
127        // If the stream is waiting to be opened, nothing more to do.
128        if stream.is_send_ready() {
129            tracing::trace!(?stream.id, "schedule_send");
130            // Queue the stream
131            self.pending_send.push(stream);
132
133            // Notify the connection.
134            if let Some(task) = task.take() {
135                task.wake();
136            }
137        }
138    }
139
140    pub fn queue_open(&mut self, stream: &mut store::Ptr) {
141        self.pending_open.push(stream);
142    }
143
144    /// Send a data frame
145    pub fn send_data<B>(
146        &mut self,
147        frame: frame::Data<B>,
148        buffer: &mut Buffer<Frame<B>>,
149        stream: &mut store::Ptr,
150        counts: &mut Counts,
151        task: &mut Option<Waker>,
152    ) -> Result<(), UserError>
153    where
154        B: Buf,
155    {
156        let sz = frame.payload().remaining();
157
158        if sz > MAX_WINDOW_SIZE as usize {
159            return Err(UserError::PayloadTooBig);
160        }
161
162        let sz = sz as WindowSize;
163
164        if !stream.state.is_send_streaming() {
165            if stream.state.is_closed() {
166                return Err(InactiveStreamId);
167            } else {
168                return Err(UnexpectedFrameType);
169            }
170        }
171
172        // Update the buffered data counter
173        stream.buffered_send_data += sz as usize;
174
175        let span =
176            tracing::trace_span!("send_data", sz, requested = stream.requested_send_capacity);
177        let _e = span.enter();
178        tracing::trace!(buffered = stream.buffered_send_data);
179
180        // Implicitly request more send capacity if not enough has been
181        // requested yet.
182        if (stream.requested_send_capacity as usize) < stream.buffered_send_data {
183            // Update the target requested capacity
184            stream.requested_send_capacity =
185                cmp::min(stream.buffered_send_data, WindowSize::MAX as usize) as WindowSize;
186
187            // `try_assign_capacity` will queue the stream to `pending_capacity` if the capcaity
188            // cannot be assigned at the time it is called.
189            self.try_assign_capacity(stream);
190        }
191
192        if frame.is_end_stream() {
193            stream.state.send_close();
194            self.reserve_capacity(0, stream, counts);
195        }
196
197        tracing::trace!(
198            available = %stream.send_flow.available(),
199            buffered = stream.buffered_send_data,
200        );
201
202        // The `stream.buffered_send_data == 0` check is here so that, if a zero
203        // length data frame is queued to the front (there is no previously
204        // queued data), it gets sent out immediately even if there is no
205        // available send window.
206        //
207        // Sending out zero length data frames can be done to signal
208        // end-of-stream.
209        //
210        if stream.send_flow.available() > 0 || stream.buffered_send_data == 0 {
211            // The stream currently has capacity to send the data frame, so
212            // queue it up and notify the connection task.
213            self.queue_frame(frame.into(), buffer, stream, task);
214        } else {
215            // The stream has no capacity to send the frame now, save it but
216            // don't notify the connection task. Once additional capacity
217            // becomes available, the frame will be flushed.
218            stream.pending_send.push_back(buffer, frame.into());
219        }
220
221        Ok(())
222    }
223
224    /// Request capacity to send data
225    pub fn reserve_capacity(
226        &mut self,
227        capacity: WindowSize,
228        stream: &mut store::Ptr,
229        counts: &mut Counts,
230    ) {
231        let span = tracing::trace_span!(
232            "reserve_capacity",
233            ?stream.id,
234            requested = capacity,
235            effective = (capacity as usize) + stream.buffered_send_data,
236            curr = stream.requested_send_capacity
237        );
238        let _e = span.enter();
239
240        // Actual capacity is `capacity` + the current amount of buffered data.
241        // If it were less, then we could never send out the buffered data.
242        let capacity = (capacity as usize) + stream.buffered_send_data;
243
244        match capacity.cmp(&(stream.requested_send_capacity as usize)) {
245            Ordering::Equal => {
246                // Nothing to do
247            }
248            Ordering::Less => {
249                // Update the target requested capacity
250                stream.requested_send_capacity = capacity as WindowSize;
251
252                // Currently available capacity assigned to the stream
253                let available = stream.send_flow.available().as_size();
254
255                // If the stream has more assigned capacity than requested, reclaim
256                // some for the connection
257                if available as usize > capacity {
258                    let diff = available - capacity as WindowSize;
259
260                    // TODO: proper error handling
261                    let _res = stream.send_flow.claim_capacity(diff);
262                    debug_assert!(_res.is_ok());
263
264                    self.assign_connection_capacity(diff, stream, counts);
265                }
266            }
267            Ordering::Greater => {
268                // If trying to *add* capacity, but the stream send side is closed,
269                // there's nothing to be done.
270                if stream.state.is_send_closed() {
271                    return;
272                }
273
274                // Update the target requested capacity
275                stream.requested_send_capacity =
276                    cmp::min(capacity, WindowSize::MAX as usize) as WindowSize;
277
278                // Try to assign additional capacity to the stream. If none is
279                // currently available, the stream will be queued to receive some
280                // when more becomes available.
281                self.try_assign_capacity(stream);
282            }
283        }
284    }
285
286    pub fn recv_stream_window_update(
287        &mut self,
288        inc: WindowSize,
289        stream: &mut store::Ptr,
290    ) -> Result<(), Reason> {
291        let span = tracing::trace_span!(
292            "recv_stream_window_update",
293            ?stream.id,
294            ?stream.state,
295            inc,
296            flow = ?stream.send_flow
297        );
298        let _e = span.enter();
299
300        if stream.state.is_send_closed() && stream.buffered_send_data == 0 {
301            // We can't send any data, so don't bother doing anything else.
302            return Ok(());
303        }
304
305        // Update the stream level flow control.
306        stream.send_flow.inc_window(inc)?;
307
308        // If the stream is waiting on additional capacity, then this will
309        // assign it (if available on the connection) and notify the producer
310        self.try_assign_capacity(stream);
311
312        Ok(())
313    }
314
315    pub fn recv_connection_window_update(
316        &mut self,
317        inc: WindowSize,
318        store: &mut Store,
319        counts: &mut Counts,
320    ) -> Result<(), Reason> {
321        // Update the connection's window
322        self.flow.inc_window(inc)?;
323
324        self.assign_connection_capacity(inc, store, counts);
325        Ok(())
326    }
327
328    /// Reclaim all capacity assigned to the stream and re-assign it to the
329    /// connection
330    pub fn reclaim_all_capacity(&mut self, stream: &mut store::Ptr, counts: &mut Counts) {
331        let available = stream.send_flow.available().as_size();
332        if available > 0 {
333            // TODO: proper error handling
334            let _res = stream.send_flow.claim_capacity(available);
335            debug_assert!(_res.is_ok());
336            // Re-assign all capacity to the connection
337            self.assign_connection_capacity(available, stream, counts);
338        }
339    }
340
341    /// Reclaim just reserved capacity, not buffered capacity, and re-assign
342    /// it to the connection
343    pub fn reclaim_reserved_capacity(&mut self, stream: &mut store::Ptr, counts: &mut Counts) {
344        // only reclaim reserved capacity that isn't already buffered
345        if stream.send_flow.available().as_size() as usize > stream.buffered_send_data {
346            let reserved =
347                stream.send_flow.available().as_size() - stream.buffered_send_data as WindowSize;
348
349            // Panic safety: due to how `reserved` is computed it can't be greater
350            // than what's available.
351            stream
352                .send_flow
353                .claim_capacity(reserved)
354                .expect("window size should be greater than reserved");
355
356            self.assign_connection_capacity(reserved, stream, counts);
357        }
358    }
359
360    pub fn clear_pending_capacity(&mut self, store: &mut Store, counts: &mut Counts) {
361        let span = tracing::trace_span!("clear_pending_capacity");
362        let _e = span.enter();
363        while let Some(stream) = self.pending_capacity.pop(store) {
364            counts.transition(stream, |_, stream| {
365                tracing::trace!(?stream.id, "clear_pending_capacity");
366            })
367        }
368    }
369
370    pub fn assign_connection_capacity<R>(
371        &mut self,
372        inc: WindowSize,
373        store: &mut R,
374        counts: &mut Counts,
375    ) where
376        R: Resolve,
377    {
378        let span = tracing::trace_span!("assign_connection_capacity", inc);
379        let _e = span.enter();
380
381        // TODO: proper error handling
382        let _res = self.flow.assign_capacity(inc);
383        debug_assert!(_res.is_ok());
384
385        // Assign newly acquired capacity to streams pending capacity.
386        while self.flow.available() > 0 {
387            let stream = match self.pending_capacity.pop(store) {
388                Some(stream) => stream,
389                None => return,
390            };
391
392            // Streams pending capacity may have been reset before capacity
393            // became available. In that case, the stream won't want any
394            // capacity, and so we shouldn't "transition" on it, but just evict
395            // it and continue the loop.
396            if !(stream.state.is_send_streaming() || stream.buffered_send_data > 0) {
397                continue;
398            }
399
400            counts.transition(stream, |_, stream| {
401                // Try to assign capacity to the stream. This will also re-queue the
402                // stream if there isn't enough connection level capacity to fulfill
403                // the capacity request.
404                self.try_assign_capacity(stream);
405            })
406        }
407    }
408
409    /// Request capacity to send data
410    fn try_assign_capacity(&mut self, stream: &mut store::Ptr) {
411        // Streams over the max concurrent count should not have capacity assign to avoid starving the connection
412        // capacity for open streams
413        if stream.is_pending_open {
414            return;
415        }
416
417        let total_requested = stream.requested_send_capacity;
418
419        // Total requested should never go below actual assigned
420        // (Note: the window size can go lower than assigned)
421        debug_assert!(stream.send_flow.available() <= total_requested as usize);
422
423        // The amount of additional capacity that the stream requests.
424        // Don't assign more than the window has available!
425        let additional = cmp::min(
426            total_requested - stream.send_flow.available().as_size(),
427            // Can't assign more than what is available
428            stream.send_flow.window_size() - stream.send_flow.available().as_size(),
429        );
430        let span = tracing::trace_span!("try_assign_capacity", ?stream.id);
431        let _e = span.enter();
432        tracing::trace!(
433            requested = total_requested,
434            additional,
435            buffered = stream.buffered_send_data,
436            window = stream.send_flow.window_size(),
437            conn = %self.flow.available()
438        );
439
440        if additional == 0 {
441            // Nothing more to do
442            return;
443        }
444
445        // The stream may have been reset or closed since capacity was requested.
446        if !stream.state.is_send_streaming() && stream.buffered_send_data == 0 {
447            return;
448        }
449
450        // The amount of currently available capacity on the connection
451        let conn_available = self.flow.available().as_size();
452
453        // First check if capacity is immediately available
454        if conn_available > 0 {
455            // The amount of capacity to assign to the stream
456            // TODO: Should prioritization factor into this?
457            let assign = cmp::min(conn_available, additional);
458
459            tracing::trace!(capacity = assign, "assigning");
460
461            // Assign the capacity to the stream
462            stream.assign_capacity(assign, self.max_buffer_size);
463
464            // Claim the capacity from the connection
465            // TODO: proper error handling
466            let _res = self.flow.claim_capacity(assign);
467            debug_assert!(_res.is_ok());
468        }
469
470        tracing::trace!(
471            available = %stream.send_flow.available(),
472            requested = stream.requested_send_capacity,
473            buffered = stream.buffered_send_data,
474            has_unavailable = %stream.send_flow.has_unavailable()
475        );
476
477        if stream.send_flow.available() < stream.requested_send_capacity as usize
478            && stream.send_flow.has_unavailable()
479        {
480            // The stream requires additional capacity and the stream's
481            // window has available capacity, but the connection window
482            // does not.
483            //
484            // In this case, the stream needs to be queued up for when the
485            // connection has more capacity.
486            self.pending_capacity.push(stream);
487        }
488
489        // If data is buffered and the stream is send ready, then
490        // schedule the stream for execution
491        if stream.buffered_send_data > 0 && stream.is_send_ready() {
492            // TODO: This assertion isn't *exactly* correct. There can still be
493            // buffered send data while the stream's pending send queue is
494            // empty. This can happen when a large data frame is in the process
495            // of being **partially** sent. Once the window has been sent, the
496            // data frame will be returned to the prioritization layer to be
497            // re-scheduled.
498            //
499            // That said, it would be nice to figure out how to make this
500            // assertion correctly.
501            //
502            // debug_assert!(!stream.pending_send.is_empty());
503
504            self.pending_send.push(stream);
505        }
506    }
507
508    pub fn buffer_pending<T, B>(
509        &mut self,
510        buffer: &mut Buffer<Frame<B>>,
511        store: &mut Store,
512        counts: &mut Counts,
513        dst: &mut Codec<T, Prioritized<B>>,
514    ) -> io::Result<BufferStatus>
515    where
516        T: AsyncWrite + Unpin,
517        B: Buf,
518    {
519        // Reclaim any frame that has previously been written
520        self.reclaim_frame(buffer, store, dst);
521
522        // The max frame length
523        let max_frame_len = dst.max_send_frame_size();
524
525        tracing::trace!("buffer_pending");
526
527        loop {
528            if !dst.has_send_capacity() {
529                return Ok(BufferStatus::CodecFull);
530            }
531
532            if let Some(mut stream) = self.pop_pending_open(store, counts) {
533                self.pending_send.push_front(&mut stream);
534                self.try_assign_capacity(&mut stream);
535            }
536
537            match self.pop_frame(buffer, store, max_frame_len, counts) {
538                Some(frame) => {
539                    tracing::trace!(?frame, "writing");
540
541                    debug_assert_eq!(self.in_flight_data_frame, InFlightData::Nothing);
542                    if let Frame::Data(ref frame) = frame {
543                        self.in_flight_data_frame = InFlightData::DataFrame(frame.payload().stream);
544                    }
545                    dst.buffer(frame).expect("invalid frame");
546
547                    // Small DATA frames can be fully encoded by `buffer`,
548                    // which records completion in a single codec slot. Reclaim
549                    // before accepting another frame so that slot is not
550                    // overwritten.
551                    self.reclaim_frame(buffer, store, dst);
552                }
553                None => {
554                    return Ok(BufferStatus::Complete);
555                }
556            }
557        }
558    }
559
560    pub fn reclaim_written_frame<T, B>(
561        &mut self,
562        buffer: &mut Buffer<Frame<B>>,
563        store: &mut Store,
564        dst: &mut Codec<T, Prioritized<B>>,
565    ) -> bool
566    where
567        B: Buf,
568    {
569        self.reclaim_frame(buffer, store, dst)
570    }
571
572    /// Tries to reclaim a pending data frame from the codec.
573    ///
574    /// Returns true if a frame was reclaimed.
575    ///
576    /// When a data frame is written to the codec, it may not be written in its
577    /// entirety (large chunks are split up into potentially many data frames).
578    /// In this case, the stream needs to be reprioritized.
579    fn reclaim_frame<T, B>(
580        &mut self,
581        buffer: &mut Buffer<Frame<B>>,
582        store: &mut Store,
583        dst: &mut Codec<T, Prioritized<B>>,
584    ) -> bool
585    where
586        B: Buf,
587    {
588        let span = tracing::trace_span!("try_reclaim_frame");
589        let _e = span.enter();
590
591        // First check if there are any data chunks to take back
592        if let Some(frame) = dst.take_last_data_frame() {
593            self.reclaim_frame_inner(buffer, store, frame)
594        } else {
595            false
596        }
597    }
598
599    fn reclaim_frame_inner<B>(
600        &mut self,
601        buffer: &mut Buffer<Frame<B>>,
602        store: &mut Store,
603        frame: frame::Data<Prioritized<B>>,
604    ) -> bool
605    where
606        B: Buf,
607    {
608        tracing::trace!(
609            ?frame,
610            sz = frame.payload().inner.get_ref().remaining(),
611            "reclaimed"
612        );
613
614        let mut eos = false;
615        let key = frame.payload().stream;
616
617        match mem::replace(&mut self.in_flight_data_frame, InFlightData::Nothing) {
618            InFlightData::Nothing => panic!("wasn't expecting a frame to reclaim"),
619            InFlightData::Drop => {
620                tracing::trace!("not reclaiming frame for cancelled stream");
621                return false;
622            }
623            InFlightData::DataFrame(k) => {
624                debug_assert_eq!(k, key);
625            }
626        }
627
628        let mut frame = frame.map(|prioritized| {
629            // TODO: Ensure fully written
630            eos = prioritized.end_of_stream;
631            prioritized.inner.into_inner()
632        });
633
634        if frame.payload().has_remaining() {
635            let mut stream = store.resolve(key);
636
637            if eos {
638                frame.set_end_stream(true);
639            }
640
641            self.push_back_frame(frame.into(), buffer, &mut stream);
642
643            return true;
644        }
645
646        false
647    }
648
649    /// Push the frame to the front of the stream's deque, scheduling the
650    /// stream if needed.
651    fn push_back_frame<B>(
652        &mut self,
653        frame: Frame<B>,
654        buffer: &mut Buffer<Frame<B>>,
655        stream: &mut store::Ptr,
656    ) {
657        // Push the frame to the front of the stream's deque
658        stream.pending_send.push_front(buffer, frame);
659
660        // If needed, schedule the sender
661        if stream.send_flow.available() > 0 {
662            debug_assert!(!stream.pending_send.is_empty());
663            self.pending_send.push(stream);
664        }
665    }
666
667    pub fn clear_queue<B>(&mut self, buffer: &mut Buffer<Frame<B>>, stream: &mut store::Ptr) {
668        let span = tracing::trace_span!("clear_queue", ?stream.id);
669        let _e = span.enter();
670
671        // TODO: make this more efficient?
672        while let Some(frame) = stream.pending_send.pop_front(buffer) {
673            tracing::trace!(?frame, "dropping");
674        }
675
676        stream.buffered_send_data = 0;
677        stream.requested_send_capacity = 0;
678        if let InFlightData::DataFrame(key) = self.in_flight_data_frame {
679            if stream.key() == key {
680                // This stream could get cleaned up now - don't allow the buffered frame to get reclaimed.
681                self.in_flight_data_frame = InFlightData::Drop;
682            }
683        }
684    }
685
686    pub fn clear_pending_send(&mut self, store: &mut Store, counts: &mut Counts) {
687        while let Some(mut stream) = self.pending_send.pop(store) {
688            let is_pending_reset = stream.is_pending_reset_expiration();
689            if let Some(reason) = stream.state.get_scheduled_reset() {
690                stream.set_reset(reason, Initiator::Library);
691            }
692            counts.transition_after(stream, is_pending_reset);
693        }
694    }
695
696    pub fn clear_pending_open(&mut self, store: &mut Store, counts: &mut Counts) {
697        while let Some(stream) = self.pending_open.pop(store) {
698            let is_pending_reset = stream.is_pending_reset_expiration();
699            counts.transition_after(stream, is_pending_reset);
700        }
701    }
702
703    fn pop_frame<B>(
704        &mut self,
705        buffer: &mut Buffer<Frame<B>>,
706        store: &mut Store,
707        max_len: usize,
708        counts: &mut Counts,
709    ) -> Option<Frame<Prioritized<B>>>
710    where
711        B: Buf,
712    {
713        let span = tracing::trace_span!("pop_frame");
714        let _e = span.enter();
715
716        loop {
717            let mut stream = self.pending_send.pop(store)?;
718            let span = tracing::trace_span!("popped", ?stream.id, ?stream.state);
719            let _e = span.enter();
720
721            // It's possible that this stream, besides having data to send,
722            // is also queued to send a reset, and thus is already in the queue
723            // to wait for "some time" after a reset.
724            //
725            // To be safe, we just always ask the stream.
726            let is_pending_reset = stream.is_pending_reset_expiration();
727
728            tracing::trace!(is_pending_reset);
729
730            let frame = match stream.pending_send.pop_front(buffer) {
731                Some(Frame::Data(mut frame)) => {
732                    if let Some(reason) = stream.state.get_scheduled_reset() {
733                        // If a reset is scheduled due to cancellation or
734                        // an error, discard buffered DATA and let the `None`
735                        // arm emit the RST_STREAM on the next iteration.
736                        //
737                        // NO_ERROR is excluded. Per RFC 9113 §8.1, a NO_ERROR
738                        // stream reset may only be sent after a complete
739                        // response, which requires sending all queued DATA.
740                        if reason != Reason::NO_ERROR {
741                            stream.pending_send.push_front(buffer, frame.into());
742                            self.clear_queue(buffer, &mut stream);
743                            self.reclaim_all_capacity(&mut stream, counts);
744                            self.pending_send.push(&mut stream);
745                            continue;
746                        }
747                    }
748
749                    // Get the amount of capacity remaining for stream's
750                    // window.
751                    let stream_capacity = stream.send_flow.available();
752                    let sz = frame.payload().remaining();
753
754                    tracing::trace!(
755                        sz,
756                        eos = frame.is_end_stream(),
757                        window = %stream_capacity,
758                        available = %stream.send_flow.available(),
759                        requested = stream.requested_send_capacity,
760                        buffered = stream.buffered_send_data,
761                        "data frame"
762                    );
763
764                    // Zero length data frames always have capacity to
765                    // be sent.
766                    if sz > 0 && stream_capacity == 0 {
767                        tracing::trace!("stream capacity is 0");
768
769                        // Ensure that the stream is waiting for
770                        // connection level capacity
771                        //
772                        // TODO: uncomment
773                        // debug_assert!(stream.is_pending_send_capacity);
774
775                        // The stream has no more capacity, this can
776                        // happen if the remote reduced the stream
777                        // window. In this case, we need to buffer the
778                        // frame and wait for a window update...
779                        stream.pending_send.push_front(buffer, frame.into());
780
781                        continue;
782                    }
783
784                    // Only send up to the max frame length
785                    let len = cmp::min(sz, max_len);
786
787                    // Only send up to the stream's window capacity
788                    let len = cmp::min(len, stream_capacity.as_size() as usize) as WindowSize;
789
790                    // There *must* be be enough connection level
791                    // capacity at this point.
792                    debug_assert!(len <= self.flow.window_size());
793
794                    // Check if the stream level window the peer knows is available. In some
795                    // scenarios, maybe the window we know is available but the window which
796                    // peer knows is not.
797                    if len > 0 && len > stream.send_flow.window_size() {
798                        stream.pending_send.push_front(buffer, frame.into());
799                        continue;
800                    }
801
802                    tracing::trace!(len, "sending data frame");
803
804                    // Update the flow control
805                    tracing::trace_span!("updating stream flow").in_scope(|| {
806                        stream.send_data(len, self.max_buffer_size);
807
808                        // Assign the capacity back to the connection that
809                        // was just consumed from the stream in the previous
810                        // line.
811                        // TODO: proper error handling
812                        let _res = self.flow.assign_capacity(len);
813                        debug_assert!(_res.is_ok());
814                    });
815
816                    let (eos, len) =
817                        tracing::trace_span!("updating connection flow").in_scope(|| {
818                            // TODO: proper error handling
819                            let _res = self.flow.send_data(len);
820                            debug_assert!(_res.is_ok());
821
822                            // Wrap the frame's data payload to ensure that the
823                            // correct amount of data gets written.
824
825                            let eos = frame.is_end_stream();
826                            let len = len as usize;
827
828                            if frame.payload().remaining() > len {
829                                frame.set_end_stream(false);
830                            }
831                            (eos, len)
832                        });
833
834                    Frame::Data(frame.map(|buf| Prioritized {
835                        inner: buf.take(len),
836                        end_of_stream: eos,
837                        stream: stream.key(),
838                    }))
839                }
840                Some(Frame::PushPromise(pp)) => {
841                    let mut pushed = stream.store_mut().find_mut(&pp.promised_id()).unwrap();
842                    pushed.is_pending_push = false;
843                    // Transition stream from pending_push to pending_open
844                    // if possible
845                    if !pushed.pending_send.is_empty() {
846                        if counts.can_inc_num_send_streams() {
847                            counts.inc_num_send_streams(&mut pushed);
848                            self.pending_send.push(&mut pushed);
849                        } else {
850                            self.queue_open(&mut pushed);
851                        }
852                    }
853                    Frame::PushPromise(pp)
854                }
855                Some(frame) => frame.map(|_| {
856                    unreachable!(
857                        "Frame::map closure will only be called \
858                             on DATA frames."
859                    )
860                }),
861                None => {
862                    if let Some(reason) = stream.state.get_scheduled_reset() {
863                        stream.set_reset(reason, Initiator::Library);
864
865                        let frame = frame::Reset::new(stream.id, reason);
866                        Frame::Reset(frame)
867                    } else {
868                        // If the stream receives a RESET from the peer, it may have
869                        // had data buffered to be sent, but all the frames are cleared
870                        // in clear_queue(). Instead of doing O(N) traversal through queue
871                        // to remove, lets just ignore the stream here.
872                        tracing::trace!("removing dangling stream from pending_send");
873                        // Since this should only happen as a consequence of `clear_queue`,
874                        // we must be in a closed state of some kind.
875                        debug_assert!(stream.state.is_closed());
876                        counts.transition_after(stream, is_pending_reset);
877                        continue;
878                    }
879                }
880            };
881
882            tracing::trace!("pop_frame; frame={:?}", frame);
883
884            if cfg!(debug_assertions) && stream.state.is_idle() {
885                debug_assert!(stream.id > self.last_opened_id);
886                self.last_opened_id = stream.id;
887            }
888
889            if !stream.pending_send.is_empty() || stream.state.is_scheduled_reset() {
890                // TODO: Only requeue the sender IF it is ready to send
891                // the next frame. i.e. don't requeue it if the next
892                // frame is a data frame and the stream does not have
893                // any more capacity.
894                self.pending_send.push(&mut stream);
895            }
896
897            counts.transition_after(stream, is_pending_reset);
898
899            return Some(frame);
900        }
901    }
902
903    fn pop_pending_open<'s>(
904        &mut self,
905        store: &'s mut Store,
906        counts: &mut Counts,
907    ) -> Option<store::Ptr<'s>> {
908        tracing::trace!("schedule_pending_open");
909        // check for any pending open streams
910        if counts.can_inc_num_send_streams() {
911            if let Some(mut stream) = self.pending_open.pop(store) {
912                tracing::trace!("schedule_pending_open; stream={:?}", stream.id);
913
914                counts.inc_num_send_streams(&mut stream);
915                stream.notify_send();
916                return Some(stream);
917            }
918        }
919
920        None
921    }
922}
923
924// ===== impl Prioritized =====
925
926impl<B> Buf for Prioritized<B>
927where
928    B: Buf,
929{
930    fn remaining(&self) -> usize {
931        self.inner.remaining()
932    }
933
934    fn chunk(&self) -> &[u8] {
935        self.inner.chunk()
936    }
937
938    fn chunks_vectored<'a>(&'a self, dst: &mut [std::io::IoSlice<'a>]) -> usize {
939        self.inner.chunks_vectored(dst)
940    }
941
942    fn advance(&mut self, cnt: usize) {
943        self.inner.advance(cnt)
944    }
945}
946
947impl<B: Buf> fmt::Debug for Prioritized<B> {
948    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
949        fmt.debug_struct("Prioritized")
950            .field("remaining", &self.inner.get_ref().remaining())
951            .field("end_of_stream", &self.end_of_stream)
952            .field("stream", &self.stream)
953            .finish()
954    }
955}