blob: 885e6b13062e3a7dbfdc5125d83103c82e75c565 [file] [log] [blame]
// Copyright (c) 2019 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/quartc/test/quartc_peer.h"
#include <utility>
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
namespace quic {
namespace test {
QuartcPeer::QuartcPeer(const QuicClock* clock,
QuicAlarmFactory* alarm_factory,
QuicRandom* random,
QuicBufferAllocator* buffer_allocator,
const std::vector<QuartcDataSource::Config>& configs)
: clock_(clock),
alarm_factory_(alarm_factory),
random_(random),
buffer_allocator_(buffer_allocator),
enabled_(false),
session_(nullptr),
configs_(configs),
last_available_(QuicBandwidth::Zero()) {}
QuartcPeer::~QuartcPeer() {
session_->CloseConnection("~QuartcPeer()");
}
void QuartcPeer::SetEnabled(bool value) {
enabled_ = value;
for (auto& source : data_sources_) {
source->SetEnabled(enabled_);
}
}
IdToSequenceNumberMap QuartcPeer::GetLastSequenceNumbers() const {
DCHECK_GE(configs_.size(), data_sources_.size());
IdToSequenceNumberMap out;
for (size_t i = 0; i < data_sources_.size(); ++i) {
out[configs_[i].id] = data_sources_[i]->sequence_number();
}
return out;
}
void QuartcPeer::OnSessionCreated(QuartcSession* session) {
session_ = session;
session_->StartCryptoHandshake();
QuicByteCount largest_message_payload =
session_->GetGuaranteedLargestMessagePayload();
for (auto& config : configs_) {
// Clamp maximum frame sizes to the largest supported by the session before
// creating data sources.
config.max_frame_size =
config.max_frame_size > 0
? std::min(config.max_frame_size, largest_message_payload)
: largest_message_payload;
QUIC_LOG(INFO) << "Set max frame size for source " << config.id << " to "
<< config.max_frame_size;
data_sources_.push_back(std::make_unique<QuartcDataSource>(
clock_, alarm_factory_, random_, config, this));
}
}
void QuartcPeer::OnCryptoHandshakeComplete() {
SetEnabled(true);
}
void QuartcPeer::OnConnectionWritable() {
SetEnabled(true);
}
void QuartcPeer::OnIncomingStream(QuartcStream* stream) {
QUIC_LOG(DFATAL) << "Unexpected incoming stream, id=" << stream->id();
}
void QuartcPeer::OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
QuicBandwidth pacing_rate,
QuicTime::Delta /*latest_rtt*/) {
// Note: this is fairly crude rate adaptation and makes no effort to account
// for overhead. The congestion controller is assumed to account for this.
// It may do so by detecting overuse and pushing back on its bandwidth
// estimate, or it may explicitly subtract overhead before surfacing its
// estimate.
QuicBandwidth available = std::min(bandwidth_estimate, pacing_rate);
last_available_ = available;
for (auto& source : data_sources_) {
available = source->AllocateBandwidth(available);
}
}
void QuartcPeer::OnConnectionClosed(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource /*source*/) {
QUIC_LOG(INFO) << "Connection closed, frame=" << frame;
SetEnabled(false);
}
void QuartcPeer::OnMessageReceived(QuicStringPiece message) {
ReceivedMessage received;
received.receive_time = clock_->Now();
if (!ParsedQuartcDataFrame::Parse(message, &received.frame)) {
QUIC_LOG(DFATAL) << "Failed to parse incoming message as test data frame: ["
<< message << "]";
}
received_messages_.push_back(received);
}
void QuartcPeer::OnDataProduced(const char* data, size_t length) {
// Further packetization is not required, as sources are configured to produce
// frames that fit within message payloads.
DCHECK_LE(length, session_->GetCurrentLargestMessagePayload());
struct iovec iov = {const_cast<char*>(data), length};
QuicMemSliceStorage storage(&iov, 1, buffer_allocator_, length);
session_->SendOrQueueMessage(storage.ToSpan(), /*datagram_id=*/0);
}
} // namespace test
} // namespace quic