1 // Copyright (c) 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_ 6 #define QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_ 7 8 #include <cstdint> 9 #include <map> 10 #include <set> 11 12 #include "absl/container/flat_hash_map.h" 13 #include "quiche/quic/core/quic_types.h" 14 #include "quiche/quic/platform/api/quic_export.h" 15 16 namespace quic { 17 18 namespace test { 19 20 class QpackBlockingManagerPeer; 21 22 } // namespace test 23 24 // Class to keep track of blocked streams and blocking dynamic table entries: 25 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-decoding 26 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-insertion 27 class QUICHE_EXPORT QpackBlockingManager { 28 public: 29 using IndexSet = std::multiset<uint64_t>; 30 31 QpackBlockingManager(); 32 33 // Called when a Header Acknowledgement instruction is received on the decoder 34 // stream. Returns false if there are no outstanding header blocks to be 35 // acknowledged on |stream_id|. 36 bool OnHeaderAcknowledgement(QuicStreamId stream_id); 37 38 // Called when a Stream Cancellation instruction is received on the decoder 39 // stream. 40 void OnStreamCancellation(QuicStreamId stream_id); 41 42 // Called when an Insert Count Increment instruction is received on the 43 // decoder stream. Returns true if Known Received Count is successfully 44 // updated. Returns false on overflow. 45 bool OnInsertCountIncrement(uint64_t increment); 46 47 // Called when sending a header block containing references to dynamic table 48 // entries with |indices|. |indices| must not be empty. 49 void OnHeaderBlockSent(QuicStreamId stream_id, IndexSet indices); 50 51 // Returns true if sending blocking references on stream |stream_id| would not 52 // increase the total number of blocked streams above 53 // |maximum_blocked_streams|. Note that if |stream_id| is already blocked 54 // then it is always allowed to send more blocking references on it. 55 // Behavior is undefined if |maximum_blocked_streams| is smaller than number 56 // of currently blocked streams. 57 bool blocking_allowed_on_stream(QuicStreamId stream_id, 58 uint64_t maximum_blocked_streams) const; 59 60 // Returns the index of the blocking entry with the smallest index, 61 // or std::numeric_limits<uint64_t>::max() if there are no blocking entries. 62 uint64_t smallest_blocking_index() const; 63 64 // Returns the Known Received Count as defined at 65 // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#known-received-count. known_received_count()66 uint64_t known_received_count() const { return known_received_count_; } 67 68 // Required Insert Count for set of indices. 69 static uint64_t RequiredInsertCount(const IndexSet& indices); 70 71 private: 72 friend test::QpackBlockingManagerPeer; 73 74 // A stream typically has only one header block, except for the rare cases of 75 // 1xx responses and trailers. Even if there are multiple header blocks sent 76 // on a single stream, they might not be blocked at the same time. Use 77 // std::list instead of quiche::QuicheCircularDeque because it has lower 78 // memory footprint when holding few elements. 79 using HeaderBlocksForStream = std::list<IndexSet>; 80 using HeaderBlocks = absl::flat_hash_map<QuicStreamId, HeaderBlocksForStream>; 81 82 // Increase or decrease the reference count for each index in |indices|. 83 void IncreaseReferenceCounts(const IndexSet& indices); 84 void DecreaseReferenceCounts(const IndexSet& indices); 85 86 // Multiset of indices in each header block for each stream. 87 // Must not contain a stream id with an empty queue. 88 HeaderBlocks header_blocks_; 89 90 // Number of references in |header_blocks_| for each entry index. 91 std::map<uint64_t, uint64_t> entry_reference_counts_; 92 93 uint64_t known_received_count_; 94 }; 95 96 } // namespace quic 97 98 #endif // QUICHE_QUIC_CORE_QPACK_QPACK_BLOCKING_MANAGER_H_ 99