diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-24 02:53:21 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-24 02:53:21 +0000 |
commit | c67a82cbf39e28a9160158c6f9638bed0c934f6f (patch) | |
tree | 1c5e5cf813bcc5095b750daa1a730f1898d9d50c /net/quic | |
parent | c2b68c83f9d9031bdcc9d7bf1723e013ab919752 (diff) | |
download | chromium_src-c67a82cbf39e28a9160158c6f9638bed0c934f6f.zip chromium_src-c67a82cbf39e28a9160158c6f9638bed0c934f6f.tar.gz chromium_src-c67a82cbf39e28a9160158c6f9638bed0c934f6f.tar.bz2 |
Land Recent QUIC changes.
Flag protect (and default to off) the new QUIC retransmission history
tracking.
Merge internal change: 52291286
Do not send retransmissions of packets if a previous transmission has
been acked.
Merge internal change: 52261869
Send ACKs in response to every packet when a QUIC connection has missing
packets from the peer.
Merge internal change: 52247928
Rename CongestionWindow to SendWindow in several place in
TcpCubicSender, in particular when we have taken a min(cwnd, rwin).
Merge internal change: 52246424
Remove Q008 from the protocol.
Merge internal change: 52231392
Also removed Q007 and the TODO with deleting the code when we delete
version Q007 and Q008.
Retransmit whatever the congestion manager tells us to, and use the
correct RTO timeout when multiple sequential RTO's fire.
Merge internal change: 52231261
Change Retransmission to TransmissionType and split IS_RETRANSMISSION
into NACK_RETRANSMISSION and RTO_RETRANSMISSION so they can be
differentiated by the congestion control.
Merge internal change: 52187292
Track the retransmission history of a QUIC packet so that if a previous
version of the packet is ack'd, the data is not re-sent.
Merge internal change: 52125881
R=rch@chromium.org
Review URL: https://chromiumcodereview.appspot.com/23514073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224863 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
34 files changed, 1326 insertions, 546 deletions
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 99aa10f..f7db31c 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -64,11 +64,11 @@ bool FixRateSender::SentPacket( QuicTime sent_time, QuicPacketSequenceNumber /*sequence_number*/, QuicByteCount bytes, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData /*has_retransmittable_data*/) { fix_rate_leaky_bucket_.Add(sent_time, bytes); paced_sender_.SentPacket(sent_time, bytes); - if (is_retransmission == NOT_RETRANSMISSION) { + if (transmission_type == NOT_RETRANSMISSION) { data_in_flight_ += bytes; } return true; @@ -81,7 +81,7 @@ void FixRateSender::AbandoningPacket( QuicTime::Delta FixRateSender::TimeUntilSend( QuicTime now, - Retransmission /*is_retransmission*/, + TransmissionType /* transmission_type */, HasRetransmittableData /*has_retransmittable_data*/, IsHandshake /*handshake*/) { if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) { diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 781dead..77f4457b 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -36,13 +36,13 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { QuicTime sent_time, QuicPacketSequenceNumber equence_number, QuicByteCount bytes, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( QuicTime now, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc index 5640a73..38fb4cf 100644 --- a/net/quic/congestion_control/inter_arrival_sender.cc +++ b/net/quic/congestion_control/inter_arrival_sender.cc @@ -239,7 +239,7 @@ bool InterArrivalSender::SentPacket( QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission /*is_retransmit*/, + TransmissionType /*transmission_type*/, HasRetransmittableData /*has_retransmittable_data*/) { if (probing_) { probe_->OnSentPacket(bytes); @@ -259,7 +259,7 @@ void InterArrivalSender::AbandoningPacket( QuicTime::Delta InterArrivalSender::TimeUntilSend( QuicTime now, - Retransmission /*retransmit*/, + TransmissionType /*transmission_type*/, HasRetransmittableData has_retransmittable_data, IsHandshake /*handshake*/) { // TODO(pwestin): implement outer_congestion_window_ logic. diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h index 2c455cc..57a616e 100644 --- a/net/quic/congestion_control/inter_arrival_sender.h +++ b/net/quic/congestion_control/inter_arrival_sender.h @@ -47,7 +47,7 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmit, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, @@ -55,7 +55,7 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { virtual QuicTime::Delta TimeUntilSend( QuicTime now, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc index ec519db..c441496 100644 --- a/net/quic/congestion_control/quic_congestion_manager.cc +++ b/net/quic/congestion_control/quic_congestion_manager.cc @@ -52,12 +52,13 @@ void QuicCongestionManager::SentPacket( QuicPacketSequenceNumber sequence_number, QuicTime sent_time, QuicByteCount bytes, - Retransmission retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) { DCHECK(!ContainsKey(pending_packets_, sequence_number)); if (send_algorithm_->SentPacket(sent_time, sequence_number, bytes, - retransmission, has_retransmittable_data)) { + transmission_type, + has_retransmittable_data)) { packet_history_map_[sequence_number] = new class SendAlgorithmInterface::SentPacket(bytes, sent_time); pending_packets_[sequence_number] = bytes; @@ -130,10 +131,10 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame, QuicTime::Delta QuicCongestionManager::TimeUntilSend( QuicTime now, - Retransmission retransmission, + TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake) { - return send_algorithm_->TimeUntilSend(now, retransmission, retransmittable, + return send_algorithm_->TimeUntilSend(now, transmission_type, retransmittable, handshake); } @@ -191,7 +192,7 @@ const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay( retransmission_delay = QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs); } - // Calcluate exponential back off. + // Calculate exponential back off. retransmission_delay = QuicTime::Delta::FromMilliseconds( retransmission_delay.ToMilliseconds() * static_cast<size_t>( (1 << min<size_t>(number_retransmissions, kMaxRetransmissions)))); diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h index 6630343..7b8e1d2 100644 --- a/net/quic/congestion_control/quic_congestion_manager.h +++ b/net/quic/congestion_control/quic_congestion_manager.h @@ -46,7 +46,7 @@ class NET_EXPORT_PRIVATE QuicCongestionManager { virtual void SentPacket(QuicPacketSequenceNumber sequence_number, QuicTime sent_time, QuicByteCount bytes, - Retransmission retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data); // Called when a packet is timed out. @@ -58,7 +58,7 @@ class NET_EXPORT_PRIVATE QuicCongestionManager { // Note 2: Send algorithms may or may not use |retransmit| in their // calculations. virtual QuicTime::Delta TimeUntilSend(QuicTime now, - Retransmission retransmission, + TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake); diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index c29f225..1326d79 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -62,7 +62,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { virtual bool SentPacket(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData is_retransmittable) = 0; // Called when a packet is timed out. @@ -72,7 +72,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Calculate the time until we can send the next packet. virtual QuicTime::Delta TimeUntilSend( QuicTime now, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, IsHandshake handshake) = 0; diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 52c910e..edf80b1 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -28,7 +28,7 @@ TcpCubicSender::TcpCubicSender( cubic_(clock), reno_(reno), congestion_window_count_(0), - receiver_congestion_window_(kDefaultReceiveWindow), + receive_window_(kDefaultReceiveWindow), last_received_accumulated_number_of_lost_packets_(0), bytes_in_flight_(0), update_end_sequence_number_(true), @@ -59,7 +59,7 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( OnIncomingLoss(feedback_receive_time); } } - receiver_congestion_window_ = feedback.tcp.receive_window; + receive_window_ = feedback.tcp.receive_window; } void TcpCubicSender::OnIncomingAck( @@ -97,7 +97,7 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { bool TcpCubicSender::SentPacket(QuicTime /*sent_time*/, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData is_retransmittable) { // Only update bytes_in_flight_ for data packets. if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { @@ -105,9 +105,9 @@ bool TcpCubicSender::SentPacket(QuicTime /*sent_time*/, } bytes_in_flight_ += bytes; - if (is_retransmission == NOT_RETRANSMISSION && update_end_sequence_number_) { + if (transmission_type == NOT_RETRANSMISSION && update_end_sequence_number_) { end_sequence_number_ = sequence_number; - if (AvailableCongestionWindow() == 0) { + if (AvailableSendWindow() == 0) { update_end_sequence_number_ = false; DLOG(INFO) << "Stop update end sequence number @" << sequence_number; } @@ -122,35 +122,35 @@ void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number, } QuicTime::Delta TcpCubicSender::TimeUntilSend( - QuicTime now, - Retransmission is_retransmission, + QuicTime /* now */, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, IsHandshake handshake) { - if (is_retransmission == IS_RETRANSMISSION || + if (transmission_type == NACK_RETRANSMISSION || has_retransmittable_data == NO_RETRANSMITTABLE_DATA || handshake == IS_HANDSHAKE) { - // For TCP we can always send a retransmission, or an ACK immediately. + // For TCP we can always send an ACK immediately. // We also immediately send any handshake packet (CHLO, etc.). We provide - // this special dispensation for handshake messages in QUIC, although the + // this special dispensation for handshake messages in QUIC, although the // concept is not present in TCP. return QuicTime::Delta::Zero(); } - if (AvailableCongestionWindow() == 0) { + if (AvailableSendWindow() == 0) { return QuicTime::Delta::Infinite(); } return QuicTime::Delta::Zero(); } -QuicByteCount TcpCubicSender::AvailableCongestionWindow() { - if (bytes_in_flight_ > CongestionWindow()) { +QuicByteCount TcpCubicSender::AvailableSendWindow() { + if (bytes_in_flight_ > SendWindow()) { return 0; } - return CongestionWindow() - bytes_in_flight_; + return SendWindow() - bytes_in_flight_; } -QuicByteCount TcpCubicSender::CongestionWindow() { - // What's the current congestion window in bytes. - return std::min(receiver_congestion_window_, +QuicByteCount TcpCubicSender::SendWindow() { + // What's the current send window in bytes. + return std::min(receive_window_, congestion_window_ * kMaxSegmentSize); } diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index db829c2..d3322c25 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -45,13 +45,13 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData is_retransmittable) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( QuicTime now, - Retransmission is_retransmission, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; @@ -62,8 +62,8 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { private: friend class test::TcpCubicSenderPeer; - QuicByteCount AvailableCongestionWindow(); - QuicByteCount CongestionWindow(); + QuicByteCount AvailableSendWindow(); + QuicByteCount SendWindow(); void Reset(); void AckAccounting(QuicTime::Delta rtt); void CongestionAvoidance(QuicPacketSequenceNumber ack); @@ -80,7 +80,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { int64 congestion_window_count_; // Receiver side advertised window. - QuicByteCount receiver_congestion_window_; + QuicByteCount receive_window_; // Receiver side advertised packet loss. int last_received_accumulated_number_of_lost_packets_; diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index c7046fc..2ce7fc5 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -23,8 +23,8 @@ class TcpCubicSenderPeer : public TcpCubicSender { QuicTcpCongestionWindow max_tcp_congestion_window) : TcpCubicSender(clock, reno, max_tcp_congestion_window) { } - using TcpCubicSender::AvailableCongestionWindow; - using TcpCubicSender::CongestionWindow; + using TcpCubicSender::AvailableSendWindow; + using TcpCubicSender::SendWindow; using TcpCubicSender::AckAccounting; }; @@ -40,8 +40,8 @@ class TcpCubicSenderTest : public ::testing::Test { acked_sequence_number_(0) { } - void SendAvailableCongestionWindow() { - QuicByteCount bytes_to_send = sender_->AvailableCongestionWindow(); + void SendAvailableSendWindow() { + QuicByteCount bytes_to_send = sender_->AvailableSendWindow(); while (bytes_to_send > 0) { QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send); sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, @@ -76,7 +76,7 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { QuicCongestionFeedbackFrame feedback; // At startup make sure we are at the default. EXPECT_EQ(kDefaultWindowTCP, - sender_->AvailableCongestionWindow()); + sender_->AvailableSendWindow()); // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); @@ -88,11 +88,11 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); // And that window is un-affected. - EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow()); + EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow()); // A retransmit should always return 0. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - IS_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + NACK_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); } TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { @@ -110,11 +110,11 @@ TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - QuicByteCount bytes_to_send = sender_->CongestionWindow(); + QuicByteCount bytes_to_send = sender_->SendWindow(); EXPECT_EQ(kDefaultWindowTCP + kMaxPacketSize * 2 * kNumberOfAck, bytes_to_send); } @@ -139,31 +139,31 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - QuicByteCount expected_congestion_window = + QuicByteCount expected_send_window = kDefaultWindowTCP + (kMaxPacketSize * 2 * kNumberOfAck); - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); // We should now have fallen out of slow start. - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(2); - expected_congestion_window += kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + expected_send_window += kMaxPacketSize; + EXPECT_EQ(expected_send_window, sender_->SendWindow()); // Testing Reno phase. // We should need 141(65*2+1+10) ACK:ed packets before increasing window by // one. for (int m = 0; m < 70; ++m) { - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(2); - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(2); - expected_congestion_window += kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + expected_send_window += kMaxPacketSize; + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { @@ -182,14 +182,14 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); for (int i = 0; i < kNumberOfAck; ++i) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - SendAvailableCongestionWindow(); - QuicByteCount expected_congestion_window = kDefaultWindowTCP + + SendAvailableSendWindow(); + QuicByteCount expected_send_window = kDefaultWindowTCP + (kMaxPacketSize * 2 * kNumberOfAck); - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); sender_->OnIncomingLoss(clock_.Now()); @@ -199,32 +199,32 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { // We should now have fallen out of slow start. // We expect window to be cut in half. - expected_congestion_window /= 2; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + expected_send_window /= 2; + EXPECT_EQ(expected_send_window, sender_->SendWindow()); // Testing Reno phase. // We need to ack half of the pending packet before we can send again. - int number_of_packets_in_window = expected_congestion_window / kMaxPacketSize; + int number_of_packets_in_window = expected_send_window / kMaxPacketSize; AckNPackets(number_of_packets_in_window); - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); - EXPECT_EQ(0u, sender_->AvailableCongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); + EXPECT_EQ(0u, sender_->AvailableSendWindow()); AckNPackets(1); - expected_congestion_window += kMaxPacketSize; + expected_send_window += kMaxPacketSize; number_of_packets_in_window++; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); // We should need number_of_packets_in_window ACK:ed packets before // increasing window by one. for (int k = 0; k < number_of_packets_in_window; ++k) { - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(1); - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(1); - expected_congestion_window += kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + expected_send_window += kMaxPacketSize; + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } TEST_F(TcpCubicSenderTest, RetransmissionDelay) { @@ -256,7 +256,7 @@ TEST_F(TcpCubicSenderTest, RetransmissionDelay) { 1); } -TEST_F(TcpCubicSenderTest, SlowStartMaxCongestionWindow) { +TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) { const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50; const int kNumberOfAck = 100; sender_.reset( @@ -275,13 +275,13 @@ TEST_F(TcpCubicSenderTest, SlowStartMaxCongestionWindow) { NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); for (int i = 0; i < kNumberOfAck; ++i) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - QuicByteCount expected_congestion_window = + QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) { @@ -302,20 +302,20 @@ TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(2); // Make sure we fall out of slow start. sender_->OnIncomingLoss(clock_.Now()); for (int i = 0; i < kNumberOfAck; ++i) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - QuicByteCount expected_congestion_window = + QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { @@ -336,37 +336,37 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - SendAvailableCongestionWindow(); + SendAvailableSendWindow(); AckNPackets(2); // Make sure we fall out of slow start. sender_->OnIncomingLoss(clock_.Now()); for (int i = 0; i < kNumberOfAck; ++i) { - // Send our full congestion window. - SendAvailableCongestionWindow(); + // Send our full send window. + SendAvailableSendWindow(); AckNPackets(2); } - QuicByteCount expected_congestion_window = + QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kMaxPacketSize; - EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->SendWindow()); } -TEST_F(TcpCubicSenderTest, CongestionWindowNotAffectedByAcks) { - QuicByteCount congestion_window = sender_->AvailableCongestionWindow(); +TEST_F(TcpCubicSenderTest, SendWindowNotAffectedByAcks) { + QuicByteCount send_window = sender_->AvailableSendWindow(); // Send a packet with no retransmittable data, and ensure that the congestion // window doesn't change. - QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, congestion_window); + QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, send_window); sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); - EXPECT_EQ(congestion_window, sender_->AvailableCongestionWindow()); + EXPECT_EQ(send_window, sender_->AvailableSendWindow()); // Send a data packet with retransmittable data, and ensure that the // congestion window has shrunk. sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); - EXPECT_GT(congestion_window, sender_->AvailableCongestionWindow()); + EXPECT_GT(send_window, sender_->AvailableSendWindow()); } } // namespace test diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc index e4e661a..ad8d4e7 100644 --- a/net/quic/crypto/proof_test.cc +++ b/net/quic/crypto/proof_test.cc @@ -223,7 +223,6 @@ TEST(ProofTest, VerifyRSAKnownAnswerTest) { const string server_config = "server config bytes"; const string hostname = "test.example.com"; - string error_details; CertVerifyResult cert_verify_result; vector<string> certs(2); @@ -312,7 +311,6 @@ TEST(ProofTest, VerifyECDSAKnownAnswerTest) { const string server_config = "server config bytes"; const string hostname = "test.example.com"; - string error_details; CertVerifyResult cert_verify_result; vector<string> certs(2); diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 7417bd4..92ef7a3 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -32,7 +32,7 @@ namespace { const QuicPacketSequenceNumber kMaxPacketGap = 5000; // We want to make sure if we get a large nack packet, we don't queue up too -// many packets at once. 10 is arbitrary. +// many packets at once. 10 is a common default initial congestion window. const size_t kMaxRetransmissionsPerAck = 10; // TCP retransmits after 2 nacks. We allow for a third in case of out-of-order @@ -41,10 +41,6 @@ const size_t kMaxRetransmissionsPerAck = 10; // at least 3 sequence numbers larger arrives. const size_t kNumberOfNacksBeforeRetransmission = 3; -// Limit the number of packets we send per retransmission-alarm so we -// eventually cede. 10 is arbitrary. -const size_t kMaxPacketsPerRetransmissionAlarm = 10; - // Limit the number of FEC groups to two. If we get enough out of order packets // that this becomes limiting, we can revisit. const size_t kMaxFecGroups = 2; @@ -85,7 +81,25 @@ class RetransmissionAlarm : public QuicAlarm::Delegate { } virtual QuicTime OnAlarm() OVERRIDE { - return connection_->OnRetransmissionTimeout(); + connection_->OnRetransmissionTimeout(); + return QuicTime::Zero(); + } + + private: + QuicConnection* connection_; +}; + +// This alarm will be scheduled any time a FEC-bearing packet is sent out. +// When the alarm goes off, the connection checks to see if the oldest packets +// have been acked, and removes them from the congestion window if not. +class AbandonFecAlarm : public QuicAlarm::Delegate { + public: + explicit AbandonFecAlarm(QuicConnection* connection) + : connection_(connection) { + } + + virtual QuicTime OnAlarm() OVERRIDE { + return connection_->OnAbandonFecTimeout(); } private: @@ -168,10 +182,10 @@ QuicConnection::QuicConnection(QuicGuid guid, guid_(guid), peer_address_(address), largest_seen_packet_with_ack_(0), - handling_retransmission_timeout_(false), write_blocked_(false), ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))), + abandon_fec_alarm_(helper->CreateAlarm(new AbandonFecAlarm(this))), send_alarm_(helper->CreateAlarm(new SendAlarm(this))), timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))), debug_visitor_(NULL), @@ -186,7 +200,7 @@ QuicConnection::QuicConnection(QuicGuid guid, congestion_manager_(clock_, kTCP), sent_packet_manager_(is_server, this), version_negotiation_state_(START_NEGOTIATION), - max_packets_per_retransmission_alarm_(kMaxPacketsPerRetransmissionAlarm), + consecutive_rto_count_(0), is_server_(is_server), connected_(true), received_truncated_ack_(false), @@ -453,16 +467,6 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { return false; } - // Reset the RTO timeout for each packet when an ack is received. - if (retransmission_alarm_->IsSet()) { - retransmission_alarm_->Cancel(); - QuicTime::Delta retransmission_delay = - congestion_manager_.GetRetransmissionDelay( - sent_packet_manager_.GetNumUnackedPackets(), 0); - retransmission_alarm_->Set(clock_->ApproximateNow().Add( - retransmission_delay)); - } - last_ack_frames_.push_back(incoming_ack); return connected_; } @@ -484,8 +488,8 @@ void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) { retransmitted_nacked_packet_count_ = 0; SequenceNumberSet acked_packets; - sent_packet_manager_.HandleAckForSentPackets(incoming_ack, &acked_packets); - sent_packet_manager_.HandleAckForSentFecPackets(incoming_ack, &acked_packets); + sent_packet_manager_.OnIncomingAck( + incoming_ack.received_info, received_truncated_ack_, &acked_packets); if (acked_packets.size() > 0) { // Inform all the registered AckNotifiers of the new ACKs. // TODO(rjshade): Make this more efficient by maintaining a mapping of @@ -503,13 +507,31 @@ void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) { ++it; } } - } - // Clear the earliest retransmission timeouts that are no longer unacked to - // ensure the priority queue doesn't become too large. - while (!retransmission_timeouts_.empty() && - !sent_packet_manager_.IsUnacked( - retransmission_timeouts_.top().sequence_number)) { - retransmission_timeouts_.pop(); + + // Reset the RTO timeout for each packet when an ack is received. + if (retransmission_alarm_->IsSet()) { + retransmission_alarm_->Cancel(); + // Only reschedule the timer if there are outstanding packets. + if (sent_packet_manager_.HasUnackedPackets()) { + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), 0); + retransmission_alarm_->Set(clock_->ApproximateNow().Add( + retransmission_delay)); + } + } + if (abandon_fec_alarm_->IsSet()) { + abandon_fec_alarm_->Cancel(); + // Only reschedule the timer if there are outstanding fec packets. + if (sent_packet_manager_.HasUnackedFecPackets()) { + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), 0); + abandon_fec_alarm_->Set(clock_->ApproximateNow().Add( + retransmission_delay)); + } + } + consecutive_rto_count_ = 0; } congestion_manager_.OnIncomingAckFrame(incoming_ack, time_of_last_received_packet_); @@ -668,6 +690,13 @@ void QuicConnection::OnPacketComplete() { // from unacket_packets_, increasing the least_unacked. const bool last_packet_should_instigate_ack = ShouldLastPacketInstigateAck(); + // If we are missing any packets from the peer, then we want to ack + // immediately. We need to check both before and after we process the + // current packet because we want to ack immediately when we discover + // a missing packet AND when we receive the last missing packet. + bool send_ack_immediately = + received_packet_manager_.GetNumMissingPackets() != 0; + if (last_stream_frames_.empty() || visitor_->OnStreamFrames(last_stream_frames_)) { received_packet_manager_.RecordPacketReceived( @@ -689,7 +718,13 @@ void QuicConnection::OnPacketComplete() { last_congestion_frames_[i], time_of_last_received_packet_); } - MaybeSendInResponseToPacket(last_packet_should_instigate_ack); + if (received_packet_manager_.GetNumMissingPackets() != 0) { + send_ack_immediately = true; + } + + MaybeSendInResponseToPacket(send_ack_immediately, + last_packet_should_instigate_ack); + ClearLastFrames(); } @@ -726,8 +761,7 @@ bool QuicConnection::ShouldLastPacketInstigateAck() { // longer planning to send, we should send an ack to raise // the high water mark. if (!last_ack_frames_.empty() && - !last_ack_frames_.back().received_info.missing_packets.empty() && - sent_packet_manager_.HasUnackedPackets()) { + !last_ack_frames_.back().received_info.missing_packets.empty()) { return sent_packet_manager_.GetLeastUnackedSentPacket() > *last_ack_frames_.back().received_info.missing_packets.begin(); } @@ -735,9 +769,16 @@ bool QuicConnection::ShouldLastPacketInstigateAck() { } void QuicConnection::MaybeSendInResponseToPacket( + bool send_ack_immediately, bool last_packet_should_instigate_ack) { packet_generator_.StartBatchOperations(); + if (send_ack_immediately) { + send_ack_in_response_to_packet_ = true; + } + + // TODO(rch): remove last_packet_should_instigate_ack when we remove + // g_acks_do_not_instigate_acks. if (last_packet_should_instigate_ack || !g_acks_do_not_instigate_acks) { if (send_ack_in_response_to_packet_) { @@ -1005,6 +1046,7 @@ bool QuicConnection::WriteQueuedPackets() { if (WritePacket(packet_iterator->encryption_level, packet_iterator->sequence_number, packet_iterator->packet, + packet_iterator->transmission_type, packet_iterator->retransmittable, packet_iterator->forced)) { packet_iterator = queued_packets_.erase(packet_iterator); @@ -1018,37 +1060,10 @@ bool QuicConnection::WriteQueuedPackets() { return !write_blocked_; } -bool QuicConnection::MaybeRetransmitPacketForRTO( - QuicPacketSequenceNumber sequence_number) { - if (!sent_packet_manager_.IsUnacked(sequence_number)) { - DVLOG(2) << ENDPOINT << "alarm fired for " << sequence_number - << " but it has been acked or already retransmitted with" - << " a different sequence number."; - // So no extra delay is added for this packet. - return true; - } - - // If the packet hasn't been acked and we're getting truncated acks, ignore - // any RTO for packets larger than the peer's largest observed packet; it may - // have been received by the peer and just wasn't acked due to the ack frame - // running out of space. - if (received_truncated_ack_ && - sequence_number > GetPeerLargestObservedPacket() && - // We allow retransmission of already retransmitted packets so that we - // retransmit packets that were retransmissions of the packet with - // sequence number < the largest observed field of the truncated ack. - !sent_packet_manager_.IsRetransmission(sequence_number)) { - return false; - } - - ++stats_.rto_count; - RetransmitPacket(sequence_number); - return true; -} - void QuicConnection::RetransmitUnackedPackets( RetransmissionType retransmission_type) { - SequenceNumberSet unacked_packets = sent_packet_manager_.GetUnackedPackets(); + SequenceNumberSet unacked_packets = + sent_packet_manager_.GetRetransmittablePackets(); if (unacked_packets.empty()) { return; } @@ -1062,19 +1077,27 @@ void QuicConnection::RetransmitUnackedPackets( // TODO(satyamshekhar): Think about congestion control here. // Specifically, about the retransmission count of packets being sent // proactively to achieve 0 (minimal) RTT. - RetransmitPacket(*unacked_it); + RetransmitPacket(*unacked_it, NACK_RETRANSMISSION); } } } void QuicConnection::RetransmitPacket( - QuicPacketSequenceNumber sequence_number) { + QuicPacketSequenceNumber sequence_number, + TransmissionType transmission_type) { DCHECK(sent_packet_manager_.IsUnacked(sequence_number)); // TODO(pwestin): Need to fix potential issue with FEC and a 1 packet // congestion window see b/8331807 for details. congestion_manager_.AbandoningPacket(sequence_number); + // If we have received an ACK for an old version of this packet, then + // we should not retransmit the data. + if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) { + sent_packet_manager_.DiscardUnackedPacket(sequence_number); + return; + } + const RetransmittableFrames& retransmittable_frames = sent_packet_manager_.GetRetransmittableFrames(sequence_number); @@ -1108,11 +1131,12 @@ void QuicConnection::RetransmitPacket( serialized_packet.sequence_number, serialized_packet.packet, serialized_packet.entropy_hash, + transmission_type, HAS_RETRANSMITTABLE_DATA, HasForcedFrames(serialized_packet.retransmittable_frames)); } -bool QuicConnection::CanWrite(Retransmission retransmission, +bool QuicConnection::CanWrite(TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake) { // TODO(ianswett): If the packet is a retransmit, the current send alarm may @@ -1123,7 +1147,7 @@ bool QuicConnection::CanWrite(Retransmission retransmission, QuicTime now = clock_->Now(); QuicTime::Delta delay = congestion_manager_.TimeUntilSend( - now, retransmission, retransmittable, handshake); + now, transmission_type, retransmittable, handshake); if (delay.IsInfinite()) { return false; } @@ -1140,51 +1164,42 @@ bool QuicConnection::CanWrite(Retransmission retransmission, void QuicConnection::SetupRetransmission( QuicPacketSequenceNumber sequence_number, EncryptionLevel level) { - if (!sent_packet_manager_.IsUnacked(sequence_number)) { + if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) { DVLOG(1) << ENDPOINT << "Will not retransmit packet " << sequence_number; return; } - size_t retransmission_count = - sent_packet_manager_.GetRetransmissionCount(sequence_number); - // TODO(rch): consider using a much smaller retransmisison_delay - // for the ENCRYPTION_NONE packets. - size_t effective_retransmission_count = - level == ENCRYPTION_NONE ? 0 : retransmission_count; - QuicTime::Delta retransmission_delay = - congestion_manager_.GetRetransmissionDelay( - sent_packet_manager_.GetNumUnackedPackets(), - effective_retransmission_count); - - retransmission_timeouts_.push(RetransmissionTime( - sequence_number, - clock_->ApproximateNow().Add(retransmission_delay), - false)); - // Do not set the retransmisson alarm if we're already handling the + // Do not set the retransmission alarm if we're already handling the // retransmission alarm because the retransmission alarm will be reset when // OnRetransmissionTimeout completes. - if (!handling_retransmission_timeout_ && !retransmission_alarm_->IsSet()) { - retransmission_alarm_->Set( - clock_->ApproximateNow().Add(retransmission_delay)); + if (retransmission_alarm_->IsSet()) { + return; } + + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), consecutive_rto_count_); + retransmission_alarm_->Set( + clock_->ApproximateNow().Add(retransmission_delay)); // TODO(satyamshekhar): restore packet reordering with Ian's TODO in // SendStreamData(). } void QuicConnection::SetupAbandonFecTimer( QuicPacketSequenceNumber sequence_number) { + if (abandon_fec_alarm_->IsSet()) { + return; + } QuicTime::Delta retransmission_delay = - QuicTime::Delta::FromMilliseconds( - congestion_manager_.DefaultRetransmissionTime().ToMilliseconds() * 3); - retransmission_timeouts_.push(RetransmissionTime( - sequence_number, - clock_->ApproximateNow().Add(retransmission_delay), - true)); + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), consecutive_rto_count_); + abandon_fec_alarm_->Set(clock_->ApproximateNow().Add(retransmission_delay)); } bool QuicConnection::WritePacket(EncryptionLevel level, QuicPacketSequenceNumber sequence_number, QuicPacket* packet, + TransmissionType transmission_type, HasRetransmittableData retransmittable, Force forced) { if (!connected_) { @@ -1202,14 +1217,47 @@ bool QuicConnection::WritePacket(EncryptionLevel level, // anymore. DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number << " since the packet is NULL encrypted."; - sent_packet_manager_.DiscardPacket(sequence_number); + sent_packet_manager_.DiscardUnackedPacket(sequence_number); delete packet; return true; } - Retransmission retransmission = - sent_packet_manager_.IsRetransmission(sequence_number) ? - IS_RETRANSMISSION : NOT_RETRANSMISSION; + if (retransmittable == HAS_RETRANSMITTABLE_DATA) { + if (!sent_packet_manager_.IsUnacked(sequence_number)) { + // This is a crazy edge case, but if we retransmit a packet, + // (but have to queue it for some reason) then receive an ack + // for the previous transmission (but not the retransmission) + // then receive a truncated ACK which causes us to raise the + // high water mark, all before we're able to send the packet + // then we can simply drop it. + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since it has already been acked."; + delete packet; + return true; + } + + if (sent_packet_manager_.IsPreviousTransmission(sequence_number)) { + // If somehow we have already retransmitted this packet *before* + // we actually send it for the first time (I think this is probably + // impossible in the real world), then don't bother sending it. + // We don't want to call DiscardUnackedPacket because in this case + // the peer has not yet ACK'd the data. We need the subsequent + // retransmission to be sent. + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since it has already been retransmitted."; + delete packet; + return true; + } + + if (!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) { + DLOG(INFO) << ENDPOINT << "Dropping packet: " << sequence_number + << " since a previous transmission has been acked."; + sent_packet_manager_.DiscardUnackedPacket(sequence_number); + delete packet; + return true; + } + } + // TODO(wtc): use the same logic that is used in the packet generator. // Namely, a packet is a handshake if it contains a stream frame for the // crypto stream. It should be possible to look at the RetransmittableFrames @@ -1219,7 +1267,7 @@ bool QuicConnection::WritePacket(EncryptionLevel level, // If we are not forced and we can't write, then simply return false; if (forced == NO_FORCE && - !CanWrite(retransmission, retransmittable, handshake)) { + !CanWrite(transmission_type, retransmittable, handshake)) { return false; } @@ -1248,11 +1296,6 @@ bool QuicConnection::WritePacket(EncryptionLevel level, int error; QuicTime now = clock_->Now(); - if (!retransmission) { - time_of_last_sent_packet_ = now; - } - DVLOG(1) << ENDPOINT << "time of last sent packet: " - << now.ToDebuggingValue(); if (WritePacketToWire(sequence_number, level, *encrypted, &error) == -1) { if (helper_->IsWriteBlocked(error)) { // TODO(satyashekhar): It might be more efficient (fewer system calls), if @@ -1272,6 +1315,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level, CloseConnection(QUIC_PACKET_WRITE_ERROR, false); return false; } + if (transmission_type == NOT_RETRANSMISSION) { + time_of_last_sent_packet_ = now; + } + DVLOG(1) << ENDPOINT << "time of last sent packet: " + << now.ToDebuggingValue(); // Set the retransmit alarm only when we have sent the packet to the client // and not when it goes to the pending queue, otherwise we will end up adding @@ -1290,12 +1338,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level, congestion_manager_.SmoothedRtt())); congestion_manager_.SentPacket(sequence_number, now, packet->length(), - retransmission, retransmittable); + transmission_type, retransmittable); stats_.bytes_sent += encrypted->length(); ++stats_.packets_sent; - if (retransmission == IS_RETRANSMISSION) { + if (transmission_type == NACK_RETRANSMISSION || + transmission_type == RTO_RETRANSMISSION) { stats_.bytes_retransmitted += encrypted->length(); ++stats_.packets_retransmitted; } @@ -1324,11 +1373,15 @@ bool QuicConnection::OnSerializedPacket( serialized_packet.retransmittable_frames->set_encryption_level( encryption_level_); } - sent_packet_manager_.OnSerializedPacket(serialized_packet); + sent_packet_manager_.OnSerializedPacket(serialized_packet, + clock_->ApproximateNow()); + // The TransmissionType is NOT_RETRANSMISSION because all retransmissions + // serialize packets and invoke SendOrQueuePacket directly. return SendOrQueuePacket(encryption_level_, serialized_packet.sequence_number, serialized_packet.packet, serialized_packet.entropy_hash, + NOT_RETRANSMISSION, serialized_packet.retransmittable_frames != NULL ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA, @@ -1336,10 +1389,6 @@ bool QuicConnection::OnSerializedPacket( serialized_packet.retransmittable_frames)); } -QuicPacketSequenceNumber QuicConnection::GetPeerLargestObservedPacket() { - return received_packet_manager_.peer_largest_observed_packet(); -} - QuicPacketSequenceNumber QuicConnection::GetNextPacketSequenceNumber() { return packet_creator_.sequence_number() + 1; } @@ -1349,7 +1398,7 @@ void QuicConnection::OnPacketNacked(QuicPacketSequenceNumber sequence_number, if (nack_count >= kNumberOfNacksBeforeRetransmission && retransmitted_nacked_packet_count_ < kMaxRetransmissionsPerAck) { ++retransmitted_nacked_packet_count_; - RetransmitPacket(sequence_number); + RetransmitPacket(sequence_number, NACK_RETRANSMISSION); } } @@ -1357,12 +1406,15 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level, QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, + TransmissionType transmission_type, HasRetransmittableData retransmittable, Force forced) { sent_entropy_manager_.RecordPacketEntropyHash(sequence_number, entropy_hash); - if (!WritePacket(level, sequence_number, packet, retransmittable, forced)) { + if (!WritePacket(level, sequence_number, packet, + transmission_type, retransmittable, forced)) { queued_packets_.push_back(QueuedPacket(sequence_number, packet, level, - retransmittable, forced)); + transmission_type, retransmittable, + forced)); return false; } return true; @@ -1400,58 +1452,49 @@ void QuicConnection::SendAck() { packet_generator_.SetShouldSendAck(send_feedback); } -void QuicConnection::MaybeAbandonFecPacket( - QuicPacketSequenceNumber sequence_number) { - if (!sent_packet_manager_.IsFecUnacked(sequence_number)) { - DVLOG(2) << ENDPOINT << "no need to abandon fec packet: " - << sequence_number << "; it's already acked'"; +void QuicConnection::OnRetransmissionTimeout() { + if (!sent_packet_manager_.HasUnackedPackets()) { return; } - congestion_manager_.AbandoningPacket(sequence_number); -} -QuicTime QuicConnection::OnRetransmissionTimeout() { - // This guards against registering the alarm later than we should. - // - // If we have packet A and B in the list and we call - // MaybeRetransmitPacketForRTO on A, that may trigger a call to - // SetRetransmissionAlarm if A is retransmitted as C. In that case we - // don't want to register the alarm under SetRetransmissionAlarm; we - // want to set it to the RTO of B when we return from this function. - handling_retransmission_timeout_ = true; - - for (size_t i = 0; i < max_packets_per_retransmission_alarm_ && - !retransmission_timeouts_.empty(); ++i) { - RetransmissionTime retransmission_time = retransmission_timeouts_.top(); - DCHECK(retransmission_time.scheduled_time.IsInitialized()); - if (retransmission_time.scheduled_time > clock_->ApproximateNow()) { - break; - } - retransmission_timeouts_.pop(); + // TODO(ianswett): When multiple RTO's fire, the subsequent RTO should send + // the same data packet as the first RTO according to the TCP spec. + // TODO(ianswett): When an RTO fires, but the connection has not been + // established as forward secure, re-send the client hello first. + ++stats_.rto_count; + ++consecutive_rto_count_; - if (retransmission_time.for_fec) { - MaybeAbandonFecPacket(retransmission_time.sequence_number); - continue; - } else if ( - !MaybeRetransmitPacketForRTO(retransmission_time.sequence_number)) { - DLOG(INFO) << ENDPOINT << "MaybeRetransmitPacketForRTO failed: " - << "adding an extra delay for " - << retransmission_time.sequence_number; - retransmission_time.scheduled_time = clock_->ApproximateNow().Add( - congestion_manager_.DefaultRetransmissionTime()); - retransmission_timeouts_.push(retransmission_time); - } + // Attempt to send all the unacked packets when the RTO fires, let the + // congestion manager decide how many to send immediately and the remaining + // packets will be queued for future sending. + SequenceNumberSet unacked_packets = + sent_packet_manager_.GetRetransmittablePackets(); + for (SequenceNumberSet::const_iterator it = unacked_packets.begin(); + it != unacked_packets.end(); ++it) { + RetransmitPacket(*it, RTO_RETRANSMISSION); } +} - handling_retransmission_timeout_ = false; - - if (retransmission_timeouts_.empty()) { - return QuicTime::Zero(); +QuicTime QuicConnection::OnAbandonFecTimeout() { + // Abandon all the FEC packets older than the current RTO, then reschedule + // the alarm if there are more pending fec packets. + QuicTime::Delta retransmission_delay = + congestion_manager_.GetRetransmissionDelay( + sent_packet_manager_.GetNumUnackedPackets(), consecutive_rto_count_); + QuicTime max_send_time = + clock_->ApproximateNow().Subtract(retransmission_delay); + while (sent_packet_manager_.HasUnackedFecPackets()) { + QuicPacketSequenceNumber oldest_unacked_fec = + sent_packet_manager_.GetLeastUnackedFecPacket(); + QuicTime fec_sent_time = + sent_packet_manager_.GetFecSentTime(oldest_unacked_fec); + if (fec_sent_time > max_send_time) { + return fec_sent_time.Add(retransmission_delay); + } + sent_packet_manager_.DiscardFecPacket(oldest_unacked_fec); + congestion_manager_.AbandoningPacket(oldest_unacked_fec); } - - // We have packets remaining. Return the absolute RTO of the oldest packet - // on the list. - return retransmission_timeouts_.top().scheduled_time; + return QuicTime::Zero(); } void QuicConnection::SetEncrypter(EncryptionLevel level, diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 1524909..99ac1ab 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -303,16 +303,14 @@ class NET_EXPORT_PRIVATE QuicConnection virtual void OnPacketComplete() OVERRIDE; // QuicPacketGenerator::DelegateInterface - virtual bool CanWrite( - Retransmission is_retransmission, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) OVERRIDE; + virtual bool CanWrite(TransmissionType transmission_type, + HasRetransmittableData retransmittable, + IsHandshake handshake) OVERRIDE; virtual QuicAckFrame* CreateAckFrame() OVERRIDE; virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() OVERRIDE; virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE; // QuicSentPacketManager::HelperInterface - virtual QuicPacketSequenceNumber GetPeerLargestObservedPacket() OVERRIDE; virtual QuicPacketSequenceNumber GetNextPacketSequenceNumber() OVERRIDE; virtual void OnPacketNacked(QuicPacketSequenceNumber sequence_number, size_t nack_count) OVERRIDE; @@ -331,14 +329,10 @@ class NET_EXPORT_PRIVATE QuicConnection const QuicClock* clock() const { return clock_; } QuicRandom* random_generator() const { return random_generator_; } - // Called by a RetransmissionAlarm when the timer goes off. If the peer - // appears to be sending truncated acks, this returns false to indicate - // failure, otherwise it calls MaybeRetransmitPacket and returns true. - bool MaybeRetransmitPacketForRTO(QuicPacketSequenceNumber sequence_number); - // Called to retransmit a packet, in the case a packet was sufficiently // nacked by the peer, or not acked within the time out window. - void RetransmitPacket(QuicPacketSequenceNumber sequence_number); + void RetransmitPacket(QuicPacketSequenceNumber sequence_number, + TransmissionType transmission_type); QuicPacketCreator::Options* options() { return packet_creator_.options(); } @@ -378,7 +372,11 @@ class NET_EXPORT_PRIVATE QuicConnection // Called when an RTO fires. Returns the time when this alarm // should next fire, or 0 if no retransmission alarm should be set. - QuicTime OnRetransmissionTimeout(); + void OnRetransmissionTimeout(); + + // Called when an alarm to abandon sent FEC packets fires. The alarm is set + // by the same policy as the RTO alarm, but is a separate alarm. + QuicTime OnAbandonFecTimeout(); // Retransmits unacked packets which were sent with initial encryption, if // |initial_encryption_only| is true, otherwise retransmits all unacked @@ -425,13 +423,14 @@ class NET_EXPORT_PRIVATE QuicConnection // Deletes |packet| via WritePacket call or transfers ownership to // QueuedPacket, ultimately deleted via WritePacket. Updates the // entropy map corresponding to |sequence_number| using |entropy_hash|. - // |retransmittable| is supplied to the congestion manager, and when |forced| - // is true, it bypasses the congestion manager. + // |transmission_type| and |retransmittable| are supplied to the congestion + // manager, and when |forced| is true, it bypasses the congestion manager. // TODO(wtc): none of the callers check the return value. virtual bool SendOrQueuePacket(EncryptionLevel level, QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, + TransmissionType transmission_type, HasRetransmittableData retransmittable, Force forced); @@ -446,6 +445,7 @@ class NET_EXPORT_PRIVATE QuicConnection bool WritePacket(EncryptionLevel level, QuicPacketSequenceNumber sequence_number, QuicPacket* packet, + TransmissionType transmission_type, HasRetransmittableData retransmittable, Force force); @@ -484,11 +484,13 @@ class NET_EXPORT_PRIVATE QuicConnection QueuedPacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, EncryptionLevel level, + TransmissionType transmission_type, HasRetransmittableData retransmittable, Force forced) : sequence_number(sequence_number), packet(packet), encryption_level(level), + transmission_type(transmission_type), retransmittable(retransmittable), forced(forced) { } @@ -496,21 +498,25 @@ class NET_EXPORT_PRIVATE QuicConnection QuicPacketSequenceNumber sequence_number; QuicPacket* packet; const EncryptionLevel encryption_level; + TransmissionType transmission_type; HasRetransmittableData retransmittable; Force forced; }; struct RetransmissionInfo { RetransmissionInfo(QuicPacketSequenceNumber sequence_number, - QuicSequenceNumberLength sequence_number_length) + QuicSequenceNumberLength sequence_number_length, + QuicTime sent_time) : sequence_number(sequence_number), sequence_number_length(sequence_number_length), + sent_time(sent_time), number_nacks(0), number_retransmissions(0) { } QuicPacketSequenceNumber sequence_number; QuicSequenceNumberLength sequence_number_length; + QuicTime sent_time; size_t number_nacks; size_t number_retransmissions; }; @@ -599,9 +605,8 @@ class NET_EXPORT_PRIVATE QuicConnection // Sends any packets which are a response to the last packet, including both // acks and pending writes if an ack opened the congestion window. - void MaybeSendInResponseToPacket(bool last_packet_should_instigate_ack); - - void MaybeAbandonFecPacket(QuicPacketSequenceNumber sequence_number); + void MaybeSendInResponseToPacket(bool send_ack_immediately, + bool last_packet_should_instigate_ack); // Get the FEC group associate with the last processed packet or NULL, if the // group has already been deleted. @@ -645,18 +650,6 @@ class NET_EXPORT_PRIVATE QuicConnection // sent with the INITIAL encryption and the CHLO message was lost. std::deque<QuicEncryptedPacket*> undecryptable_packets_; - // Heap of packets that we might need to retransmit, and the time at - // which we should retransmit them. Every time a packet is sent it is added - // to this heap which is O(log(number of pending packets to be retransmitted)) - // which might be costly. This should be optimized to O(1) by maintaining a - // priority queue of lists of packets to be retransmitted, where list x - // contains all packets that have been retransmitted x times. - RetransmissionTimeouts retransmission_timeouts_; - - // True while OnRetransmissionTimeout is running to prevent - // SetRetransmissionAlarm from being called erroneously. - bool handling_retransmission_timeout_; - // When packets could not be sent because the socket was not writable, // they are added to this list. All corresponding frames are in // unacked_packets_ if they are to be retransmitted. @@ -674,6 +667,8 @@ class NET_EXPORT_PRIVATE QuicConnection scoped_ptr<QuicAlarm> ack_alarm_; // An alarm that fires when a packet needs to be retransmitted. scoped_ptr<QuicAlarm> retransmission_alarm_; + // An alarm that fires when one or more FEC packets are to be discarded. + scoped_ptr<QuicAlarm> abandon_fec_alarm_; // An alarm that is scheduled when the sent scheduler requires a // a delay before sending packets and fires when the packet may be sent. scoped_ptr<QuicAlarm> send_alarm_; @@ -713,7 +708,8 @@ class NET_EXPORT_PRIVATE QuicConnection // The state of connection in version negotiation finite state machine. QuicVersionNegotiationState version_negotiation_state_; - size_t max_packets_per_retransmission_alarm_; + // Number of times the RTO timer has fired in a row without receiving an ack. + size_t consecutive_rto_count_; // Tracks if the connection was created by the server. bool is_server_; diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index aaa692b..c28c236 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -58,8 +58,6 @@ class TestConnection : public QuicConnection { void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); } - - using QuicConnection::SendOrQueuePacket; }; class QuicConnectionHelperTest : public ::testing::Test { @@ -309,7 +307,7 @@ TEST_F(QuicConnectionHelperTest, CreateAlarmAndReset) { EXPECT_TRUE(delegate->fired()); } -TEST_F(QuicConnectionHelperTest, TestRetransmission) { +TEST_F(QuicConnectionHelperTest, TestRTORetransmission) { AddWrite(SYNCHRONOUS, ConstructDataPacket(1)); AddWrite(SYNCHRONOUS, ConstructDataPacket(2)); Initialize(); @@ -328,7 +326,7 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) { struct iovec iov = {const_cast<char*>(kData), static_cast<size_t>(strlen(kData))}; connection_->SendvStreamData(1, &iov, 1, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, RTO_RETRANSMISSION, _)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); @@ -338,7 +336,7 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) { EXPECT_TRUE(AtEof()); } -TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) { +TEST_F(QuicConnectionHelperTest, TestMultipleRTORetransmission) { AddWrite(SYNCHRONOUS, ConstructDataPacket(1)); AddWrite(SYNCHRONOUS, ConstructDataPacket(2)); AddWrite(SYNCHRONOUS, ConstructDataPacket(3)); @@ -358,7 +356,7 @@ TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) { struct iovec iov = {const_cast<char*>(kData), static_cast<size_t>(strlen(kData))}; connection_->SendvStreamData(1, &iov, 1, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, RTO_RETRANSMISSION, _)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); @@ -368,7 +366,7 @@ TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) { // Since no ack was received, the retransmission alarm will fire and // retransmit it. - EXPECT_CALL(*send_algorithm_, SentPacket(_, 3, _, IS_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 3, _, RTO_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)); runner_->RunNextTask(); @@ -476,11 +474,11 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) { EXPECT_CALL( *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( Return(QuicTime::Delta::FromMicroseconds(1))); + connection_->OnSerializedPacket( + SerializedPacket(1, PACKET_6BYTE_SEQUENCE_NUMBER, + ConstructRawDataPacket(1), 0, + new RetransmittableFrames)); - QuicPacket* packet = ConstructRawDataPacket(1); - connection_->SendOrQueuePacket(ENCRYPTION_NONE, 1, packet, 0, - HAS_RETRANSMITTABLE_DATA, - QuicConnection::NO_FORCE); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); EXPECT_EQ(1u, connection_->NumQueuedPackets()); diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index afe8a76..1e622e7 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -389,17 +389,17 @@ class TestConnection : public QuicConnection { QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); } - bool SendOrQueuePacket(EncryptionLevel level, - QuicPacketSequenceNumber sequence_number, - QuicPacket* packet, - QuicPacketEntropyHash entropy_hash, - HasRetransmittableData retransmittable) { - return SendOrQueuePacket(level, - sequence_number, - packet, - entropy_hash, - retransmittable, - NO_FORCE); + void SendPacket(EncryptionLevel level, + QuicPacketSequenceNumber sequence_number, + QuicPacket* packet, + QuicPacketEntropyHash entropy_hash, + HasRetransmittableData retransmittable) { + RetransmittableFrames* retransmittable_frames = + retransmittable == HAS_RETRANSMITTABLE_DATA ? + new RetransmittableFrames() : NULL; + OnSerializedPacket( + SerializedPacket(sequence_number, PACKET_6BYTE_SEQUENCE_NUMBER, + packet, entropy_hash, retransmittable_frames)); } QuicConsumedData SendStreamData(QuicStreamId id, @@ -475,7 +475,6 @@ class TestConnection : public QuicConnection { return QuicConnectionPeer::GetTimeoutAlarm(this); } - using QuicConnection::SendOrQueuePacket; using QuicConnection::SelectMutualVersion; private: @@ -496,6 +495,9 @@ class QuicConnectionTest : public ::testing::Test { frame1_(1, false, 0, data1), frame2_(1, false, 3, data2), accept_packet_(true) { + // TODO(rtenneti): remove g_* flags. + QuicConnection::g_acks_do_not_instigate_acks = true; + FLAGS_track_retransmission_history = true; connection_.set_visitor(&visitor_); connection_.SetSendAlgorithm(send_algorithm_); // Simplify tests by not sending feedback unless specifically configured. @@ -514,8 +516,6 @@ class QuicConnectionTest : public ::testing::Test { QuicTime::Delta::FromMilliseconds(100))); ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)) .WillByDefault(Return(true)); - // TODO(rch): remove this. - QuicConnection::g_acks_do_not_instigate_acks = true; EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber()); } @@ -928,37 +928,67 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) { ProcessAckPacket(&frame, true); } +TEST_F(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + + ProcessPacket(3); + // Should ack immediately since we have missing packets. + EXPECT_EQ(1u, helper_->packets_write_attempts()); + + ProcessPacket(2); + // Should ack immediately since we have missing packets. + EXPECT_EQ(2u, helper_->packets_write_attempts()); + + ProcessPacket(1); + // Should ack immediately, since this fills the last hole. + EXPECT_EQ(3u, helper_->packets_write_attempts()); + + ProcessPacket(4); + // Should not cause an ack. + EXPECT_EQ(3u, helper_->packets_write_attempts()); +} + TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); - QuicPacketSequenceNumber largest_observed; + QuicPacketSequenceNumber original; QuicByteCount packet_size; EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) - .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size), + .WillOnce(DoAll(SaveArg<1>(&original), SaveArg<2>(&packet_size), Return(true))); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); connection_.SendStreamData(1, "foo", 0, !kFin); - QuicAckFrame frame(1, QuicTime::Zero(), largest_observed); - frame.received_info.missing_packets.insert(largest_observed); + QuicAckFrame frame(original, QuicTime::Zero(), 1); + frame.received_info.missing_packets.insert(original); frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( - &connection_, largest_observed - 1); + &connection_, original - 1); ProcessAckPacket(&frame, true); ProcessAckPacket(&frame, true); // Third nack should retransmit the largest observed packet. + QuicPacketSequenceNumber retransmission; EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize, - IS_RETRANSMISSION, _)); + NACK_RETRANSMISSION, _)) + .WillOnce(DoAll(SaveArg<1>(&retransmission), Return(true))); ProcessAckPacket(&frame, true); + QuicAckFrame frame2(retransmission, QuicTime::Zero(), 1); + frame2.received_info.missing_packets.insert(original); + frame2.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, retransmission) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, original); + EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)); + + ProcessAckPacket(&frame2, true); // Now if the peer sends an ack which still reports the retransmitted packet // as missing, then that will count as a packet which instigates an ack. - ProcessAckPacket(&frame, true); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); - ProcessAckPacket(&frame, true); + ProcessAckPacket(&frame2, true); + ProcessAckPacket(&frame2, true); - // But an ack with no new missing packest will not send an ack. - frame.received_info.missing_packets.clear(); - ProcessAckPacket(&frame, true); - ProcessAckPacket(&frame, true); + // But an ack with no missing packets will not send an ack. + frame2.received_info.missing_packets.clear(); + ProcessAckPacket(&frame2, true); + ProcessAckPacket(&frame2, true); } TEST_F(QuicConnectionTest, LeastUnackedLower) { @@ -1247,17 +1277,14 @@ TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) { EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(2); connection_.SendStreamData(1, "foo", 0, !kFin); - // Larger timeout for FEC bytes to expire. const QuicTime::Delta retransmission_time = QuicTime::Delta::FromMilliseconds(5000); clock_.AdvanceTime(retransmission_time); - // Send only data packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); - // Abandon both FEC and data packet. - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); + // Abandon FEC packet. + EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(1); - connection_.OnRetransmissionTimeout(); + connection_.OnAbandonFecTimeout(); } TEST_F(QuicConnectionTest, DontAbandonAckedFEC) { @@ -1543,10 +1570,66 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { // The third nack should trigger a retransimission. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, second_packet_size - kQuicVersionSize, - IS_RETRANSMISSION, _)).Times(1); + NACK_RETRANSMISSION, _)).Times(1); ProcessAckPacket(&nack_two, true); } +TEST_F(QuicConnectionTest, DiscardRetransmit) { + EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); + EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)).Times(1); + QuicPacketSequenceNumber last_packet; + SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 + SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2 + SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3 + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + + // Peer acks one but not two or three. Right now we only retransmit on + // explicit nack, so it should not trigger a retransimission. + QuicAckFrame ack_one(1, QuicTime::Zero(), 0); + ack_one.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); + ProcessAckPacket(&ack_one, true); + ProcessAckPacket(&ack_one, true); + ProcessAckPacket(&ack_one, true); + + // Peer acks up to 3 with two explicitly missing. Two nacks should cause no + // change. + QuicAckFrame nack_two(3, QuicTime::Zero(), 0); + nack_two.received_info.missing_packets.insert(2); + nack_two.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 3) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 2) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); + ProcessAckPacket(&nack_two, true); + ProcessAckPacket(&nack_two, true); + + // The third nack should trigger a retransimission, but we'll be + // write blocked, so the packet will be queued. + helper_->set_blocked(true); + + ProcessAckPacket(&nack_two, false); + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + + // Now, ack the previous transmission. + QuicAckFrame ack_all(3, QuicTime::Zero(), 0); + nack_two.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 3); + ProcessAckPacket(&ack_all, true); + + // Unblock the socket and attempt to send the queued packets. However, + // since the previous transmission has been acked, we will not + // send the retransmission. + EXPECT_CALL(*send_algorithm_, + SentPacket(_, _, _, _, _)).Times(0); + + helper_->set_blocked(false); + connection_.OnCanWrite(); + + EXPECT_EQ(0u, connection_.NumQueuedPackets()); +} + TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); @@ -1565,44 +1648,34 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { ProcessAckPacket(&frame, true); // Third nack should retransmit the largest observed packet. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize, - IS_RETRANSMISSION, _)); + NACK_RETRANSMISSION, _)); ProcessAckPacket(&frame, true); } -TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) { - for (int i = 0; i < 200; ++i) { +TEST_F(QuicConnectionTest, QueueAfterTwoRTOs) { + for (int i = 0; i < 10; ++i) { EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); connection_.SendStreamData(1, "foo", i * 3, !kFin); } - // Make a truncated ack frame. - QuicAckFrame frame(0, QuicTime::Zero(), 1); - frame.received_info.largest_observed = 193; - InsertMissingPacketsBetween(&frame.received_info, 1, 193); - frame.received_info.entropy_hash = - QuicConnectionPeer::GetSentEntropyHash(&connection_, 193) ^ - QuicConnectionPeer::GetSentEntropyHash(&connection_, 192); - - EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); - EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessAckPacket(&frame, true); - EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); - - QuicConnectionPeer::SetMaxPacketsPerRetransmissionAlarm(&connection_, 200); + // Block the congestion window and ensure they're queued. + helper_->set_blocked(true); clock_.AdvanceTime(DefaultRetransmissionTime()); - // Only packets that are less than largest observed should be retransmitted. - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(192); + // Only one packet should be retransmitted. + EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(10); connection_.OnRetransmissionTimeout(); + EXPECT_TRUE(connection_.HasQueuedData()); + // Unblock the congestion window. + helper_->set_blocked(false); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds( 2 * DefaultRetransmissionTime().ToMicroseconds())); // Retransmit already retransmitted packets event though the sequence number // greater than the largest observed. - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(192); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(10); connection_.OnRetransmissionTimeout(); + EXPECT_CALL(visitor_, OnCanWrite()); + connection_.OnCanWrite(); } TEST_F(QuicConnectionTest, LimitPacketsPerNack) { @@ -1772,9 +1845,10 @@ TEST_F(QuicConnectionTest, TestRetransmit) { clock_.AdvanceTime(DefaultRetransmissionTime()); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); - connection_.RetransmitPacket(1); + connection_.RetransmitPacket(1, RTO_RETRANSMISSION); EXPECT_EQ(2u, last_header()->packet_sequence_number); - EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked); + // We do not raise the high water mark yet. + EXPECT_EQ(1u, outgoing_ack()->sent_info.least_unacked); } TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { @@ -1800,12 +1874,12 @@ TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); - connection_.RetransmitPacket(1); + connection_.RetransmitPacket(1, RTO_RETRANSMISSION); // Packet should have been sent with ENCRYPTION_NONE. EXPECT_EQ(0x01010101u, final_bytes_of_last_packet()); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); - connection_.RetransmitPacket(2); + connection_.RetransmitPacket(2, RTO_RETRANSMISSION); // Packet should have been sent with ENCRYPTION_INITIAL. EXPECT_EQ(0x02020202u, final_bytes_of_last_packet()); } @@ -1883,7 +1957,6 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) { QuicByteCount first_packet_size; EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).WillOnce( DoAll(SaveArg<2>(&first_packet_size), Return(true))); - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); connection_.SendStreamData(1, "first_packet", 0, !kFin); QuicByteCount second_packet_size; @@ -1893,6 +1966,19 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) { EXPECT_NE(first_packet_size, second_packet_size); // Advance the clock by huge time to make sure packets will be retransmitted. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); + EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); + { + InSequence s; + EXPECT_CALL(*send_algorithm_, + SentPacket(_, _, first_packet_size, _, _)); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, _, second_packet_size, _, _)); + } + connection_.OnRetransmissionTimeout(); + + // Advance again and expect the packets to be sent again in the same order. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(20)); + EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); { InSequence s; EXPECT_CALL(*send_algorithm_, @@ -1905,20 +1991,21 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) { TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); QuicPacketSequenceNumber original_sequence_number; EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .WillOnce(DoAll(SaveArg<1>(&original_sequence_number), Return(true))); connection_.SendStreamData(1, "foo", 0, !kFin); + EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, original_sequence_number)); EXPECT_EQ(0u, QuicConnectionPeer::GetRetransmissionCount( &connection_, original_sequence_number)); // Force retransmission due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); + EXPECT_CALL(*send_algorithm_, + AbandoningPacket(original_sequence_number, _)).Times(1); QuicPacketSequenceNumber rto_sequence_number; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, RTO_RETRANSMISSION, _)) .WillOnce(DoAll(SaveArg<1>(&rto_sequence_number), Return(true))); connection_.OnRetransmissionTimeout(); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( @@ -1928,24 +2015,29 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { EXPECT_EQ(1u, QuicConnectionPeer::GetRetransmissionCount( &connection_, rto_sequence_number)); // Once by explicit nack. - QuicPacketSequenceNumber nack_sequence_number; + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); + EXPECT_CALL(*send_algorithm_, + AbandoningPacket(rto_sequence_number, _)).Times(1); + QuicPacketSequenceNumber nack_sequence_number = 0; // Ack packets might generate some other packets, which are not // retransmissions. (More ack packets). EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NACK_RETRANSMISSION, _)) .WillOnce(DoAll(SaveArg<1>(&nack_sequence_number), Return(true))); QuicAckFrame ack(rto_sequence_number, QuicTime::Zero(), 0); // Ack the retransmitted packet. + ack.received_info.missing_packets.insert(original_sequence_number); ack.received_info.missing_packets.insert(rto_sequence_number); ack.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( &connection_, rto_sequence_number - 1); for (int i = 0; i < 3; i++) { ProcessAckPacket(&ack, true); } + ASSERT_NE(0u, nack_sequence_number); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, rto_sequence_number)); - EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission( + ASSERT_TRUE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, nack_sequence_number)); EXPECT_EQ(2u, QuicConnectionPeer::GetRetransmissionCount( &connection_, nack_sequence_number)); @@ -1955,13 +2047,15 @@ TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) { helper_->set_blocked(true); connection_.SendStreamData(1, "foo", 0, !kFin); // Make sure that RTO is not started when the packet is queued. - EXPECT_EQ(0u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); + EXPECT_FALSE( + QuicConnectionPeer::GetRetransmissionAlarm(&connection_)->IsSet()); // Test that RTO is started once we write to the socket. helper_->set_blocked(false); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnCanWrite(); - EXPECT_EQ(1u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); + EXPECT_TRUE( + QuicConnectionPeer::GetRetransmissionAlarm(&connection_)->IsSet()); } TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) { @@ -1970,37 +2064,39 @@ TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) { .Times(2); connection_.SendStreamData(1, "foo", 0, !kFin); connection_.SendStreamData(2, "bar", 0, !kFin); - EXPECT_EQ(2u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); + QuicAlarm* retransmission_alarm = + QuicConnectionPeer::GetRetransmissionAlarm(&connection_); + EXPECT_TRUE(retransmission_alarm->IsSet()); // Advance the time right before the RTO, then receive an ack for the first // packet to delay the RTO. clock_.AdvanceTime(DefaultRetransmissionTime()); - EXPECT_EQ(2u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); QuicAckFrame ack(1, QuicTime::Zero(), 0); ProcessAckPacket(&ack, true); - EXPECT_EQ(1u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); + EXPECT_TRUE(retransmission_alarm->IsSet()); // Move forward past the original RTO and ensure the RTO is still pending. clock_.AdvanceTime(DefaultRetransmissionTime()); - EXPECT_EQ(1u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); // Ensure the second packet gets retransmitted when it finally fires. - EXPECT_TRUE( - QuicConnectionPeer::GetRetransmissionAlarm(&connection_)->IsSet()); - EXPECT_GE( - QuicConnectionPeer::GetRetransmissionAlarm(&connection_)->deadline(), - clock_.ApproximateNow()); + EXPECT_TRUE(retransmission_alarm->IsSet()); + EXPECT_GE(retransmission_alarm->deadline(), clock_.ApproximateNow()); clock_.AdvanceTime(DefaultRetransmissionTime()); - EXPECT_LT( - QuicConnectionPeer::GetRetransmissionAlarm(&connection_)->deadline(), - clock_.ApproximateNow()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _)); + EXPECT_LT(retransmission_alarm->deadline(), clock_.ApproximateNow()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, RTO_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)); + // Manually cancel the alarm to simulate a real test. + retransmission_alarm->Cancel(); connection_.OnRetransmissionTimeout(); - // The new retransmitted sequence number should now be in the timeout queue. - EXPECT_EQ(1u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); + // The new retransmitted sequence number should set the RTO to a larger value + // than previously. + EXPECT_TRUE(retransmission_alarm->IsSet()); + QuicTime next_rto_time = retransmission_alarm->deadline(); + QuicTime::Delta expected_rto = QuicConnectionPeer::GetCongestionManager( + &connection_)->GetRetransmissionDelay(1, 1); + EXPECT_EQ(next_rto_time, clock_.ApproximateNow().Add(expected_rto)); } TEST_F(QuicConnectionTest, TestQueued) { @@ -2126,7 +2222,7 @@ TEST_F(QuicConnectionTest, SendScheduler) { TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } @@ -2138,7 +2234,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) { TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } @@ -2147,11 +2243,11 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) { // Test that if we force send a packet, it is not queued. QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, IS_RETRANSMISSION, _, _)).Times(0); + TimeUntilSend(_, NACK_RETRANSMISSION, _, _)).Times(0); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); - // XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce); + // XXX: fixme. was: connection_.SendPacket(1, packet, kForce); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } @@ -2162,7 +2258,7 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) { TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } @@ -2173,7 +2269,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2202,7 +2298,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501)); // Test that if we send a retransmit with a delay, it ends up queued. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, IS_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, RTO_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.OnRetransmissionTimeout(); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2210,12 +2306,12 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, IS_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, RTO_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); // Ensure the scheduler is notified this is a retransmit. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, IS_RETRANSMISSION, _)); + SentPacket(_, _, _, RTO_RETRANSMISSION, _)); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(visitor_, OnCanWrite()); @@ -2228,13 +2324,13 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Attempt to send another packet and make sure that it gets queued. packet = ConstructDataPacket(2, 0, !kEntropyFlag); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 2, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(2u, connection_.NumQueuedPackets()); } @@ -2245,7 +2341,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2270,7 +2366,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2290,7 +2386,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2350,7 +2446,7 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) { EXPECT_FALSE(connection_.connected()); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); } @@ -2476,7 +2572,7 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) { packet_entropy_hash = 1 << (i % 8); } QuicPacket* packet = ConstructDataPacket(i, 0, entropy_flag); - connection_.SendOrQueuePacket( + connection_.SendPacket( ENCRYPTION_NONE, i, packet, packet_entropy_hash, HAS_RETRANSMITTABLE_DATA); @@ -2597,7 +2693,6 @@ TEST_F(QuicConnectionTest, BadVersionNegotiation) { } TEST_F(QuicConnectionTest, CheckSendStats) { - EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); connection_.SendStreamData(1u, "first", 0, !kFin); @@ -2610,7 +2705,10 @@ TEST_F(QuicConnectionTest, CheckSendStats) { // 2 retransmissions due to rto, 1 due to explicit nack. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, IS_RETRANSMISSION, _)).Times(3); + SentPacket(_, _, _, RTO_RETRANSMISSION, _)).Times(2); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, _, _, NACK_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); // Retransmit due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); @@ -2619,10 +2717,12 @@ TEST_F(QuicConnectionTest, CheckSendStats) { // Retransmit due to explicit nacks QuicAckFrame nack_three(4, QuicTime::Zero(), 0); nack_three.received_info.missing_packets.insert(3); + nack_three.received_info.missing_packets.insert(1); nack_three.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(&connection_, 4) ^ QuicConnectionPeer::GetSentEntropyHash(&connection_, 3) ^ - QuicConnectionPeer::GetSentEntropyHash(&connection_, 2); + QuicConnectionPeer::GetSentEntropyHash(&connection_, 2) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); QuicFrame frame(&nack_three); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); @@ -2645,7 +2745,7 @@ TEST_F(QuicConnectionTest, CheckSendStats) { EXPECT_EQ(2 * first_packet_size + second_packet_size - kQuicVersionSize, stats.bytes_retransmitted); EXPECT_EQ(3u, stats.packets_retransmitted); - EXPECT_EQ(2u, stats.rto_count); + EXPECT_EQ(1u, stats.rto_count); } TEST_F(QuicConnectionTest, CheckReceiveStats) { diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 0122c64..6cbbb97 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -91,12 +91,8 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, SpdyHeaderBlock headers; CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, &headers, 3, /*direct=*/true); - if (session_->connection()->version() < QUIC_VERSION_9) { - request_ = stream_->compressor()->CompressHeaders(headers); - } else { - request_ = stream_->compressor()->CompressHeadersWithPriority(priority, - headers); - } + request_ = stream_->compressor()->CompressHeadersWithPriority(priority, + headers); // Log the actual request with the URL Request's net log. stream_net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS, diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 7ccab6d..816c5cb 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -242,7 +242,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { bool write_priority, RequestPriority priority) { QuicSpdyCompressor compressor; - if (framer_.version() >= QUIC_VERSION_9 && write_priority) { + if (write_priority) { return compressor.CompressHeadersWithPriority( ConvertRequestPriorityToQuicPriority(priority), headers); } diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index 940b259..1467760 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h @@ -64,7 +64,7 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator { class NET_EXPORT_PRIVATE DelegateInterface { public: virtual ~DelegateInterface() {} - virtual bool CanWrite(Retransmission retransmission, + virtual bool CanWrite(TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake) = 0; virtual QuicAckFrame* CreateAckFrame() = 0; diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index ec8dd56..627c58d 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc @@ -33,7 +33,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface { MockDelegate() {} virtual ~MockDelegate() {} - MOCK_METHOD3(CanWrite, bool(Retransmission retransmission, + MOCK_METHOD3(CanWrite, bool(TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake)); diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index cdf3c6c..d08e7b8 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -121,8 +121,6 @@ QuicVersion QuicVersionMin() { QuicTag QuicVersionToQuicTag(const QuicVersion version) { switch (version) { - case QUIC_VERSION_8: - return MakeQuicTag('Q', '0', '0', '8'); case QUIC_VERSION_9: return MakeQuicTag('Q', '0', '0', '9'); case QUIC_VERSION_10: @@ -136,13 +134,10 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { } QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) { - const QuicTag quic_tag_v8 = MakeQuicTag('Q', '0', '0', '8'); const QuicTag quic_tag_v9 = MakeQuicTag('Q', '0', '0', '9'); const QuicTag quic_tag_v10 = MakeQuicTag('Q', '0', '1', '0'); - if (version_tag == quic_tag_v8) { - return QUIC_VERSION_8; - } else if (version_tag == quic_tag_v9) { + if (version_tag == quic_tag_v9) { return QUIC_VERSION_9; } else if (version_tag == quic_tag_v10) { return QUIC_VERSION_10; @@ -160,7 +155,6 @@ return #x string QuicVersionToString(const QuicVersion version) { switch (version) { - RETURN_STRING_LITERAL(QUIC_VERSION_8); RETURN_STRING_LITERAL(QUIC_VERSION_9); RETURN_STRING_LITERAL(QUIC_VERSION_10); default: diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 26e6c02..8532a22 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -83,9 +83,10 @@ const int64 kDefaultInitialTimeoutSecs = 120; // 2 mins. const int64 kDefaultTimeoutSecs = 60 * 10; // 10 minutes. const int64 kDefaultMaxTimeForCryptoHandshakeSecs = 5; // 5 secs. -enum Retransmission { +enum TransmissionType { NOT_RETRANSMISSION, - IS_RETRANSMISSION, + NACK_RETRANSMISSION, + RTO_RETRANSMISSION, }; enum HasRetransmittableData { @@ -189,7 +190,6 @@ enum QuicVersion { // Special case to indicate unknown/unsupported QUIC version. QUIC_VERSION_UNSUPPORTED = 0, - QUIC_VERSION_8 = 8, QUIC_VERSION_9 = 9, QUIC_VERSION_10 = 10, // Current version. }; @@ -220,7 +220,7 @@ NET_EXPORT_PRIVATE QuicTag QuicVersionToQuicTag(const QuicVersion version); NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag); // Returns the appropriate QuicTag for a properly formed version string -// (e.g. Q008). +// (e.g. Q010). NET_EXPORT_PRIVATE QuicTag StringToQuicTag(std::string version); // Helper function which translates from a QuicVersion to a string. diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc index 52ed664..13c7eb4 100644 --- a/net/quic/quic_protocol_test.cc +++ b/net/quic/quic_protocol_test.cc @@ -127,17 +127,16 @@ TEST(QuicProtocolTest, QuicTagToQuicVersionUnsupported) { } TEST(QuicProtocolTest, QuicVersionToString) { - EXPECT_EQ("QUIC_VERSION_8", - QuicVersionToString(QUIC_VERSION_8)); + EXPECT_EQ("QUIC_VERSION_10", QuicVersionToString(QUIC_VERSION_10)); EXPECT_EQ("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(QUIC_VERSION_UNSUPPORTED)); - QuicVersion single_version[] = {QUIC_VERSION_8}; - EXPECT_EQ("QUIC_VERSION_8,", QuicVersionArrayToString( - single_version, arraysize(single_version))); - QuicVersion multiple_versions[] = - {QUIC_VERSION_10, QUIC_VERSION_9, QUIC_VERSION_8}; - EXPECT_EQ("QUIC_VERSION_10,QUIC_VERSION_9,QUIC_VERSION_8,", + QuicVersion single_version[] = {QUIC_VERSION_10}; + EXPECT_EQ("QUIC_VERSION_10,", + QuicVersionArrayToString(single_version, + arraysize(single_version))); + QuicVersion multiple_versions[] = {QUIC_VERSION_10, QUIC_VERSION_9}; + EXPECT_EQ("QUIC_VERSION_10,QUIC_VERSION_9,", QuicVersionArrayToString(multiple_versions, arraysize(multiple_versions))); } diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc index 9a136db..81868ac 100644 --- a/net/quic/quic_received_packet_manager.cc +++ b/net/quic/quic_received_packet_manager.cc @@ -185,4 +185,8 @@ void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer( peer_least_packet_awaiting_ack_); } +size_t QuicReceivedPacketManager::GetNumMissingPackets() { + return received_info_.missing_packets.size(); +} + } // namespace net diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h index a762ae8..f25c35f 100644 --- a/net/quic/quic_received_packet_manager.h +++ b/net/quic/quic_received_packet_manager.h @@ -50,6 +50,9 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager : // Updates internal state based on |incoming_ack.sent_info|. void UpdatePacketInformationSentByPeer(const QuicAckFrame& incoming_ack); + // Returns the number of packets which are missing from the peer. + size_t GetNumMissingPackets(); + QuicPacketSequenceNumber peer_largest_observed_packet() { return peer_largest_observed_packet_; } diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index a8960f0..0163ccc 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -9,6 +9,14 @@ using std::make_pair; +// TODO(rtenneti): Remove this. +// Do not flip this flag until the flakiness of the +// net/tools/quic/end_to_end_test is fixed. +// If true, then QUIC connections will track the retransmission history of a +// packet so that an ack of a previous transmission will ack the data of all +// other transmissions. +bool FLAGS_track_retransmission_history = false; + namespace net { #define ENDPOINT (is_server_ ? "Server: " : " Client: ") @@ -24,14 +32,24 @@ QuicSentPacketManager::QuicSentPacketManager(bool is_server, QuicSentPacketManager::~QuicSentPacketManager() { STLDeleteValues(&unacked_packets_); + while (!previous_transmissions_map_.empty()) { + SequenceNumberSet* previous_transmissions = + previous_transmissions_map_.begin()->second; + for (SequenceNumberSet::const_iterator it = previous_transmissions->begin(); + it != previous_transmissions->end(); ++it) { + DCHECK(ContainsKey(previous_transmissions_map_, *it)); + previous_transmissions_map_.erase(*it); + } + delete previous_transmissions; + } } void QuicSentPacketManager::OnSerializedPacket( - const SerializedPacket& serialized_packet) { + const SerializedPacket& serialized_packet, QuicTime serialized_time) { if (serialized_packet.packet->is_fec_packet()) { + DCHECK(!serialized_packet.retransmittable_frames); unacked_fec_packets_.insert(make_pair( - serialized_packet.sequence_number, - serialized_packet.retransmittable_frames)); + serialized_packet.sequence_number, serialized_time)); return; } @@ -42,7 +60,7 @@ void QuicSentPacketManager::OnSerializedPacket( DCHECK(unacked_packets_.empty() || unacked_packets_.rbegin()->first < - serialized_packet.sequence_number); + serialized_packet.sequence_number); unacked_packets_[serialized_packet.sequence_number] = serialized_packet.retransmittable_frames; retransmission_map_[serialized_packet.sequence_number] = @@ -67,76 +85,219 @@ void QuicSentPacketManager::OnRetransmittedPacket( RetransmittableFrames* frames = unacked_packets_[old_sequence_number]; DCHECK(frames); - unacked_packets_.erase(old_sequence_number); + if (FLAGS_track_retransmission_history) { + // We keep the old packet in the unacked packet list until it, or one of + // the retransmissions of it are acked. + unacked_packets_[old_sequence_number] = NULL; + } else { + unacked_packets_.erase(old_sequence_number); + } unacked_packets_[new_sequence_number] = frames; + + if (!FLAGS_track_retransmission_history) { + return; + } + // Keep track of all sequence numbers that this packet + // has been transmitted as. + SequenceNumberSet* previous_transmissions; + PreviousTransmissionMap::iterator it = + previous_transmissions_map_.find(old_sequence_number); + if (it == previous_transmissions_map_.end()) { + // This is the first retransmission of this packet, so create a new entry. + previous_transmissions = new SequenceNumberSet; + previous_transmissions_map_[old_sequence_number] = previous_transmissions; + previous_transmissions->insert(old_sequence_number); + } else { + // Otherwise, use the existing entry. + previous_transmissions = it->second; + } + previous_transmissions->insert(new_sequence_number); + previous_transmissions_map_[new_sequence_number] = previous_transmissions; + + DCHECK(HasRetransmittableFrames(new_sequence_number)); +} + +void QuicSentPacketManager::OnIncomingAck( + const ReceivedPacketInfo& received_info, + bool is_truncated_ack, + SequenceNumberSet* acked_packets) { + HandleAckForSentPackets(received_info, is_truncated_ack, acked_packets); + HandleAckForSentFecPackets(received_info, acked_packets); +} + +void QuicSentPacketManager::DiscardUnackedPacket( + QuicPacketSequenceNumber sequence_number) { + MarkPacketReceivedByPeer(sequence_number); } void QuicSentPacketManager::HandleAckForSentPackets( - const QuicAckFrame& incoming_ack, + const ReceivedPacketInfo& received_info, + bool is_truncated_ack, SequenceNumberSet* acked_packets) { // Go through the packets we have not received an ack for and see if this // incoming_ack shows they've been seen by the peer. UnackedPacketMap::iterator it = unacked_packets_.begin(); while (it != unacked_packets_.end()) { QuicPacketSequenceNumber sequence_number = it->first; - if (sequence_number > helper_->GetPeerLargestObservedPacket()) { + if (sequence_number > received_info.largest_observed) { // These are very new sequence_numbers. break; } - RetransmittableFrames* unacked = it->second; - if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) { + + if (!IsAwaitingPacket(received_info, sequence_number)) { // Packet was acked, so remove it from our unacked packet list. DVLOG(1) << ENDPOINT <<"Got an ack for packet " << sequence_number; - acked_packets->insert(sequence_number); - delete unacked; - unacked_packets_.erase(it++); - retransmission_map_.erase(sequence_number); - } else { - // This is a packet which we planned on retransmitting and has not been - // seen at the time of this ack being sent out. See if it's our new - // lowest unacked packet. - DVLOG(1) << ENDPOINT << "still missing packet " << sequence_number; + // Only count this packet as acked if it has not been retransmitted. + if (!IsPreviousTransmission(sequence_number)) { + acked_packets->insert(sequence_number); + } + it = MarkPacketReceivedByPeer(sequence_number); + continue; + } + + // The peer got packets after this sequence number. This is an explicit + // nack. + + // TODO(rch): move this to the congestion manager, and fix the logic. + // This is a packet which we planned on retransmitting and has not been + // seen at the time of this ack being sent out. See if it's our new + // lowest unacked packet. + DVLOG(1) << ENDPOINT << "still missing packet " << sequence_number; + ++it; + RetransmissionMap::iterator retransmission_it = + retransmission_map_.find(sequence_number); + if (retransmission_it == retransmission_map_.end()) { + continue; + } + size_t nack_count = ++(retransmission_it->second.number_nacks); + helper_->OnPacketNacked(sequence_number, nack_count); + } + + // If we have received a trunacted ack, then we need to + // clear out some previous transmissions to allow the peer + // to actually ACK new packets. + if (is_truncated_ack) { + size_t num_to_clear = received_info.missing_packets.size() / 2; + UnackedPacketMap::iterator it = unacked_packets_.begin(); + while (it != unacked_packets_.end() && num_to_clear > 0) { + QuicPacketSequenceNumber sequence_number = it->first; ++it; - // The peer got packets after this sequence number. This is an explicit - // nack. - RetransmissionMap::iterator retransmission_it = - retransmission_map_.find(sequence_number); - if (retransmission_it == retransmission_map_.end()) { - continue; + // If this is not a previous transmission then there is no point + // in clearing out any further packets, because it will not + // affect the high water mark. + if (!IsPreviousTransmission(sequence_number)) { + break; } - size_t nack_count = ++(retransmission_it->second.number_nacks); - helper_->OnPacketNacked(sequence_number, nack_count); + + DCHECK(ContainsKey(previous_transmissions_map_, sequence_number)); + DCHECK(!ContainsKey(retransmission_map_, sequence_number)); + DCHECK(!HasRetransmittableFrames(sequence_number)); + unacked_packets_.erase(sequence_number); + SequenceNumberSet* previous_transmissions = + previous_transmissions_map_[sequence_number]; + previous_transmissions_map_.erase(sequence_number); + previous_transmissions->erase(sequence_number); + if (previous_transmissions->size() == 1) { + previous_transmissions_map_.erase(*previous_transmissions->begin()); + delete previous_transmissions; + } + --num_to_clear; } } } -void QuicSentPacketManager::HandleAckForSentFecPackets( - const QuicAckFrame& incoming_ack, - SequenceNumberSet* acked_packets) { - UnackedPacketMap::iterator it = unacked_fec_packets_.begin(); - while (it != unacked_fec_packets_.end()) { - QuicPacketSequenceNumber sequence_number = it->first; - if (sequence_number > helper_->GetPeerLargestObservedPacket()) { - break; +bool QuicSentPacketManager::HasRetransmittableFrames( + QuicPacketSequenceNumber sequence_number) const { + if (!ContainsKey(unacked_packets_, sequence_number)) { + return false; + } + + DCHECK(ContainsKey(unacked_packets_, sequence_number)) << sequence_number; + + return unacked_packets_.find(sequence_number)->second != NULL; +} + +bool QuicSentPacketManager::IsPreviousTransmission( + QuicPacketSequenceNumber sequence_number) const { + DCHECK(ContainsKey(unacked_packets_, sequence_number)); + + PreviousTransmissionMap::const_iterator it = + previous_transmissions_map_.find(sequence_number); + if (it == previous_transmissions_map_.end()) { + return false; + } + + SequenceNumberSet* previous_transmissions = it->second; + DCHECK(!previous_transmissions->empty()); + return *previous_transmissions->rbegin() != sequence_number; +} + +QuicSentPacketManager::UnackedPacketMap::iterator +QuicSentPacketManager::MarkPacketReceivedByPeer( + QuicPacketSequenceNumber sequence_number) { + DCHECK(ContainsKey(unacked_packets_, sequence_number)); + UnackedPacketMap::iterator next_unacked = + unacked_packets_.find(sequence_number); + ++next_unacked; + + // If this packet has never been retransmitted, then simply drop it. + if (!ContainsKey(previous_transmissions_map_, sequence_number)) { + DiscardPacket(sequence_number); + return next_unacked; + } + + SequenceNumberSet* previous_transmissions = + previous_transmissions_map_.find(sequence_number)->second; + SequenceNumberSet::reverse_iterator previous_transmissions_it + = previous_transmissions->rbegin(); + DCHECK(previous_transmissions_it != previous_transmissions->rend()); + + QuicPacketSequenceNumber new_packet = *previous_transmissions_it; + bool is_new_packet = new_packet == sequence_number; + if (is_new_packet) { + DiscardPacket(new_packet); + } else { + if (next_unacked->first == new_packet) { + ++next_unacked; } - if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) { - DVLOG(1) << ENDPOINT << "Got an ack for fec packet: " << sequence_number; - acked_packets->insert(sequence_number); - unacked_fec_packets_.erase(it++); - } else { - DVLOG(1) << ENDPOINT << "Still missing ack for fec packet: " - << sequence_number; - ++it; + // If we have received an ack for a previous transmission of a packet, + // we want to keep the "new" transmission of the packet unacked, + // but prevent the data from being retransmitted. + delete unacked_packets_[new_packet]; + unacked_packets_[new_packet] = NULL; + } + previous_transmissions_map_.erase(new_packet); + + // Clear out information all previous transmissions. + ++previous_transmissions_it; + while (previous_transmissions_it != previous_transmissions->rend()) { + QuicPacketSequenceNumber previous_transmission = *previous_transmissions_it; + ++previous_transmissions_it; + DCHECK(ContainsKey(previous_transmissions_map_, previous_transmission)); + previous_transmissions_map_.erase(previous_transmission); + if (next_unacked != unacked_packets_.end() && + next_unacked->first == previous_transmission) { + ++next_unacked; } + DiscardPacket(previous_transmission); } + + delete previous_transmissions; + + next_unacked = unacked_packets_.begin(); + while (next_unacked != unacked_packets_.end() && + next_unacked->first < sequence_number) { + ++next_unacked; + } + return next_unacked; } void QuicSentPacketManager::DiscardPacket( QuicPacketSequenceNumber sequence_number) { UnackedPacketMap::iterator unacked_it = unacked_packets_.find(sequence_number); + // Packet was not meant to be retransmitted. if (unacked_it == unacked_packets_.end()) { - // Packet was not meant to be retransmitted. DCHECK(!ContainsKey(retransmission_map_, sequence_number)); return; } @@ -145,10 +306,43 @@ void QuicSentPacketManager::DiscardPacket( delete unacked_it->second; unacked_packets_.erase(unacked_it); retransmission_map_.erase(sequence_number); + return; +} + +void QuicSentPacketManager::HandleAckForSentFecPackets( + const ReceivedPacketInfo& received_info, + SequenceNumberSet* acked_packets) { + UnackedFecPacketMap::iterator it = unacked_fec_packets_.begin(); + while (it != unacked_fec_packets_.end()) { + QuicPacketSequenceNumber sequence_number = it->first; + if (sequence_number > received_info.largest_observed) { + break; + } + + if (!IsAwaitingPacket(received_info, sequence_number)) { + DVLOG(1) << ENDPOINT << "Got an ack for fec packet: " << sequence_number; + acked_packets->insert(sequence_number); + unacked_fec_packets_.erase(it++); + } else { + // TODO(rch): treat these packets more consistently. They should + // be subject to NACK and RTO based loss. (Thought obviously, they + // should not be retransmitted.) + DVLOG(1) << ENDPOINT << "Still missing ack for fec packet: " + << sequence_number; + ++it; + } + } +} + +void QuicSentPacketManager::DiscardFecPacket( + QuicPacketSequenceNumber sequence_number) { + DCHECK(ContainsKey(unacked_fec_packets_, sequence_number)); + unacked_fec_packets_.erase(sequence_number); } bool QuicSentPacketManager::IsRetransmission( QuicPacketSequenceNumber sequence_number) const { + DCHECK(HasRetransmittableFrames(sequence_number)); RetransmissionMap::const_iterator it = retransmission_map_.find(sequence_number); return it != retransmission_map_.end() && @@ -157,6 +351,7 @@ bool QuicSentPacketManager::IsRetransmission( size_t QuicSentPacketManager::GetRetransmissionCount( QuicPacketSequenceNumber sequence_number) const { + DCHECK(HasRetransmittableFrames(sequence_number)); DCHECK(ContainsKey(retransmission_map_, sequence_number)); RetransmissionMap::const_iterator it = retransmission_map_.find(sequence_number); @@ -190,6 +385,13 @@ QuicSequenceNumberLength QuicSentPacketManager::GetSequenceNumberLength( sequence_number)->second.sequence_number_length; } +QuicTime QuicSentPacketManager::GetFecSentTime( + QuicPacketSequenceNumber sequence_number) const { + DCHECK(ContainsKey(unacked_fec_packets_, sequence_number)); + + return unacked_fec_packets_.find(sequence_number)->second; +} + bool QuicSentPacketManager::HasUnackedPackets() const { return !unacked_packets_.empty(); } @@ -198,6 +400,10 @@ size_t QuicSentPacketManager::GetNumUnackedPackets() const { return unacked_packets_.size(); } +bool QuicSentPacketManager::HasUnackedFecPackets() const { + return !unacked_fec_packets_.empty(); +} + QuicPacketSequenceNumber QuicSentPacketManager::GetLeastUnackedSentPacket() const { if (unacked_packets_.empty()) { @@ -209,13 +415,26 @@ QuicSentPacketManager::GetLeastUnackedSentPacket() const { return unacked_packets_.begin()->first; } -SequenceNumberSet QuicSentPacketManager::GetUnackedPackets() const { - SequenceNumberSet unacked_packets; +QuicPacketSequenceNumber +QuicSentPacketManager::GetLeastUnackedFecPacket() const { + if (unacked_fec_packets_.empty()) { + // If there are no unacked packets, set the least unacked packet to + // the sequence number of the next packet sent. + return helper_->GetNextPacketSequenceNumber(); + } + + return unacked_fec_packets_.begin()->first; +} + +SequenceNumberSet QuicSentPacketManager::GetRetransmittablePackets() const { + SequenceNumberSet retransmittable_packets; for (UnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it) { - unacked_packets.insert(it->first); + if (HasRetransmittableFrames(it->first)) { + retransmittable_packets.insert(it->first); + } } - return unacked_packets; + return retransmittable_packets; } } // namespace net diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 355ea49..c8ca6da 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -17,19 +17,31 @@ #include "net/base/linked_hash_map.h" #include "net/quic/quic_protocol.h" +NET_EXPORT extern bool FLAGS_track_retransmission_history; + namespace net { +// Class which tracks the set of packets sent on a QUIC connection. +// It keeps track of the retransmittable data ssociated with each +// packets. If a packet is retransmitted, it will keep track of each +// version of a packet so that if a previous transmission is acked, +// the data will not be retransmitted. class NET_EXPORT_PRIVATE QuicSentPacketManager { public: + // Interface which provides callbacks that the manager needs. class NET_EXPORT_PRIVATE HelperInterface { public: - virtual QuicPacketSequenceNumber GetPeerLargestObservedPacket() = 0; + virtual ~HelperInterface(); + + // Called to return the sequence number of the next packet to be sent. virtual QuicPacketSequenceNumber GetNextPacketSequenceNumber() = 0; - // Called when a packet has been explicitly NACKd + // Called when a packet has been explicitly NACK'd. If a packet + // has been retransmitted with mutliple sequence numbers, this will + // only be called for the sequence number (if any) associated with + // retransmittable frames. virtual void OnPacketNacked(QuicPacketSequenceNumber sequence_number, size_t nack_count) = 0; - virtual ~HelperInterface(); }; QuicSentPacketManager(bool is_server, HelperInterface* helper); @@ -37,7 +49,8 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { // Called when a new packet is serialized. If the packet contains // retransmittable data, it will be added to the unacked packet map. - void OnSerializedPacket(const SerializedPacket& serialized_packet); + void OnSerializedPacket(const SerializedPacket& serialized_packet, + QuicTime serialized_time); // Called when a packet is retransmitted with a new sequence number. // Replaces the old entry in the unacked packet map with the new @@ -45,16 +58,18 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { void OnRetransmittedPacket(QuicPacketSequenceNumber old_sequence_number, QuicPacketSequenceNumber new_sequence_number); - // Process the incoming ack looking for newly ack'd data packets. - void HandleAckForSentPackets(const QuicAckFrame& incoming_ack, - SequenceNumberSet* acked_packets); + // Processes the ReceivedPacketInfo data from the incoming ack. + void OnIncomingAck(const ReceivedPacketInfo& received_info, + bool is_truncated_ack, + SequenceNumberSet* acked_packets); - // Process the incoming ack looking for newly ack'd FEC packets. - void HandleAckForSentFecPackets(const QuicAckFrame& incoming_ack, - SequenceNumberSet* acked_packets); + // Discards any information for the packet corresponding to |sequence_number|. + // If this packet has been retransmitted, information on those packets + // will be discarded as well. + void DiscardUnackedPacket(QuicPacketSequenceNumber sequence_number); - // Discards all information about packet |sequence_number|. - void DiscardPacket(QuicPacketSequenceNumber sequence_number); + // Discards all information about fec packet |sequence_number|. + void DiscardFecPacket(QuicPacketSequenceNumber sequence_number); // Returns true if |sequence_number| is a retransmission of a packet. bool IsRetransmission(QuicPacketSequenceNumber sequence_number) const; @@ -70,6 +85,12 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { // Returns true if the FEC packet |sequence_number| is unacked. bool IsFecUnacked(QuicPacketSequenceNumber sequence_number) const; + // Returns true if the unacked packet |sequence_number| has retransmittable + // frames. This will only return false if the packet has been acked, if a + // previous transmission of this packet was ACK'd, or if this packet has been + // retransmitted as with different sequence number. + bool HasRetransmittableFrames(QuicPacketSequenceNumber sequence_number) const; + // Returns the RetransmittableFrames for |sequence_number|. const RetransmittableFrames& GetRetransmittableFrames( QuicPacketSequenceNumber sequence_number) const; @@ -79,19 +100,37 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { QuicSequenceNumberLength GetSequenceNumberLength( QuicPacketSequenceNumber sequence_number) const; + // Returns the time the fec packet was sent. + QuicTime GetFecSentTime(QuicPacketSequenceNumber sequence_number) const; + // Returns true if there are any unacked packets. bool HasUnackedPackets() const; // Returns the number of unacked packets. size_t GetNumUnackedPackets() const; - // Returns the smallest sequence number of a sent packet which has not - // been acked by the peer. If all packets have been acked, returns the + // Returns true if there are any unacked FEC packets. + bool HasUnackedFecPackets() const; + + // Returns the smallest sequence number of a sent packet which has not been + // acked by the peer. Excludes any packets which have been retransmitted + // with a new sequence number. If all packets have been acked, returns the // sequence number of the next packet that will be sent. QuicPacketSequenceNumber GetLeastUnackedSentPacket() const; - // Returns the set of unacked packet sequence numbers. - SequenceNumberSet GetUnackedPackets() const; + // Returns the smallest sequence number of a sent fec packet which has not + // been acked by the peer. If all packets have been acked, returns the + // sequence number of the next packet that will be sent. + QuicPacketSequenceNumber GetLeastUnackedFecPacket() const; + + // Returns the set of sequence numbers of all unacked packets with data + // that might need to be retransmitted. This excludes all packets which are + // previous transmissions of other packets, and all packets whose previous + // transmissions have been acked. + SequenceNumberSet GetRetransmittablePackets() const; + + // Returns true if |sequence_number| is a previous transmission of packet. + bool IsPreviousTransmission(QuicPacketSequenceNumber sequence_number) const; private: struct RetransmissionInfo { @@ -107,29 +146,67 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { QuicPacketSequenceNumber sequence_number; QuicSequenceNumberLength sequence_number_length; size_t number_nacks; + // TODO(ianswett): I believe this is now obsolete, or could at least be + // changed to a bool. size_t number_retransmissions; }; typedef linked_hash_map<QuicPacketSequenceNumber, RetransmittableFrames*> UnackedPacketMap; + typedef linked_hash_map<QuicPacketSequenceNumber, + QuicTime> UnackedFecPacketMap; typedef base::hash_map<QuicPacketSequenceNumber, RetransmissionInfo> RetransmissionMap; + typedef base::hash_map<QuicPacketSequenceNumber, SequenceNumberSet*> + PreviousTransmissionMap; + + // Process the incoming ack looking for newly ack'd data packets. + void HandleAckForSentPackets(const ReceivedPacketInfo& received_info, + bool is_truncated_ack, + SequenceNumberSet* acked_packets); + + // Process the incoming ack looking for newly ack'd FEC packets. + void HandleAckForSentFecPackets(const ReceivedPacketInfo& received_info, + SequenceNumberSet* acked_packets); + + // Marks |sequence_number| as having been seen by the peer. Returns an + // iterator to the next remaining unacked packet. + UnackedPacketMap::iterator MarkPacketReceivedByPeer( + QuicPacketSequenceNumber sequence_number); + + // Simply removes the entries, if any, from the unacked packet map + // and the retransmission map. + void DiscardPacket(QuicPacketSequenceNumber sequence_number); // When new packets are created which may be retransmitted, they are added - // to this map, which contains owning pointers to the contained frames. + // to this map, which contains owning pointers to the contained frames. If + // a packet is retransmitted, this map will contain entries for both the old + // and the new packet. The old packet's retransmittable frames entry will be + // NULL, while the new packet's entry will contain the frames to retransmit. + // If the old packet is acked before the new packet, then the old entry will + // be removed from the map and the new entry's retransmittable frames will be + // set to NULL. UnackedPacketMap unacked_packets_; // Pending fec packets that have not been acked yet. These packets need to be // cleared out of the cgst_window after a timeout since FEC packets are never // retransmitted. - // TODO(satyamshekhar): What should be the timeout for these packets? - UnackedPacketMap unacked_fec_packets_; + UnackedFecPacketMap unacked_fec_packets_; - // Map from sequence number to the retransmission info. + // Map from sequence number to the retransmission info for a packet. + // This includes the retransmission timeout, and the NACK count. Only + // the new transmission of a packet will have entries in this map. RetransmissionMap retransmission_map_; + // Map from sequence number to set of all sequence number that this packet has + // been transmitted as. If a packet has not been retransmitted, it will not + // have an entry in this map. If any transmission of a packet has been acked + // it will not have an entry in this map. + PreviousTransmissionMap previous_transmissions_map_; + // Tracks if the connection was created by the server. bool is_server_; + HelperInterface* helper_; DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager); diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index 8f5cb3d..6bc8eaf 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc @@ -4,10 +4,12 @@ #include "net/quic/quic_sent_packet_manager.h" +#include "base/stl_util.h" #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using std::vector; using testing::_; using testing::Return; using testing::StrictMock; @@ -18,63 +20,417 @@ namespace { class MockHelper : public QuicSentPacketManager::HelperInterface { public: - MOCK_METHOD0(GetPeerLargestObservedPacket, QuicPacketSequenceNumber()); MOCK_METHOD0(GetNextPacketSequenceNumber, QuicPacketSequenceNumber()); MOCK_METHOD2(OnPacketNacked, void(QuicPacketSequenceNumber sequence_number, size_t nack_count)); }; -class QuicSentPacketManagerTest : public ::testing::Test { +class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { protected: QuicSentPacketManagerTest() : manager_(true, &helper_) { } + void SetUp() { + FLAGS_track_retransmission_history = GetParam(); + } + + ~QuicSentPacketManagerTest() { + STLDeleteElements(&packets_); + } + + + void VerifyUnackedPackets(QuicPacketSequenceNumber* packets, + size_t num_packets) { + if (num_packets == 0) { + EXPECT_FALSE(manager_.HasUnackedPackets()); + EXPECT_EQ(0u, manager_.GetNumUnackedPackets()); + EXPECT_TRUE(manager_.GetRetransmittablePackets().empty()); + return; + } + + EXPECT_TRUE(manager_.HasUnackedPackets()); + EXPECT_EQ(packets[0], manager_.GetLeastUnackedSentPacket()); + for (size_t i = 0; i < num_packets; ++i) { + EXPECT_TRUE(manager_.IsUnacked(packets[i])) << packets[i]; + } + } + + void VerifyRetransmittablePackets(QuicPacketSequenceNumber* packets, + size_t num_packets) { + SequenceNumberSet unacked = manager_.GetRetransmittablePackets(); + EXPECT_EQ(num_packets, unacked.size()); + for (size_t i = 0; i < num_packets; ++i) { + EXPECT_TRUE(ContainsKey(unacked, packets[i])) << packets[i]; + } + } + + SerializedPacket CreatePacket(QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewDataPacket( + NULL, 0, false, PACKET_8BYTE_GUID, false, + PACKET_6BYTE_SEQUENCE_NUMBER)); + return SerializedPacket(sequence_number, PACKET_6BYTE_SEQUENCE_NUMBER, + packets_.back(), 0u, new RetransmittableFrames()); + } + + SerializedPacket CreateFecPacket(QuicPacketSequenceNumber sequence_number) { + packets_.push_back(QuicPacket::NewFecPacket( + NULL, 0, false, PACKET_8BYTE_GUID, false, + PACKET_6BYTE_SEQUENCE_NUMBER)); + return SerializedPacket(sequence_number, PACKET_6BYTE_SEQUENCE_NUMBER, + packets_.back(), 0u, NULL); + } + testing::StrictMock<MockHelper> helper_; QuicSentPacketManager manager_; + vector<QuicPacket*> packets_; }; -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacket) { +INSTANTIATE_TEST_CASE_P(TrackRetransmissionHistory, + QuicSentPacketManagerTest, + ::testing::Values(false, true)); + +TEST_P(QuicSentPacketManagerTest, IsUnacked) { + VerifyUnackedPackets(NULL, 0); + + SerializedPacket serialized_packet(CreatePacket(1)); + + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + + QuicPacketSequenceNumber unacked[] = { 1 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 1 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); +} + +TEST_P(QuicSentPacketManagerTest, IsUnAckedRetransmit) { + if (!FLAGS_track_retransmission_history) { + // This tests restransmission tracking specifically. + return; + } + SerializedPacket serialized_packet(CreatePacket(1)); + + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + manager_.OnRetransmittedPacket(1, 2); + + EXPECT_TRUE(manager_.IsRetransmission(2)); + EXPECT_EQ(1u, manager_.GetRetransmissionCount(2)); + QuicPacketSequenceNumber unacked[] = { 1, 2 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 2 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + + manager_.OnRetransmittedPacket(2, 3); + EXPECT_TRUE(manager_.IsRetransmission(3)); + EXPECT_EQ(2u, manager_.GetRetransmissionCount(3)); + QuicPacketSequenceNumber unacked2[] = { 1, 2, 3 }; + VerifyUnackedPackets(unacked2, arraysize(unacked2)); + QuicPacketSequenceNumber retransmittable2[] = { 3 }; + VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2)); +} + +TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { + SerializedPacket serialized_packet(CreatePacket(1)); + + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + manager_.OnRetransmittedPacket(1, 2); + + // Ack 2 but not 1. + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + received_info.missing_packets.insert(1); + SequenceNumberSet acked; + manager_.OnIncomingAck(received_info, false, &acked); + + // No unacked packets remain. + VerifyUnackedPackets(NULL, 0); + VerifyRetransmittablePackets(NULL, 0); +} + +TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { + if (!FLAGS_track_retransmission_history) { + // This tests restransmission tracking specifically. + return; + } + SerializedPacket serialized_packet(CreatePacket(1)); + + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + manager_.OnRetransmittedPacket(1, 2); + + // Ack 1 but not 2. + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + received_info.missing_packets.insert(2); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(2, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + // 2 remains unacked, but no packets have retransmittable data. + QuicPacketSequenceNumber unacked[] = { 2 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyRetransmittablePackets(NULL, 0); +} + +TEST_P(QuicSentPacketManagerTest, TruncatedAck) { + if (!FLAGS_track_retransmission_history) { + // This tests restransmission tracking specifically. + return; + } + SerializedPacket serialized_packet(CreatePacket(1)); + + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + manager_.OnRetransmittedPacket(1, 2); + manager_.OnRetransmittedPacket(2, 3); + manager_.OnRetransmittedPacket(3, 4); + + // Truncated ack with 2 NACKs + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + received_info.missing_packets.insert(1); + received_info.missing_packets.insert(2); + SequenceNumberSet acked; + manager_.OnIncomingAck(received_info, true, &acked); + + // High water mark will be raised. + QuicPacketSequenceNumber unacked[] = { 2, 3, 4 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 4 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); +} + +TEST_P(QuicSentPacketManagerTest, SendDropAckRetransmitManyPackets) { + if (!FLAGS_track_retransmission_history) { + // This tests restransmission tracking specifically. + return; + } + manager_.OnSerializedPacket(CreatePacket(1), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(2), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(3), QuicTime::Zero()); + + { + // Ack packets 1 and 3. + ReceivedPacketInfo received_info; + received_info.largest_observed = 3; + received_info.missing_packets.insert(2); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(2, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + QuicPacketSequenceNumber unacked[] = { 2 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 2 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } + + manager_.OnSerializedPacket(CreatePacket(4), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(5), QuicTime::Zero()); + + { + // Ack packets 5. + ReceivedPacketInfo received_info; + received_info.largest_observed = 5; + received_info.missing_packets.insert(2); + received_info.missing_packets.insert(4); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(2, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(4, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + QuicPacketSequenceNumber unacked[] = { 2, 4 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 2, 4 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } + + manager_.OnSerializedPacket(CreatePacket(6), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(7), QuicTime::Zero()); + + { + // Ack packets 7. + ReceivedPacketInfo received_info; + received_info.largest_observed = 7; + received_info.missing_packets.insert(2); + received_info.missing_packets.insert(4); + received_info.missing_packets.insert(6); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(2, 3)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(4, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(6, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + QuicPacketSequenceNumber unacked[] = { 2, 4, 6 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 2, 4, 6 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } + + manager_.OnRetransmittedPacket(2, 8); + manager_.OnSerializedPacket(CreatePacket(9), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(10), QuicTime::Zero()); + + { + // Ack packet 10. + ReceivedPacketInfo received_info; + received_info.largest_observed = 10; + received_info.missing_packets.insert(2); + received_info.missing_packets.insert(4); + received_info.missing_packets.insert(6); + received_info.missing_packets.insert(8); + received_info.missing_packets.insert(9); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(4, 3)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(6, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(8, 1)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(9, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + QuicPacketSequenceNumber unacked[] = { 2, 4, 6, 8, 9 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 4, 6, 8, 9 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } + + + manager_.OnRetransmittedPacket(4, 11); + manager_.OnSerializedPacket(CreatePacket(12), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(13), QuicTime::Zero()); + + { + // Ack packet 13. + ReceivedPacketInfo received_info; + received_info.largest_observed = 13; + received_info.missing_packets.insert(2); + received_info.missing_packets.insert(4); + received_info.missing_packets.insert(6); + received_info.missing_packets.insert(8); + received_info.missing_packets.insert(9); + received_info.missing_packets.insert(11); + received_info.missing_packets.insert(12); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(6, 3)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(8, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(9, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(11, 1)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(12, 1)).Times(1); + manager_.OnIncomingAck(received_info, false, &acked); + + QuicPacketSequenceNumber unacked[] = { 2, 4, 6, 8, 9, 11, 12 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 6, 8, 9, 11, 12 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } + + manager_.OnRetransmittedPacket(6, 14); + manager_.OnSerializedPacket(CreatePacket(15), QuicTime::Zero()); + manager_.OnSerializedPacket(CreatePacket(16), QuicTime::Zero()); + + { + // Ack packet 16. + ReceivedPacketInfo received_info; + received_info.largest_observed = 13; + received_info.missing_packets.insert(2); + received_info.missing_packets.insert(4); + received_info.missing_packets.insert(6); + received_info.missing_packets.insert(8); + received_info.missing_packets.insert(9); + received_info.missing_packets.insert(11); + received_info.missing_packets.insert(12); + SequenceNumberSet acked; + EXPECT_CALL(helper_, OnPacketNacked(8, 3)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(9, 3)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(11, 2)).Times(1); + EXPECT_CALL(helper_, OnPacketNacked(12, 2)).Times(1); + manager_.OnIncomingAck(received_info, true, &acked); + + // Truncated ack raises the high water mark by clearing out 2, 4, and 6. + QuicPacketSequenceNumber unacked[] = { 8, 9, 11, 12, 14, 15, 16 }; + VerifyUnackedPackets(unacked, arraysize(unacked)); + QuicPacketSequenceNumber retransmittable[] = { 8, 9, 11, 12, 14, 15, 16 }; + VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + } +} + +TEST_P(QuicSentPacketManagerTest, GetLeastUnackedSentPacket) { EXPECT_CALL(helper_, GetNextPacketSequenceNumber()).WillOnce(Return(1u)); EXPECT_EQ(1u, manager_.GetLeastUnackedSentPacket()); } -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacketUnacked) { - scoped_ptr<QuicPacket> packet(QuicPacket::NewDataPacket( - NULL, 0, false, PACKET_8BYTE_GUID, false, PACKET_6BYTE_SEQUENCE_NUMBER)); - SerializedPacket serialized_packet(1u, PACKET_6BYTE_SEQUENCE_NUMBER, - packet.get(), 7u, - new RetransmittableFrames()); +TEST_P(QuicSentPacketManagerTest, GetLeastUnackedSentPacketUnacked) { + SerializedPacket serialized_packet(CreatePacket(1)); - manager_.OnSerializedPacket(serialized_packet); + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); EXPECT_EQ(1u, manager_.GetLeastUnackedSentPacket()); } -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacketUnackedFec) { - scoped_ptr<QuicPacket> packet(QuicPacket::NewFecPacket( - NULL, 0, false, PACKET_8BYTE_GUID, false, PACKET_6BYTE_SEQUENCE_NUMBER)); - SerializedPacket serialized_packet(1u, PACKET_6BYTE_SEQUENCE_NUMBER, - packet.get(), 7u, NULL); +TEST_P(QuicSentPacketManagerTest, GetLeastUnackedSentPacketUnackedFec) { + SerializedPacket serialized_packet(CreateFecPacket(1)); - manager_.OnSerializedPacket(serialized_packet); + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); // FEC packets do not count as "unacked". EXPECT_CALL(helper_, GetNextPacketSequenceNumber()).WillOnce(Return(2u)); EXPECT_EQ(2u, manager_.GetLeastUnackedSentPacket()); } -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacketDiscardUnacked) { - scoped_ptr<QuicPacket> packet(QuicPacket::NewDataPacket( - NULL, 0, false, PACKET_8BYTE_GUID, false, PACKET_6BYTE_SEQUENCE_NUMBER)); - SerializedPacket serialized_packet(1u, PACKET_6BYTE_SEQUENCE_NUMBER, - packet.get(), 7u, - new RetransmittableFrames()); +TEST_P(QuicSentPacketManagerTest, GetLeastUnackedSentPacketDiscardUnacked) { + SerializedPacket serialized_packet(CreatePacket(1)); - manager_.OnSerializedPacket(serialized_packet); - manager_.DiscardPacket(1u); + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + manager_.DiscardUnackedPacket(1u); EXPECT_CALL(helper_, GetNextPacketSequenceNumber()).WillOnce(Return(2u)); EXPECT_EQ(2u, manager_.GetLeastUnackedSentPacket()); } +TEST_P(QuicSentPacketManagerTest, GetLeastUnackedFecPacketAndDiscard) { + VerifyUnackedPackets(NULL, 0); + + SerializedPacket serialized_packet(CreateFecPacket(1)); + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + EXPECT_EQ(1u, manager_.GetLeastUnackedFecPacket()); + + SerializedPacket serialized_packet2(CreateFecPacket(2)); + manager_.OnSerializedPacket(serialized_packet2, QuicTime::Zero()); + EXPECT_EQ(1u, manager_.GetLeastUnackedFecPacket()); + + SerializedPacket serialized_packet3(CreateFecPacket(3)); + manager_.OnSerializedPacket(serialized_packet3, QuicTime::Zero()); + EXPECT_EQ(1u, manager_.GetLeastUnackedFecPacket()); + + VerifyUnackedPackets(NULL, 0); + VerifyRetransmittablePackets(NULL, 0); + + manager_.DiscardFecPacket(1); + EXPECT_EQ(2u, manager_.GetLeastUnackedFecPacket()); + + // Ack 2. + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + SequenceNumberSet acked; + manager_.OnIncomingAck(received_info, false, &acked); + + EXPECT_EQ(3u, manager_.GetLeastUnackedFecPacket()); + + // Discard the 3rd packet and ensure there are no FEC packets. + manager_.DiscardFecPacket(3); + EXPECT_FALSE(manager_.HasUnackedFecPackets()); +} + +TEST_P(QuicSentPacketManagerTest, GetFecSentTime) { + VerifyUnackedPackets(NULL, 0); + + SerializedPacket serialized_packet(CreateFecPacket(1)); + manager_.OnSerializedPacket(serialized_packet, QuicTime::Zero()); + SerializedPacket serialized_packet2(CreateFecPacket(2)); + QuicTime sent_time = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(1)); + manager_.OnSerializedPacket(serialized_packet2, sent_time); + + VerifyUnackedPackets(NULL, 0); + VerifyRetransmittablePackets(NULL, 0); + + EXPECT_TRUE(manager_.HasUnackedFecPackets()); + EXPECT_EQ(QuicTime::Zero(), manager_.GetFecSentTime(1)); + EXPECT_EQ(sent_time, manager_.GetFecSentTime(2)); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_spdy_compressor.cc b/net/quic/quic_spdy_compressor.cc index 6681493b..0a1bfb4 100644 --- a/net/quic/quic_spdy_compressor.cc +++ b/net/quic/quic_spdy_compressor.cc @@ -28,7 +28,8 @@ string QuicSpdyCompressor::CompressHeadersWithPriority( string QuicSpdyCompressor::CompressHeaders( const SpdyHeaderBlock& headers) { - return CompressHeadersInternal(0, headers, false); + // CompressHeadersInternal ignores priority when write_priority is false. + return CompressHeadersInternal(0 /* ignored */, headers, false); } string QuicSpdyCompressor::CompressHeadersInternal( diff --git a/net/quic/quic_spdy_compressor.h b/net/quic/quic_spdy_compressor.h index 53a7060..6efb73c 100644 --- a/net/quic/quic_spdy_compressor.h +++ b/net/quic/quic_spdy_compressor.h @@ -15,6 +15,7 @@ namespace net { // Handles the compression of request/response headers blocks. The // serialized format is: +// uint32 - Priority // uint32 - Header ID // uint32 - Compressed header length // ... - Compressed data diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 41cb457..dea1e81 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -483,9 +483,7 @@ uint32 ReliableQuicStream::StripPriorityAndHeaderId( const char* data, uint32 data_len) { uint32 total_bytes_parsed = 0; - if (!priority_parsed_ && - session_->connection()->version() >= QUIC_VERSION_9 && - session_->connection()->is_server()) { + if (!priority_parsed_ && session_->connection()->is_server()) { QuicPriority temporary_priority = priority_; total_bytes_parsed = StripUint32( data, data_len, &headers_id_and_priority_buffer_, &temporary_priority); diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 5d715db..a1d5b34 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -50,14 +50,14 @@ QuicPacketCreator* QuicConnectionPeer::GetPacketCreator( return &connection->packet_creator_; } -bool QuicConnectionPeer::GetReceivedTruncatedAck(QuicConnection* connection) { - return connection->received_truncated_ack_; -} - // static -size_t QuicConnectionPeer::GetNumRetransmissionTimeouts( +QuicCongestionManager* QuicConnectionPeer::GetCongestionManager( QuicConnection* connection) { - return connection->retransmission_timeouts_.size(); + return &connection->congestion_manager_; +} + +bool QuicConnectionPeer::GetReceivedTruncatedAck(QuicConnection* connection) { + return connection->received_truncated_ack_; } // static @@ -70,7 +70,9 @@ QuicTime::Delta QuicConnectionPeer::GetNetworkTimeout( bool QuicConnectionPeer::IsSavedForRetransmission( QuicConnection* connection, QuicPacketSequenceNumber sequence_number) { - return connection->sent_packet_manager_.IsUnacked(sequence_number); + return connection->sent_packet_manager_.IsUnacked(sequence_number) && + connection->sent_packet_manager_.HasRetransmittableFrames( + sequence_number); } // static @@ -137,13 +139,6 @@ void QuicConnectionPeer::SwapCrypters(QuicConnection* connection, } // static -void QuicConnectionPeer:: SetMaxPacketsPerRetransmissionAlarm( - QuicConnection* connection, - int max_packets) { - connection->max_packets_per_retransmission_alarm_ = max_packets; -} - -// static QuicConnectionHelperInterface* QuicConnectionPeer::GetHelper( QuicConnection* connection) { return connection->helper_.get(); diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 13ff14d..8aac031 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -15,6 +15,7 @@ namespace net { struct QuicAckFrame; struct QuicPacketHeader; class QuicAlarm; +class QuicCongestionManager; class QuicConnection; class QuicConnectionHelperInterface; class QuicConnectionVisitorInterface; @@ -44,9 +45,10 @@ class QuicConnectionPeer { static QuicPacketCreator* GetPacketCreator(QuicConnection* connection); - static bool GetReceivedTruncatedAck(QuicConnection* connection); + static QuicCongestionManager* GetCongestionManager( + QuicConnection* connection); - static size_t GetNumRetransmissionTimeouts(QuicConnection* connection); + static bool GetReceivedTruncatedAck(QuicConnection* connection); static QuicTime::Delta GetNetworkTimeout(QuicConnection* connection); @@ -83,9 +85,6 @@ class QuicConnectionPeer { static void SwapCrypters(QuicConnection* connection, QuicFramer* framer); - static void SetMaxPacketsPerRetransmissionAlarm(QuicConnection* connection, - int max_packets); - static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection); static QuicFramer* GetFramer(QuicConnection* connection); diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 8ba46b8..f32b761 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -244,6 +244,7 @@ bool PacketSavingConnection::SendOrQueuePacket( QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash /* entropy_hash */, + TransmissionType /* transmission_type */, HasRetransmittableData /* retransmittable */, Force /* forced */) { packets_.push_back(packet); diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 64a9d30..a2d8989 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -262,6 +262,7 @@ class PacketSavingConnection : public MockConnection { QuicPacketSequenceNumber sequence_number, QuicPacket* packet, QuicPacketEntropyHash entropy_hash, + TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data, Force forced) OVERRIDE; @@ -331,10 +332,10 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_METHOD1(OnIncomingLoss, void(QuicTime)); MOCK_METHOD5(SentPacket, bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount, - Retransmission, HasRetransmittableData)); + TransmissionType, HasRetransmittableData)); MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes)); - MOCK_METHOD4(TimeUntilSend, QuicTime::Delta(QuicTime now, Retransmission, + MOCK_METHOD4(TimeUntilSend, QuicTime::Delta(QuicTime now, TransmissionType, HasRetransmittableData, IsHandshake)); MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void)); |