|  | // 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 "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) {} | 
|  |  | 
|  | 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(QuicMakeUnique<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); | 
|  | 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 |