blob: 0800a6ae4c82f92aeff71919d8ed64a9387dbd58 [file] [log] [blame]
// Copyright (c) 2012 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/quic/core/quic_multipath_sent_packet_manager.h"
#include <cstdint>
#include "base/strings/string_number_conversions.h"
#include "net/quic/core/quic_bug_tracker.h"
using std::string;
using std::max;
namespace net {
QuicMultipathSentPacketManager::QuicMultipathSentPacketManager(
QuicSentPacketManagerInterface* manager,
QuicConnectionCloseDelegateInterface* delegate)
: delegate_(delegate) {
path_managers_info_.push_back(PathSentPacketManagerInfo(manager, ACTIVE));
}
QuicMultipathSentPacketManager::~QuicMultipathSentPacketManager() {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
delete path_manager_info.manager;
}
}
void QuicMultipathSentPacketManager::SetFromConfig(const QuicConfig& config) {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr) {
path_manager_info.manager->SetFromConfig(config);
}
}
}
void QuicMultipathSentPacketManager::ResumeConnectionState(
const CachedNetworkParameters& cached_network_params,
bool max_bandwidth_resumption) {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
return;
}
path_manager->ResumeConnectionState(cached_network_params,
max_bandwidth_resumption);
}
void QuicMultipathSentPacketManager::SetNumOpenStreams(size_t num_streams) {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr) {
path_manager_info.manager->SetNumOpenStreams(num_streams);
}
}
}
void QuicMultipathSentPacketManager::SetMaxPacingRate(
QuicBandwidth max_pacing_rate) {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
return;
}
path_manager->SetMaxPacingRate(max_pacing_rate);
}
void QuicMultipathSentPacketManager::SetHandshakeConfirmed() {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
return;
}
path_manager->SetHandshakeConfirmed();
}
void QuicMultipathSentPacketManager::OnIncomingAck(
const QuicAckFrame& ack_frame,
QuicTime ack_receive_time) {
if (ack_frame.path_id >= path_managers_info_.size() ||
path_managers_info_[ack_frame.path_id].state != ACTIVE) {
return;
}
path_managers_info_[ack_frame.path_id].manager->OnIncomingAck(
ack_frame, ack_receive_time);
}
void QuicMultipathSentPacketManager::RetransmitUnackedPackets(
TransmissionType retransmission_type) {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
return;
}
path_manager->RetransmitUnackedPackets(retransmission_type);
}
bool QuicMultipathSentPacketManager::MaybeRetransmitTailLossProbe() {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr &&
path_manager_info.state == ACTIVE) {
if (path_manager_info.manager->MaybeRetransmitTailLossProbe()) {
return true;
}
}
}
return false;
}
void QuicMultipathSentPacketManager::NeuterUnencryptedPackets() {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
return;
}
path_manager->NeuterUnencryptedPackets();
}
bool QuicMultipathSentPacketManager::HasPendingRetransmissions() const {
// TODO(fayang): Move pending_retransmissions_ from path sent packet manager
// to multipath sent packet manager.
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
return path_manager != nullptr && path_manager->HasPendingRetransmissions();
}
PendingRetransmission
QuicMultipathSentPacketManager::NextPendingRetransmission() {
// TODO(fayang): Move pending_retransmissions_ from path sent packet manager
// to multipath sent packet manager.
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
OnUnrecoverablePathError(kDefaultPathId);
QuicFrames retransmittable_frames;
return PendingRetransmission(kInvalidPathId, 0u, NOT_RETRANSMISSION,
retransmittable_frames, false, 0,
ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER);
}
return path_manager->NextPendingRetransmission();
}
bool QuicMultipathSentPacketManager::HasUnackedPackets() const {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr &&
path_manager_info.state == ACTIVE &&
path_manager_info.manager->HasUnackedPackets()) {
return true;
}
}
return false;
}
QuicPacketNumber QuicMultipathSentPacketManager::GetLeastUnacked(
QuicPathId path_id) const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForPath(path_id);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetLeastUnacked(path_id);
}
bool QuicMultipathSentPacketManager::OnPacketSent(
SerializedPacket* serialized_packet,
QuicPathId original_path_id,
QuicPacketNumber original_packet_number,
QuicTime sent_time,
TransmissionType transmission_type,
HasRetransmittableData has_retransmittable_data) {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(serialized_packet->path_id);
// TODO(fayang): Handle packets retransmitted on different path.
DCHECK(original_packet_number == 0 ||
original_path_id == serialized_packet->path_id);
if (path_manager == nullptr) {
OnUnrecoverablePathError(serialized_packet->path_id);
return false;
}
return path_manager->OnPacketSent(
serialized_packet, original_path_id, original_packet_number, sent_time,
transmission_type, has_retransmittable_data);
}
void QuicMultipathSentPacketManager::OnRetransmissionTimeout() {
QuicPathId rto_path = DetermineRetransmissionTimeoutPath();
DCHECK_NE(kInvalidPathId, rto_path);
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(rto_path);
if (path_manager == nullptr) {
OnUnrecoverablePathError(rto_path);
return;
}
path_manager->OnRetransmissionTimeout();
}
QuicTime::Delta QuicMultipathSentPacketManager::TimeUntilSend(
QuicTime now,
QuicPathId* path_id) {
QuicTime::Delta delay = QuicTime::Delta::Infinite();
*path_id = kInvalidPathId;
for (size_t i = 0; i < path_managers_info_.size(); ++i) {
if (path_managers_info_[i].manager == nullptr ||
path_managers_info_[i].state != ACTIVE) {
continue;
}
QuicTime::Delta path_delay =
path_managers_info_[i].manager->TimeUntilSend(now, path_id);
if (!path_delay.IsInfinite() && path_delay < delay) {
delay = path_delay;
*path_id = i;
}
}
DCHECK(*path_id == kInvalidPathId || !delay.IsInfinite());
return delay;
}
const QuicTime QuicMultipathSentPacketManager::GetRetransmissionTime() const {
QuicTime retransmission_time = QuicTime::Zero();
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager == nullptr ||
path_manager_info.state != ACTIVE) {
continue;
}
QuicTime path_retransmission_time =
path_manager_info.manager->GetRetransmissionTime();
if (!path_retransmission_time.IsInitialized()) {
continue;
}
if (!retransmission_time.IsInitialized() ||
path_retransmission_time < retransmission_time) {
retransmission_time = path_retransmission_time;
}
}
return retransmission_time;
}
const RttStats* QuicMultipathSentPacketManager::GetRttStats() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return nullptr;
}
return path_manager->GetRttStats();
}
QuicBandwidth QuicMultipathSentPacketManager::BandwidthEstimate() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return QuicBandwidth::Zero();
}
return path_manager->BandwidthEstimate();
}
const QuicSustainedBandwidthRecorder*
QuicMultipathSentPacketManager::SustainedBandwidthRecorder() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return nullptr;
}
return path_manager->SustainedBandwidthRecorder();
}
QuicPacketCount QuicMultipathSentPacketManager::GetCongestionWindowInTcpMss()
const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetCongestionWindowInTcpMss();
}
QuicPacketCount QuicMultipathSentPacketManager::EstimateMaxPacketsInFlight(
QuicByteCount max_packet_length) const {
QuicPacketCount max_packets_in_flight = 0;
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr) {
max_packets_in_flight =
max(max_packets_in_flight,
path_manager_info.manager->EstimateMaxPacketsInFlight(
max_packet_length));
}
}
DCHECK_LT(0u, max_packets_in_flight);
return max_packets_in_flight;
}
QuicByteCount QuicMultipathSentPacketManager::GetCongestionWindowInBytes()
const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetCongestionWindowInBytes();
}
QuicPacketCount QuicMultipathSentPacketManager::GetSlowStartThresholdInTcpMss()
const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetSlowStartThresholdInTcpMss();
}
string QuicMultipathSentPacketManager::GetDebugState() const {
string debug_state_by_path;
for (size_t i = 0; i < path_managers_info_.size(); ++i) {
if (path_managers_info_[i].manager == nullptr ||
path_managers_info_[i].state != ACTIVE) {
continue;
}
const string& debug_state = path_managers_info_[i].manager->GetDebugState();
if (debug_state.empty()) {
continue;
}
debug_state_by_path =
debug_state_by_path + "[" + base::IntToString(i) + "]:" + debug_state;
}
return debug_state_by_path;
}
void QuicMultipathSentPacketManager::CancelRetransmissionsForStream(
QuicStreamId stream_id) {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager != nullptr) {
path_manager_info.manager->CancelRetransmissionsForStream(stream_id);
}
}
}
void QuicMultipathSentPacketManager::OnConnectionMigration(
QuicPathId path_id,
PeerAddressChangeType type) {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(path_id);
if (path_manager == nullptr) {
OnUnrecoverablePathError(path_id);
return;
}
path_manager->OnConnectionMigration(path_id, type);
}
bool QuicMultipathSentPacketManager::IsHandshakeConfirmed() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
return path_manager != nullptr && path_manager->IsHandshakeConfirmed();
}
void QuicMultipathSentPacketManager::SetDebugDelegate(
DebugDelegate* debug_delegate) {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager == nullptr) {
continue;
}
path_manager_info.manager->SetDebugDelegate(debug_delegate);
}
}
QuicPacketNumber QuicMultipathSentPacketManager::GetLargestObserved(
QuicPathId path_id) const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForPath(path_id);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetLargestObserved(path_id);
}
QuicPacketNumber QuicMultipathSentPacketManager::GetLargestSentPacket(
QuicPathId path_id) const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForPath(path_id);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetLargestSentPacket(path_id);
}
QuicPacketNumber QuicMultipathSentPacketManager::GetLeastPacketAwaitedByPeer(
QuicPathId path_id) const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForPath(path_id);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetLeastPacketAwaitedByPeer(path_id);
}
void QuicMultipathSentPacketManager::SetNetworkChangeVisitor(
NetworkChangeVisitor* visitor) {
for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
if (path_manager_info.manager == nullptr ||
path_manager_info.state != ACTIVE) {
continue;
}
path_manager_info.manager->SetNetworkChangeVisitor(visitor);
}
}
bool QuicMultipathSentPacketManager::InSlowStart() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
return path_manager != nullptr && path_manager->InSlowStart();
}
size_t QuicMultipathSentPacketManager::GetConsecutiveRtoCount() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetConsecutiveRtoCount();
}
size_t QuicMultipathSentPacketManager::GetConsecutiveTlpCount() const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
if (path_manager == nullptr) {
return 0;
}
return path_manager->GetConsecutiveTlpCount();
}
QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
PathSentPacketManagerInfo()
: manager(nullptr), state(CLOSING) {}
QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
PathSentPacketManagerInfo(QuicSentPacketManagerInterface* manager,
PathSentPacketManagerState state)
: manager(manager), state(state) {}
QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
PathSentPacketManagerInfo(const PathSentPacketManagerInfo& other) = default;
QuicSentPacketManagerInterface*
QuicMultipathSentPacketManager::MaybeGetSentPacketManagerForPath(
QuicPathId path_id) const {
if (path_id >= path_managers_info_.size() ||
path_managers_info_[path_id].manager == nullptr) {
QUIC_BUG << "Sent packet manager of path: (" + base::IntToString(path_id) +
") must exist but does not.";
return nullptr;
}
return path_managers_info_[path_id].manager;
}
QuicSentPacketManagerInterface*
QuicMultipathSentPacketManager::MaybeGetSentPacketManagerForActivePath(
QuicPathId path_id) const {
QuicSentPacketManagerInterface* path_manager =
MaybeGetSentPacketManagerForPath(path_id);
if (path_manager == nullptr) {
return nullptr;
}
if (path_managers_info_[path_id].state != ACTIVE) {
QUIC_BUG << "Sent packet manager of path: (" + base::IntToString(path_id) +
") must be active but is not.";
return nullptr;
}
return path_manager;
}
QuicPathId QuicMultipathSentPacketManager::DetermineRetransmissionTimeoutPath()
const {
QuicTime retransmission_time = QuicTime::Zero();
QuicPathId rto_path = kInvalidPathId;
for (size_t i = 0; i < path_managers_info_.size(); ++i) {
if (path_managers_info_[i].manager == nullptr ||
path_managers_info_[i].state != ACTIVE) {
continue;
}
QuicTime path_retransmission_time =
path_managers_info_[i].manager->GetRetransmissionTime();
if (!path_retransmission_time.IsInitialized()) {
continue;
}
if (!retransmission_time.IsInitialized() ||
path_retransmission_time < retransmission_time) {
retransmission_time = path_retransmission_time;
rto_path = i;
}
}
return rto_path;
}
void QuicMultipathSentPacketManager::OnUnrecoverablePathError(
QuicPathId path_id) {
if (MaybeGetSentPacketManagerForPath(path_id) == nullptr) {
const string error_details = "Sent packet manager of path: (" +
base::IntToString(path_id) +
") must exist but does not.";
delegate_->OnUnrecoverableError(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
error_details,
ConnectionCloseSource::FROM_SELF);
return;
}
const string error_details = "Sent packet manager of path: (" +
base::IntToString(path_id) +
") must be active but is not.";
delegate_->OnUnrecoverableError(QUIC_MULTIPATH_PATH_NOT_ACTIVE, error_details,
ConnectionCloseSource::FROM_SELF);
}
void QuicMultipathSentPacketManager::OnApplicationLimited() {
for (PathSentPacketManagerInfo& path_manager_info : path_managers_info_) {
if (path_manager_info.manager == nullptr ||
path_manager_info.state != ACTIVE) {
continue;
}
path_manager_info.manager->OnApplicationLimited();
}
}
} // namespace net