1 // Copyright 2016 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 #include "quiche/quic/test_tools/quic_stream_sequencer_buffer_peer.h"
6
7 #include <cstddef>
8
9 #include "quiche/quic/platform/api/quic_flags.h"
10 #include "quiche/quic/platform/api/quic_logging.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/test_tools/quic_test_utils.h"
13
14 using BufferBlock = quic::QuicStreamSequencerBuffer::BufferBlock;
15
16 static const size_t kBlockSizeBytes =
17 quic::QuicStreamSequencerBuffer::kBlockSizeBytes;
18
19 namespace quic {
20 namespace test {
21
QuicStreamSequencerBufferPeer(QuicStreamSequencerBuffer * buffer)22 QuicStreamSequencerBufferPeer::QuicStreamSequencerBufferPeer(
23 QuicStreamSequencerBuffer* buffer)
24 : buffer_(buffer) {}
25
26 // Read from this buffer_ into the given destination buffer_ up to the
27 // size of the destination. Returns the number of bytes read. Reading from
28 // an empty buffer_->returns 0.
Read(char * dest_buffer,size_t size)29 size_t QuicStreamSequencerBufferPeer::Read(char* dest_buffer, size_t size) {
30 iovec dest;
31 dest.iov_base = dest_buffer, dest.iov_len = size;
32 size_t bytes_read;
33 std::string error_details;
34 EXPECT_THAT(buffer_->Readv(&dest, 1, &bytes_read, &error_details),
35 IsQuicNoError());
36 return bytes_read;
37 }
38
39 // If buffer is empty, the blocks_ array must be empty, which means all
40 // blocks are deallocated.
CheckEmptyInvariants()41 bool QuicStreamSequencerBufferPeer::CheckEmptyInvariants() {
42 return !buffer_->Empty() || IsBlockArrayEmpty();
43 }
44
IsBlockArrayEmpty()45 bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() {
46 if (buffer_->blocks_ == nullptr) {
47 return true;
48 }
49
50 size_t count = current_blocks_count();
51 for (size_t i = 0; i < count; i++) {
52 if (buffer_->blocks_[i] != nullptr) {
53 return false;
54 }
55 }
56 return true;
57 }
58
CheckInitialState()59 bool QuicStreamSequencerBufferPeer::CheckInitialState() {
60 EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 &&
61 buffer_->num_bytes_buffered_ == 0);
62 return CheckBufferInvariants();
63 }
64
CheckBufferInvariants()65 bool QuicStreamSequencerBufferPeer::CheckBufferInvariants() {
66 QuicStreamOffset data_span =
67 buffer_->NextExpectedByte() - buffer_->total_bytes_read_;
68 bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ &&
69 data_span >= buffer_->num_bytes_buffered_;
70 if (!capacity_sane) {
71 QUIC_LOG(ERROR) << "data span is larger than capacity.";
72 QUIC_LOG(ERROR) << "total read: " << buffer_->total_bytes_read_
73 << " last byte: " << buffer_->NextExpectedByte();
74 }
75 bool total_read_sane =
76 buffer_->FirstMissingByte() >= buffer_->total_bytes_read_;
77 if (!total_read_sane) {
78 QUIC_LOG(ERROR) << "read across 1st gap.";
79 }
80 bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes;
81 if (!capacity_sane) {
82 QUIC_LOG(ERROR) << "read offset go beyond 1st block";
83 }
84 bool block_match_capacity =
85 (buffer_->max_buffer_capacity_bytes_ <=
86 buffer_->max_blocks_count_ * kBlockSizeBytes) &&
87 (buffer_->max_buffer_capacity_bytes_ >
88 (buffer_->max_blocks_count_ - 1) * kBlockSizeBytes);
89 if (!capacity_sane) {
90 QUIC_LOG(ERROR) << "block number not match capcaity.";
91 }
92 bool block_retired_when_empty = CheckEmptyInvariants();
93 if (!block_retired_when_empty) {
94 QUIC_LOG(ERROR) << "block is not retired after use.";
95 }
96 return capacity_sane && total_read_sane && read_offset_sane &&
97 block_match_capacity && block_retired_when_empty;
98 }
99
GetInBlockOffset(QuicStreamOffset offset)100 size_t QuicStreamSequencerBufferPeer::GetInBlockOffset(
101 QuicStreamOffset offset) {
102 return buffer_->GetInBlockOffset(offset);
103 }
104
GetBlock(size_t index)105 BufferBlock* QuicStreamSequencerBufferPeer::GetBlock(size_t index) {
106 return buffer_->blocks_[index];
107 }
108
IntervalSize()109 int QuicStreamSequencerBufferPeer::IntervalSize() {
110 if (buffer_->bytes_received_.Empty()) {
111 return 1;
112 }
113 int gap_size = buffer_->bytes_received_.Size() + 1;
114 if (buffer_->bytes_received_.Empty()) {
115 return gap_size;
116 }
117 if (buffer_->bytes_received_.begin()->min() == 0) {
118 --gap_size;
119 }
120 if (buffer_->bytes_received_.rbegin()->max() ==
121 std::numeric_limits<uint64_t>::max()) {
122 --gap_size;
123 }
124 return gap_size;
125 }
126
max_buffer_capacity()127 size_t QuicStreamSequencerBufferPeer::max_buffer_capacity() {
128 return buffer_->max_buffer_capacity_bytes_;
129 }
130
ReadableBytes()131 size_t QuicStreamSequencerBufferPeer::ReadableBytes() {
132 return buffer_->ReadableBytes();
133 }
134
set_total_bytes_read(QuicStreamOffset total_bytes_read)135 void QuicStreamSequencerBufferPeer::set_total_bytes_read(
136 QuicStreamOffset total_bytes_read) {
137 buffer_->total_bytes_read_ = total_bytes_read;
138 }
139
AddBytesReceived(QuicStreamOffset offset,QuicByteCount length)140 void QuicStreamSequencerBufferPeer::AddBytesReceived(QuicStreamOffset offset,
141 QuicByteCount length) {
142 buffer_->bytes_received_.Add(offset, offset + length);
143 }
144
IsBufferAllocated()145 bool QuicStreamSequencerBufferPeer::IsBufferAllocated() {
146 return buffer_->blocks_ != nullptr;
147 }
148
max_blocks_count()149 size_t QuicStreamSequencerBufferPeer::max_blocks_count() {
150 return buffer_->max_blocks_count_;
151 }
152
current_blocks_count()153 size_t QuicStreamSequencerBufferPeer::current_blocks_count() {
154 return buffer_->current_blocks_count_;
155 }
156
157 const QuicIntervalSet<QuicStreamOffset>&
bytes_received()158 QuicStreamSequencerBufferPeer::bytes_received() {
159 return buffer_->bytes_received_;
160 }
161
162 } // namespace test
163 } // namespace quic
164