blob: c109325ecf18e4813622996fe146ede75d2ac197 [file] [log] [blame]
// Copyright (c) 2017 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_data_source.h"
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
namespace quic {
namespace test {
namespace {
class SendAlarmDelegate : public QuicAlarm::Delegate {
public:
explicit SendAlarmDelegate(QuartcDataSource* source) : source_(source) {}
void OnAlarm() override { source_->OnSendAlarm(); }
private:
QuartcDataSource* source_;
};
} // namespace
bool ParsedQuartcDataFrame::Parse(QuicStringPiece data,
ParsedQuartcDataFrame* out) {
QuicDataReader reader(data.data(), data.size());
uint32_t source_id;
if (!reader.ReadUInt32(&source_id)) {
return false;
}
uint64_t sequence_number;
if (!reader.ReadUInt64(&sequence_number)) {
return false;
}
uint64_t time_bits;
if (!reader.ReadUInt64(&time_bits)) {
return false;
}
QuicStringPiece payload = reader.ReadRemainingPayload();
out->source_id = source_id;
out->sequence_number = sequence_number;
out->send_time =
QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(time_bits);
out->size = data.size();
out->payload = std::string(payload.data(), payload.size());
return true;
}
QuartcDataSource::QuartcDataSource(const QuicClock* clock,
QuicAlarmFactory* alarm_factory,
QuicRandom* random,
const Config& config,
Delegate* delegate)
: clock_(clock),
alarm_factory_(alarm_factory),
random_(random),
config_(config),
delegate_(delegate),
send_alarm_(alarm_factory_->CreateAlarm(new SendAlarmDelegate(this))),
sequence_number_(0),
allocated_bandwidth_(config_.min_bandwidth),
last_send_time_(QuicTime::Zero()) {}
void QuartcDataSource::OnSendAlarm() {
QuicTime now = clock_->Now();
QuicTime::Delta time_since_last_send(QuicTime::Delta::Zero());
if (last_send_time_.IsInitialized()) {
// If previous frames have been sent, use the actual time since the last
// send to compute the frame size.
time_since_last_send = now - last_send_time_;
} else {
// For the first frame, use the configured frame interval.
time_since_last_send = config_.frame_interval;
}
QuicByteCount bytes =
allocated_bandwidth_.ToBytesPerPeriod(time_since_last_send);
while (config_.max_frame_size > 0 && bytes > config_.max_frame_size) {
GenerateFrame(config_.max_frame_size, now);
bytes -= config_.max_frame_size;
}
GenerateFrame(bytes, now);
// Reset alarm.
last_send_time_ = now;
send_alarm_->Set(now + config_.frame_interval);
}
QuicBandwidth QuartcDataSource::AllocateBandwidth(QuicBandwidth bandwidth) {
allocated_bandwidth_ = std::max(config_.min_bandwidth,
std::min(bandwidth, config_.max_bandwidth));
return std::max(bandwidth - allocated_bandwidth_, QuicBandwidth::Zero());
}
bool QuartcDataSource::Enabled() const {
return send_alarm_->IsSet();
}
void QuartcDataSource::SetEnabled(bool value) {
if (Enabled() == value) {
return;
}
if (!value) {
send_alarm_->Cancel();
// Reset the last send time. When re-enabled, the data source should
// produce a frame of approximately the right size for its current
// bandwidth allocation and frame interval, not a huge frame accounting for
// all the time since it was disabled.
last_send_time_ = QuicTime::Zero();
return;
}
send_alarm_->Set(clock_->Now());
}
void QuartcDataSource::GenerateFrame(QuicByteCount frame_size, QuicTime now) {
frame_size = std::max(frame_size, kDataFrameHeaderSize);
if (buffer_.size() < frame_size) {
buffer_.resize(frame_size);
}
// Generate data.
QuicDataWriter writer(frame_size, buffer_.data());
writer.WriteUInt32(config_.id);
writer.WriteUInt64(sequence_number_++);
writer.WriteUInt64((now - QuicTime::Zero()).ToMicroseconds());
writer.WriteRandomBytes(random_, writer.remaining());
delegate_->OnDataProduced(writer.data(), writer.length());
}
} // namespace test
} // namespace quic