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 |