Chromium Code Reviews| Index: net/quic/quic_multipath_sent_packet_manager.cc |
| diff --git a/net/quic/quic_multipath_sent_packet_manager.cc b/net/quic/quic_multipath_sent_packet_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0e5e296d80592abdb99831846a50de1972ee35e6 |
| --- /dev/null |
| +++ b/net/quic/quic_multipath_sent_packet_manager.cc |
| @@ -0,0 +1,520 @@ |
| +#include "net/quic/quic_multipath_sent_packet_manager.h" |
|
Zhongyi Shi
2016/07/25 22:30:34
ditto
|
| + |
| +#include <cstdint> |
| + |
| +#include "base/strings/string_number_conversions.h" |
| +#include "net/quic/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); |
| +} |
| + |
| +bool QuicMultipathSentPacketManager::IsUnacked( |
| + QuicPathId path_id, |
| + QuicPacketNumber packet_number) const { |
| + QuicSentPacketManagerInterface* path_manager = |
| + MaybeGetSentPacketManagerForPath(path_id); |
| + return path_manager != nullptr && |
| + path_manager->IsUnacked(path_id, packet_number); |
| +} |
| + |
| +bool QuicMultipathSentPacketManager::HasRetransmittableFrames( |
| + QuicPathId path_id, |
| + QuicPacketNumber packet_number) const { |
| + QuicSentPacketManagerInterface* path_manager = |
| + MaybeGetSentPacketManagerForPath(path_id); |
| + return path_manager != nullptr && |
| + path_manager->HasRetransmittableFrames(path_id, packet_number); |
| +} |
| + |
| +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, |
| + HasRetransmittableData retransmittable, |
| + 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, retransmittable, 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(); |
| +} |
| + |
| +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); |
| +} |
| + |
| +} // namespace net |