| // Copyright 2016 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| typedef quic::QuicStreamSequencerBuffer::BufferBlock BufferBlock; | |
| static const size_t kBlockSizeBytes = | |
| quic::QuicStreamSequencerBuffer::kBlockSizeBytes; | |
| namespace quic { | |
| namespace test { | |
| QuicStreamSequencerBufferPeer::QuicStreamSequencerBufferPeer( | |
| QuicStreamSequencerBuffer* buffer) | |
| : buffer_(buffer) {} | |
| // Read from this buffer_ into the given destination buffer_ up to the | |
| // size of the destination. Returns the number of bytes read. Reading from | |
| // an empty buffer_->returns 0. | |
| size_t QuicStreamSequencerBufferPeer::Read(char* dest_buffer, size_t size) { | |
| iovec dest; | |
| dest.iov_base = dest_buffer, dest.iov_len = size; | |
| size_t bytes_read; | |
| std::string error_details; | |
| EXPECT_EQ(QUIC_NO_ERROR, | |
| buffer_->Readv(&dest, 1, &bytes_read, &error_details)); | |
| return bytes_read; | |
| } | |
| // If buffer is empty, the blocks_ array must be empty, which means all | |
| // blocks are deallocated. | |
| bool QuicStreamSequencerBufferPeer::CheckEmptyInvariants() { | |
| return !buffer_->Empty() || IsBlockArrayEmpty(); | |
| } | |
| bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() { | |
| if (buffer_->blocks_ == nullptr) { | |
| return true; | |
| } | |
| size_t count = buffer_->blocks_count_; | |
| for (size_t i = 0; i < count; i++) { | |
| if (buffer_->blocks_[i] != nullptr) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool QuicStreamSequencerBufferPeer::CheckInitialState() { | |
| EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 && | |
| buffer_->num_bytes_buffered_ == 0); | |
| return CheckBufferInvariants(); | |
| } | |
| bool QuicStreamSequencerBufferPeer::CheckBufferInvariants() { | |
| QuicStreamOffset data_span = | |
| buffer_->NextExpectedByte() - buffer_->total_bytes_read_; | |
| bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ && | |
| data_span >= buffer_->num_bytes_buffered_; | |
| if (!capacity_sane) { | |
| QUIC_LOG(ERROR) << "data span is larger than capacity."; | |
| QUIC_LOG(ERROR) << "total read: " << buffer_->total_bytes_read_ | |
| << " last byte: " << buffer_->NextExpectedByte(); | |
| } | |
| bool total_read_sane = | |
| buffer_->FirstMissingByte() >= buffer_->total_bytes_read_; | |
| if (!total_read_sane) { | |
| QUIC_LOG(ERROR) << "read across 1st gap."; | |
| } | |
| bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes; | |
| if (!capacity_sane) { | |
| QUIC_LOG(ERROR) << "read offset go beyond 1st block"; | |
| } | |
| bool block_match_capacity = (buffer_->max_buffer_capacity_bytes_ <= | |
| buffer_->blocks_count_ * kBlockSizeBytes) && | |
| (buffer_->max_buffer_capacity_bytes_ > | |
| (buffer_->blocks_count_ - 1) * kBlockSizeBytes); | |
| if (!capacity_sane) { | |
| QUIC_LOG(ERROR) << "block number not match capcaity."; | |
| } | |
| bool block_retired_when_empty = CheckEmptyInvariants(); | |
| if (!block_retired_when_empty) { | |
| QUIC_LOG(ERROR) << "block is not retired after use."; | |
| } | |
| return capacity_sane && total_read_sane && read_offset_sane && | |
| block_match_capacity && block_retired_when_empty; | |
| } | |
| size_t QuicStreamSequencerBufferPeer::GetInBlockOffset( | |
| QuicStreamOffset offset) { | |
| return buffer_->GetInBlockOffset(offset); | |
| } | |
| BufferBlock* QuicStreamSequencerBufferPeer::GetBlock(size_t index) { | |
| return buffer_->blocks_[index]; | |
| } | |
| int QuicStreamSequencerBufferPeer::IntervalSize() { | |
| if (buffer_->bytes_received_.Empty()) { | |
| return 1; | |
| } | |
| int gap_size = buffer_->bytes_received_.Size() + 1; | |
| if (buffer_->bytes_received_.Empty()) { | |
| return gap_size; | |
| } | |
| if (buffer_->bytes_received_.begin()->min() == 0) { | |
| --gap_size; | |
| } | |
| if (buffer_->bytes_received_.rbegin()->max() == | |
| std::numeric_limits<uint64_t>::max()) { | |
| --gap_size; | |
| } | |
| return gap_size; | |
| } | |
| size_t QuicStreamSequencerBufferPeer::max_buffer_capacity() { | |
| return buffer_->max_buffer_capacity_bytes_; | |
| } | |
| size_t QuicStreamSequencerBufferPeer::ReadableBytes() { | |
| return buffer_->ReadableBytes(); | |
| } | |
| void QuicStreamSequencerBufferPeer::set_total_bytes_read( | |
| QuicStreamOffset total_bytes_read) { | |
| buffer_->total_bytes_read_ = total_bytes_read; | |
| } | |
| void QuicStreamSequencerBufferPeer::AddBytesReceived(QuicStreamOffset offset, | |
| QuicByteCount length) { | |
| buffer_->bytes_received_.Add(offset, offset + length); | |
| } | |
| bool QuicStreamSequencerBufferPeer::IsBufferAllocated() { | |
| return buffer_->blocks_ != nullptr; | |
| } | |
| size_t QuicStreamSequencerBufferPeer::block_count() { | |
| return buffer_->blocks_count_; | |
| } | |
| const QuicIntervalSet<QuicStreamOffset>& | |
| QuicStreamSequencerBufferPeer::bytes_received() { | |
| return buffer_->bytes_received_; | |
| } | |
| } // namespace test | |
| } // namespace quic |