| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/core/quic_sent_packet_manager.h" | 5 #include "net/quic/core/quic_sent_packet_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 const size_t kMinTimeoutsBeforePathDegrading = 2; | 35 const size_t kMinTimeoutsBeforePathDegrading = 2; |
| 36 | 36 |
| 37 // Ensure the handshake timer isnt't faster than 10ms. | 37 // Ensure the handshake timer isnt't faster than 10ms. |
| 38 // This limits the tenth retransmitted packet to 10s after the initial CHLO. | 38 // This limits the tenth retransmitted packet to 10s after the initial CHLO. |
| 39 static const int64_t kMinHandshakeTimeoutMs = 10; | 39 static const int64_t kMinHandshakeTimeoutMs = 10; |
| 40 | 40 |
| 41 // Sends up to two tail loss probes before firing an RTO, | 41 // Sends up to two tail loss probes before firing an RTO, |
| 42 // per draft RFC draft-dukkipati-tcpm-tcp-loss-probe. | 42 // per draft RFC draft-dukkipati-tcpm-tcp-loss-probe. |
| 43 static const size_t kDefaultMaxTailLossProbes = 2; | 43 static const size_t kDefaultMaxTailLossProbes = 2; |
| 44 | 44 |
| 45 // Number of unpaced packets to send after quiescence. | |
| 46 static const size_t kInitialUnpacedBurst = 10; | |
| 47 | |
| 48 bool HasCryptoHandshake(const TransmissionInfo& transmission_info) { | 45 bool HasCryptoHandshake(const TransmissionInfo& transmission_info) { |
| 49 DCHECK(!transmission_info.has_crypto_handshake || | 46 DCHECK(!transmission_info.has_crypto_handshake || |
| 50 !transmission_info.retransmittable_frames.empty()); | 47 !transmission_info.retransmittable_frames.empty()); |
| 51 return transmission_info.has_crypto_handshake; | 48 return transmission_info.has_crypto_handshake; |
| 52 } | 49 } |
| 53 | 50 |
| 54 } // namespace | 51 } // namespace |
| 55 | 52 |
| 56 #define ENDPOINT \ | 53 #define ENDPOINT \ |
| 57 (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") | 54 (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") |
| 58 | 55 |
| 59 QuicSentPacketManager::QuicSentPacketManager( | 56 QuicSentPacketManager::QuicSentPacketManager( |
| 60 Perspective perspective, | 57 Perspective perspective, |
| 61 QuicPathId path_id, | 58 QuicPathId path_id, |
| 62 const QuicClock* clock, | 59 const QuicClock* clock, |
| 63 QuicConnectionStats* stats, | 60 QuicConnectionStats* stats, |
| 64 CongestionControlType congestion_control_type, | 61 CongestionControlType congestion_control_type, |
| 65 LossDetectionType loss_type, | 62 LossDetectionType loss_type, |
| 66 MultipathDelegateInterface* delegate) | 63 MultipathDelegateInterface* delegate) |
| 67 : unacked_packets_(), | 64 : unacked_packets_(), |
| 68 perspective_(perspective), | 65 perspective_(perspective), |
| 69 path_id_(path_id), | 66 path_id_(path_id), |
| 70 clock_(clock), | 67 clock_(clock), |
| 71 stats_(stats), | 68 stats_(stats), |
| 72 delegate_(delegate), | 69 delegate_(delegate), |
| 73 debug_delegate_(nullptr), | 70 debug_delegate_(nullptr), |
| 74 network_change_visitor_(nullptr), | 71 network_change_visitor_(nullptr), |
| 75 initial_congestion_window_(kInitialCongestionWindow), | 72 initial_congestion_window_(kInitialCongestionWindow), |
| 76 send_algorithm_( | |
| 77 SendAlgorithmInterface::Create(clock, | |
| 78 &rtt_stats_, | |
| 79 congestion_control_type, | |
| 80 stats, | |
| 81 initial_congestion_window_)), | |
| 82 loss_algorithm_(&general_loss_algorithm_), | 73 loss_algorithm_(&general_loss_algorithm_), |
| 83 general_loss_algorithm_(loss_type), | 74 general_loss_algorithm_(loss_type), |
| 84 n_connection_simulation_(false), | 75 n_connection_simulation_(false), |
| 85 receive_buffer_bytes_(kDefaultSocketReceiveBuffer), | 76 receive_buffer_bytes_(kDefaultSocketReceiveBuffer), |
| 86 least_packet_awaited_by_peer_(1), | 77 least_packet_awaited_by_peer_(1), |
| 87 first_rto_transmission_(0), | 78 first_rto_transmission_(0), |
| 88 consecutive_rto_count_(0), | 79 consecutive_rto_count_(0), |
| 89 consecutive_tlp_count_(0), | 80 consecutive_tlp_count_(0), |
| 90 consecutive_crypto_retransmission_count_(0), | 81 consecutive_crypto_retransmission_count_(0), |
| 91 pending_timer_transmission_count_(0), | 82 pending_timer_transmission_count_(0), |
| 92 max_tail_loss_probes_(kDefaultMaxTailLossProbes), | 83 max_tail_loss_probes_(kDefaultMaxTailLossProbes), |
| 93 enable_half_rtt_tail_loss_probe_(false), | 84 enable_half_rtt_tail_loss_probe_(false), |
| 94 using_pacing_(false), | 85 using_pacing_(false), |
| 95 use_new_rto_(false), | 86 use_new_rto_(false), |
| 96 undo_pending_retransmits_(false), | 87 undo_pending_retransmits_(false), |
| 97 largest_newly_acked_(0), | 88 largest_newly_acked_(0), |
| 98 largest_mtu_acked_(0), | 89 largest_mtu_acked_(0), |
| 99 handshake_confirmed_(false) {} | 90 handshake_confirmed_(false) { |
| 91 SetSendAlgorithm(congestion_control_type); |
| 92 } |
| 100 | 93 |
| 101 QuicSentPacketManager::~QuicSentPacketManager() {} | 94 QuicSentPacketManager::~QuicSentPacketManager() {} |
| 102 | 95 |
| 103 void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { | 96 void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { |
| 104 if (config.HasReceivedInitialRoundTripTimeUs() && | 97 if (config.HasReceivedInitialRoundTripTimeUs() && |
| 105 config.ReceivedInitialRoundTripTimeUs() > 0) { | 98 config.ReceivedInitialRoundTripTimeUs() > 0) { |
| 106 rtt_stats_.set_initial_rtt_us( | 99 rtt_stats_.set_initial_rtt_us( |
| 107 max(kMinInitialRoundTripTimeUs, | 100 max(kMinInitialRoundTripTimeUs, |
| 108 min(kMaxInitialRoundTripTimeUs, | 101 min(kMaxInitialRoundTripTimeUs, |
| 109 config.ReceivedInitialRoundTripTimeUs()))); | 102 config.ReceivedInitialRoundTripTimeUs()))); |
| 110 } else if (config.HasInitialRoundTripTimeUsToSend() && | 103 } else if (config.HasInitialRoundTripTimeUsToSend() && |
| 111 config.GetInitialRoundTripTimeUsToSend() > 0) { | 104 config.GetInitialRoundTripTimeUsToSend() > 0) { |
| 112 rtt_stats_.set_initial_rtt_us( | 105 rtt_stats_.set_initial_rtt_us( |
| 113 max(kMinInitialRoundTripTimeUs, | 106 max(kMinInitialRoundTripTimeUs, |
| 114 min(kMaxInitialRoundTripTimeUs, | 107 min(kMaxInitialRoundTripTimeUs, |
| 115 config.GetInitialRoundTripTimeUsToSend()))); | 108 config.GetInitialRoundTripTimeUsToSend()))); |
| 116 } | 109 } |
| 117 // TODO(ianswett): BBR is currently a server only feature. | 110 // TODO(ianswett): BBR is currently a server only feature. |
| 118 if (FLAGS_quic_allow_bbr && config.HasReceivedConnectionOptions() && | 111 if (FLAGS_quic_allow_bbr && config.HasReceivedConnectionOptions() && |
| 119 ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) { | 112 ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) { |
| 120 send_algorithm_.reset(SendAlgorithmInterface::Create( | 113 SetSendAlgorithm(kBBR); |
| 121 clock_, &rtt_stats_, kBBR, stats_, initial_congestion_window_)); | |
| 122 } | 114 } |
| 123 if (config.HasReceivedConnectionOptions() && | 115 if (config.HasReceivedConnectionOptions() && |
| 124 ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) { | 116 ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) { |
| 125 if (ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { | 117 if (ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { |
| 126 send_algorithm_.reset(SendAlgorithmInterface::Create( | 118 SetSendAlgorithm(kRenoBytes); |
| 127 clock_, &rtt_stats_, kRenoBytes, stats_, initial_congestion_window_)); | |
| 128 } else { | 119 } else { |
| 129 send_algorithm_.reset(SendAlgorithmInterface::Create( | 120 SetSendAlgorithm(kReno); |
| 130 clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_)); | |
| 131 } | 121 } |
| 132 } else if (config.HasReceivedConnectionOptions() && | 122 } else if (config.HasReceivedConnectionOptions() && |
| 133 ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { | 123 ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { |
| 134 send_algorithm_.reset(SendAlgorithmInterface::Create( | 124 SetSendAlgorithm(kCubicBytes); |
| 135 clock_, &rtt_stats_, kCubicBytes, stats_, initial_congestion_window_)); | |
| 136 } | 125 } |
| 137 if (!FLAGS_quic_disable_pacing_for_perf_tests) { | 126 using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests; |
| 138 EnablePacing(); | |
| 139 } | |
| 140 | 127 |
| 141 if (config.HasClientSentConnectionOption(k1CON, perspective_)) { | 128 if (config.HasClientSentConnectionOption(k1CON, perspective_)) { |
| 142 send_algorithm_->SetNumEmulatedConnections(1); | 129 send_algorithm_->SetNumEmulatedConnections(1); |
| 143 } | 130 } |
| 144 if (config.HasClientSentConnectionOption(kNCON, perspective_)) { | 131 if (config.HasClientSentConnectionOption(kNCON, perspective_)) { |
| 145 n_connection_simulation_ = true; | 132 n_connection_simulation_ = true; |
| 146 } | 133 } |
| 147 if (config.HasClientSentConnectionOption(kNTLP, perspective_)) { | 134 if (config.HasClientSentConnectionOption(kNTLP, perspective_)) { |
| 148 max_tail_loss_probes_ = 0; | 135 max_tail_loss_probes_ = 0; |
| 149 } | 136 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 | 175 |
| 189 void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) { | 176 void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) { |
| 190 if (n_connection_simulation_) { | 177 if (n_connection_simulation_) { |
| 191 // Ensure the number of connections is between 1 and 5. | 178 // Ensure the number of connections is between 1 and 5. |
| 192 send_algorithm_->SetNumEmulatedConnections( | 179 send_algorithm_->SetNumEmulatedConnections( |
| 193 min<size_t>(5, max<size_t>(1, num_streams))); | 180 min<size_t>(5, max<size_t>(1, num_streams))); |
| 194 } | 181 } |
| 195 } | 182 } |
| 196 | 183 |
| 197 void QuicSentPacketManager::SetMaxPacingRate(QuicBandwidth max_pacing_rate) { | 184 void QuicSentPacketManager::SetMaxPacingRate(QuicBandwidth max_pacing_rate) { |
| 198 if (using_pacing_) { | 185 pacing_sender_.set_max_pacing_rate(max_pacing_rate); |
| 199 static_cast<PacingSender*>(send_algorithm_.get()) | |
| 200 ->SetMaxPacingRate(max_pacing_rate); | |
| 201 } | |
| 202 } | 186 } |
| 203 | 187 |
| 204 void QuicSentPacketManager::SetHandshakeConfirmed() { | 188 void QuicSentPacketManager::SetHandshakeConfirmed() { |
| 205 handshake_confirmed_ = true; | 189 handshake_confirmed_ = true; |
| 206 } | 190 } |
| 207 | 191 |
| 208 void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, | 192 void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, |
| 209 QuicTime ack_receive_time) { | 193 QuicTime ack_receive_time) { |
| 210 DCHECK_LE(ack_frame.largest_observed, unacked_packets_.largest_sent_packet()); | 194 DCHECK_LE(ack_frame.largest_observed, unacked_packets_.largest_sent_packet()); |
| 211 QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight(); | 195 QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 least_packet_awaited_by_peer_ = ack_frame.packets.Min(); | 260 least_packet_awaited_by_peer_ = ack_frame.packets.Min(); |
| 277 } | 261 } |
| 278 } | 262 } |
| 279 | 263 |
| 280 void QuicSentPacketManager::MaybeInvokeCongestionEvent( | 264 void QuicSentPacketManager::MaybeInvokeCongestionEvent( |
| 281 bool rtt_updated, | 265 bool rtt_updated, |
| 282 QuicByteCount bytes_in_flight) { | 266 QuicByteCount bytes_in_flight) { |
| 283 if (!rtt_updated && packets_acked_.empty() && packets_lost_.empty()) { | 267 if (!rtt_updated && packets_acked_.empty() && packets_lost_.empty()) { |
| 284 return; | 268 return; |
| 285 } | 269 } |
| 286 send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight, | 270 if (using_pacing_) { |
| 271 pacing_sender_.OnCongestionEvent(rtt_updated, bytes_in_flight, |
| 287 packets_acked_, packets_lost_); | 272 packets_acked_, packets_lost_); |
| 273 } else { |
| 274 send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight, |
| 275 packets_acked_, packets_lost_); |
| 276 } |
| 288 packets_acked_.clear(); | 277 packets_acked_.clear(); |
| 289 packets_lost_.clear(); | 278 packets_lost_.clear(); |
| 290 if (network_change_visitor_ != nullptr) { | 279 if (network_change_visitor_ != nullptr) { |
| 291 network_change_visitor_->OnCongestionChange(); | 280 network_change_visitor_->OnCongestionChange(); |
| 292 } | 281 } |
| 293 } | 282 } |
| 294 | 283 |
| 295 void QuicSentPacketManager::HandleAckForSentPackets( | 284 void QuicSentPacketManager::HandleAckForSentPackets( |
| 296 const QuicAckFrame& ack_frame) { | 285 const QuicAckFrame& ack_frame) { |
| 297 // Go through the packets we have not received an ack for and see if this | 286 // Go through the packets we have not received an ack for and see if this |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 << "Cannot send empty packets."; | 542 << "Cannot send empty packets."; |
| 554 | 543 |
| 555 if (delegate_ == nullptr && original_packet_number != 0) { | 544 if (delegate_ == nullptr && original_packet_number != 0) { |
| 556 pending_retransmissions_.erase(original_packet_number); | 545 pending_retransmissions_.erase(original_packet_number); |
| 557 } | 546 } |
| 558 | 547 |
| 559 if (pending_timer_transmission_count_ > 0) { | 548 if (pending_timer_transmission_count_ > 0) { |
| 560 --pending_timer_transmission_count_; | 549 --pending_timer_transmission_count_; |
| 561 } | 550 } |
| 562 | 551 |
| 563 // TODO(ianswett): Remove sent_time, because it's unused. | 552 bool in_flight; |
| 564 const bool in_flight = send_algorithm_->OnPacketSent( | 553 if (using_pacing_) { |
| 565 sent_time, unacked_packets_.bytes_in_flight(), packet_number, | 554 in_flight = pacing_sender_.OnPacketSent( |
| 566 serialized_packet->encrypted_length, has_retransmittable_data); | 555 sent_time, unacked_packets_.bytes_in_flight(), packet_number, |
| 556 serialized_packet->encrypted_length, has_retransmittable_data); |
| 557 } else { |
| 558 in_flight = send_algorithm_->OnPacketSent( |
| 559 sent_time, unacked_packets_.bytes_in_flight(), packet_number, |
| 560 serialized_packet->encrypted_length, has_retransmittable_data); |
| 561 } |
| 567 | 562 |
| 568 unacked_packets_.AddSentPacket(serialized_packet, original_packet_number, | 563 unacked_packets_.AddSentPacket(serialized_packet, original_packet_number, |
| 569 transmission_type, sent_time, in_flight); | 564 transmission_type, sent_time, in_flight); |
| 570 // Reset the retransmission timer anytime a pending packet is sent. | 565 // Reset the retransmission timer anytime a pending packet is sent. |
| 571 return in_flight; | 566 return in_flight; |
| 572 } | 567 } |
| 573 | 568 |
| 574 void QuicSentPacketManager::OnRetransmissionTimeout() { | 569 void QuicSentPacketManager::OnRetransmissionTimeout() { |
| 575 DCHECK(unacked_packets_.HasInFlightPackets()); | 570 DCHECK(unacked_packets_.HasInFlightPackets()); |
| 576 DCHECK_EQ(0u, pending_timer_transmission_count_); | 571 DCHECK_EQ(0u, pending_timer_transmission_count_); |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 return true; | 762 return true; |
| 768 } | 763 } |
| 769 | 764 |
| 770 QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now, | 765 QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now, |
| 771 QuicPathId* path_id) { | 766 QuicPathId* path_id) { |
| 772 QuicTime::Delta delay = QuicTime::Delta::Infinite(); | 767 QuicTime::Delta delay = QuicTime::Delta::Infinite(); |
| 773 // The TLP logic is entirely contained within QuicSentPacketManager, so the | 768 // The TLP logic is entirely contained within QuicSentPacketManager, so the |
| 774 // send algorithm does not need to be consulted. | 769 // send algorithm does not need to be consulted. |
| 775 if (pending_timer_transmission_count_ > 0) { | 770 if (pending_timer_transmission_count_ > 0) { |
| 776 delay = QuicTime::Delta::Zero(); | 771 delay = QuicTime::Delta::Zero(); |
| 772 } else if (using_pacing_) { |
| 773 delay = |
| 774 pacing_sender_.TimeUntilSend(now, unacked_packets_.bytes_in_flight()); |
| 777 } else { | 775 } else { |
| 778 delay = | 776 delay = |
| 779 send_algorithm_->TimeUntilSend(now, unacked_packets_.bytes_in_flight()); | 777 send_algorithm_->TimeUntilSend(now, unacked_packets_.bytes_in_flight()); |
| 780 } | 778 } |
| 781 if (!delay.IsInfinite()) { | 779 if (!delay.IsInfinite()) { |
| 782 *path_id = path_id_; | 780 *path_id = path_id_; |
| 783 } | 781 } |
| 784 return delay; | 782 return delay; |
| 785 } | 783 } |
| 786 | 784 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 PendingRetransmissionMap::iterator it = pending_retransmissions_.begin(); | 917 PendingRetransmissionMap::iterator it = pending_retransmissions_.begin(); |
| 920 while (it != pending_retransmissions_.end()) { | 918 while (it != pending_retransmissions_.end()) { |
| 921 if (unacked_packets_.HasRetransmittableFrames(it->first)) { | 919 if (unacked_packets_.HasRetransmittableFrames(it->first)) { |
| 922 ++it; | 920 ++it; |
| 923 continue; | 921 continue; |
| 924 } | 922 } |
| 925 it = pending_retransmissions_.erase(it); | 923 it = pending_retransmissions_.erase(it); |
| 926 } | 924 } |
| 927 } | 925 } |
| 928 | 926 |
| 929 void QuicSentPacketManager::EnablePacing() { | 927 void QuicSentPacketManager::SetSendAlgorithm( |
| 930 // TODO(ianswett): Replace with a method which wraps the send algorithm in a | 928 CongestionControlType congestion_control_type) { |
| 931 // pacer every time a new algorithm is set. | 929 SetSendAlgorithm(SendAlgorithmInterface::Create( |
| 932 if (using_pacing_) { | 930 clock_, &rtt_stats_, congestion_control_type, stats_, |
| 933 return; | 931 initial_congestion_window_)); |
| 934 } | 932 } |
| 935 | 933 |
| 936 // Set up a pacing sender with a 1 millisecond alarm granularity, the same as | 934 void QuicSentPacketManager::SetSendAlgorithm( |
| 937 // the default granularity of the Linux kernel's FQ qdisc. | 935 SendAlgorithmInterface* send_algorithm) { |
| 938 using_pacing_ = true; | 936 send_algorithm_.reset(send_algorithm); |
| 939 send_algorithm_.reset(new PacingSender(send_algorithm_.release(), | 937 pacing_sender_.set_sender(send_algorithm); |
| 940 QuicTime::Delta::FromMilliseconds(1), | |
| 941 kInitialUnpacedBurst)); | |
| 942 } | 938 } |
| 943 | 939 |
| 944 void QuicSentPacketManager::OnConnectionMigration(QuicPathId, | 940 void QuicSentPacketManager::OnConnectionMigration(QuicPathId, |
| 945 PeerAddressChangeType type) { | 941 PeerAddressChangeType type) { |
| 946 if (type == PORT_CHANGE || type == IPV4_SUBNET_CHANGE) { | 942 if (type == PORT_CHANGE || type == IPV4_SUBNET_CHANGE) { |
| 947 // Rtt and cwnd do not need to be reset when the peer address change is | 943 // Rtt and cwnd do not need to be reset when the peer address change is |
| 948 // considered to be caused by NATs. | 944 // considered to be caused by NATs. |
| 949 return; | 945 return; |
| 950 } | 946 } |
| 951 consecutive_rto_count_ = 0; | 947 consecutive_rto_count_ = 0; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 | 998 |
| 1003 void QuicSentPacketManager::RemoveObsoletePackets() { | 999 void QuicSentPacketManager::RemoveObsoletePackets() { |
| 1004 unacked_packets_.RemoveObsoletePackets(); | 1000 unacked_packets_.RemoveObsoletePackets(); |
| 1005 } | 1001 } |
| 1006 | 1002 |
| 1007 void QuicSentPacketManager::OnApplicationLimited() { | 1003 void QuicSentPacketManager::OnApplicationLimited() { |
| 1008 send_algorithm_->OnApplicationLimited(unacked_packets_.bytes_in_flight()); | 1004 send_algorithm_->OnApplicationLimited(unacked_packets_.bytes_in_flight()); |
| 1009 } | 1005 } |
| 1010 | 1006 |
| 1011 } // namespace net | 1007 } // namespace net |
| OLD | NEW |