diff options
59 files changed, 1058 insertions, 334 deletions
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 83d6bb7..837de5f 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h @@ -1460,6 +1460,12 @@ EVENT_TYPE(QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED) // } EVENT_TYPE(QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED) +// Session sucessfully negotiated QUIC version number. +// { +// "version": <String of QUIC version negotiated with the server>, +// } +EVENT_TYPE(QUIC_SESSION_VERSION_NEGOTIATED) + // Session revived a QUIC packet packet via FEC. // { // "guid": <The 64-bit GUID for this connection, as a base-10 string>, diff --git a/net/net.gyp b/net/net.gyp index 1cce2a6..f8cb550 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -825,6 +825,8 @@ 'quic/quic_framer.h', 'quic/quic_http_stream.cc', 'quic/quic_http_stream.h', + 'quic/quic_http_utils.cc', + 'quic/quic_http_utils.h', 'quic/quic_packet_creator.cc', 'quic/quic_packet_creator.h', 'quic/quic_packet_generator.cc', @@ -1768,6 +1770,7 @@ 'quic/quic_fec_group_test.cc', 'quic/quic_framer_test.cc', 'quic/quic_http_stream_test.cc', + 'quic/quic_http_utils_test.cc', 'quic/quic_network_transaction_unittest.cc', 'quic/quic_packet_creator_test.cc', 'quic/quic_packet_generator_test.cc', diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 22f759f..99aa10f 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -60,15 +60,18 @@ void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { // Ignore losses for fix rate sender. } -void FixRateSender::SentPacket(QuicTime sent_time, - QuicPacketSequenceNumber /*sequence_number*/, - QuicByteCount bytes, - Retransmission is_retransmission) { +bool FixRateSender::SentPacket( + QuicTime sent_time, + QuicPacketSequenceNumber /*sequence_number*/, + QuicByteCount bytes, + Retransmission is_retransmission, + HasRetransmittableData /*has_retransmittable_data*/) { fix_rate_leaky_bucket_.Add(sent_time, bytes); paced_sender_.SentPacket(sent_time, bytes); if (is_retransmission == NOT_RETRANSMISSION) { data_in_flight_ += bytes; } + return true; } void FixRateSender::AbandoningPacket( diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 38cebad1..781dead 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -32,10 +32,12 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { QuicByteCount acked_bytes, QuicTime::Delta rtt) OVERRIDE; virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE; - virtual void SentPacket(QuicTime sent_time, - QuicPacketSequenceNumber equence_number, - QuicByteCount bytes, - Retransmission is_retransmission) OVERRIDE; + virtual bool SentPacket( + QuicTime sent_time, + QuicPacketSequenceNumber equence_number, + QuicByteCount bytes, + Retransmission is_retransmission, + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index f914ed6..e316f65 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -63,11 +63,14 @@ TEST_F(FixRateTest, SenderAPI) { EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond()); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION); + sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION); - sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION); + sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); + sender_->SentPacket(clock_.Now(), 3, 600, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); @@ -98,12 +101,12 @@ TEST_F(FixRateTest, FixRatePacing) { NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, - NOT_RETRANSMISSION); + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, - NOT_RETRANSMISSION); + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); clock_.AdvanceTime(advance_time); diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc index 3afa378..5640a73 100644 --- a/net/quic/congestion_control/inter_arrival_sender.cc +++ b/net/quic/congestion_control/inter_arrival_sender.cc @@ -235,14 +235,17 @@ void InterArrivalSender::OnIncomingLoss(QuicTime ack_receive_time) { } } -void InterArrivalSender::SentPacket(QuicTime sent_time, - QuicPacketSequenceNumber sequence_number, - QuicByteCount bytes, - Retransmission /*retransmit*/) { +bool InterArrivalSender::SentPacket( + QuicTime sent_time, + QuicPacketSequenceNumber sequence_number, + QuicByteCount bytes, + Retransmission /*is_retransmit*/, + HasRetransmittableData /*has_retransmittable_data*/) { if (probing_) { probe_->OnSentPacket(bytes); } paced_sender_->SentPacket(sent_time, bytes); + return true; } void InterArrivalSender::AbandoningPacket( diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h index ad28ecd..2c455cc 100644 --- a/net/quic/congestion_control/inter_arrival_sender.h +++ b/net/quic/congestion_control/inter_arrival_sender.h @@ -43,10 +43,12 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE; - virtual void SentPacket(QuicTime sent_time, - QuicPacketSequenceNumber sequence_number, - QuicByteCount bytes, - Retransmission is_retransmit) OVERRIDE; + virtual bool SentPacket( + QuicTime sent_time, + QuicPacketSequenceNumber sequence_number, + QuicByteCount bytes, + Retransmission is_retransmit, + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; diff --git a/net/quic/congestion_control/inter_arrival_sender_test.cc b/net/quic/congestion_control/inter_arrival_sender_test.cc index d0faca0..7392b1a 100644 --- a/net/quic/congestion_control/inter_arrival_sender_test.cc +++ b/net/quic/congestion_control/inter_arrival_sender_test.cc @@ -41,7 +41,7 @@ class InterArrivalSenderTest : public ::testing::Test { bytes_in_packet, send_clock_.Now()); sender_.SentPacket(send_clock_.Now(), sequence_number_, bytes_in_packet, - NOT_RETRANSMISSION); + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); sequence_number_++; } EXPECT_FALSE(sender_.TimeUntilSend(send_clock_.Now(), diff --git a/net/quic/congestion_control/quic_congestion_control_test.cc b/net/quic/congestion_control/quic_congestion_control_test.cc index 0051aca..457538f 100644 --- a/net/quic/congestion_control/quic_congestion_control_test.cc +++ b/net/quic/congestion_control/quic_congestion_control_test.cc @@ -49,7 +49,8 @@ TEST_F(QuicCongestionControlTest, FixedRateSenderAPI) { clock_.Now()); EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(1, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION); + manager_->SentPacket(1, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40), manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); @@ -78,7 +79,8 @@ TEST_F(QuicCongestionControlTest, FixedRatePacing) { for (QuicPacketSequenceNumber i = 1; i <= 100; ++i) { EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(i, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION); + manager_->SentPacket(i, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); QuicTime::Delta advance_time = manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); clock_.AdvanceTime(advance_time); @@ -108,10 +110,12 @@ TEST_F(QuicCongestionControlTest, Pacing) { for (QuicPacketSequenceNumber i = 1; i <= 100;) { EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION); + manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); EXPECT_TRUE(manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION); + manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); QuicTime::Delta advance_time = manager_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); clock_.AdvanceTime(advance_time); diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc index ba6bab8..ec519db 100644 --- a/net/quic/congestion_control/quic_congestion_manager.cc +++ b/net/quic/congestion_control/quic_congestion_manager.cc @@ -48,18 +48,21 @@ QuicCongestionManager::~QuicCongestionManager() { STLDeleteValues(&packet_history_map_); } -void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number, - QuicTime sent_time, - QuicByteCount bytes, - Retransmission retransmission) { +void QuicCongestionManager::SentPacket( + QuicPacketSequenceNumber sequence_number, + QuicTime sent_time, + QuicByteCount bytes, + Retransmission retransmission, + HasRetransmittableData has_retransmittable_data) { DCHECK(!ContainsKey(pending_packets_, sequence_number)); - send_algorithm_->SentPacket(sent_time, sequence_number, bytes, - retransmission); - packet_history_map_[sequence_number] = - new class SendAlgorithmInterface::SentPacket(bytes, sent_time); - pending_packets_[sequence_number] = bytes; - CleanupPacketHistory(); + if (send_algorithm_->SentPacket(sent_time, sequence_number, bytes, + retransmission, has_retransmittable_data)) { + packet_history_map_[sequence_number] = + new class SendAlgorithmInterface::SentPacket(bytes, sent_time); + pending_packets_[sequence_number] = bytes; + CleanupPacketHistory(); + } } // Called when a packet is timed out. @@ -156,6 +159,23 @@ const QuicTime::Delta QuicCongestionManager::DefaultRetransmissionTime() { return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs); } +// Ensures that the Delayed Ack timer is always set to a value lesser +// than the retransmission timer's minimum value (MinRTO). We want the +// delayed ack to get back to the QUIC peer before the sender's +// retransmission timer triggers. Since we do not know the +// reverse-path one-way delay, we assume equal delays for forward and +// reverse paths, and ensure that the timer is set to less than half +// of the MinRTO. +// There may be a value in making this delay adaptive with the help of +// the sender and a signaling mechanism -- if the sender uses a +// different MinRTO, we may get spurious retransmissions. May not have +// any benefits, but if the delayed ack becomes a significant source +// of (likely, tail) latency, then consider such a mechanism. + +const QuicTime::Delta QuicCongestionManager::DelayedAckTime() { + return QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs/2); +} + const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay( size_t unacked_packets_count, size_t number_retransmissions) { diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h index 8bfa3c1..465819b 100644 --- a/net/quic/congestion_control/quic_congestion_manager.h +++ b/net/quic/congestion_control/quic_congestion_manager.h @@ -50,7 +50,8 @@ class NET_EXPORT_PRIVATE QuicCongestionManager { virtual void SentPacket(QuicPacketSequenceNumber sequence_number, QuicTime sent_time, QuicByteCount bytes, - Retransmission retransmission); + Retransmission retransmission, + HasRetransmittableData has_retransmittable_data); // Called when a packet is timed out. virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number); @@ -85,6 +86,9 @@ class NET_EXPORT_PRIVATE QuicCongestionManager { const QuicTime::Delta DefaultRetransmissionTime(); + // Returns amount of time for delayed ack timer. + const QuicTime::Delta DelayedAckTime(); + const QuicTime::Delta GetRetransmissionDelay( size_t unacked_packets_count, size_t number_retransmissions); diff --git a/net/quic/congestion_control/quic_congestion_manager_test.cc b/net/quic/congestion_control/quic_congestion_manager_test.cc index 1cf44a2..80460f55 100644 --- a/net/quic/congestion_control/quic_congestion_manager_test.cc +++ b/net/quic/congestion_control/quic_congestion_manager_test.cc @@ -14,6 +14,7 @@ using testing::_; using testing::StrictMock; +using testing::Return; namespace net { namespace test { @@ -64,7 +65,8 @@ TEST_F(QuicCongestionManagerTest, Bandwidth) { clock_.AdvanceTime(advance_time); EXPECT_TRUE(manager_->TimeUntilSend( clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); // Ack the packet we sent. ack.received_info.largest_observed = i; manager_->OnIncomingAckFrame(ack, clock_.Now()); @@ -92,8 +94,8 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); EXPECT_TRUE(manager_->TimeUntilSend( clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket( - sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(sequence_number, clock_.Now(), 1000, + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); // Ack the packet we sent. ack.received_info.largest_observed = sequence_number; manager_->OnIncomingAckFrame(ack, clock_.Now()); @@ -118,7 +120,8 @@ TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) { for (int i = 1; i <= 150; ++i) { EXPECT_TRUE(manager_->TimeUntilSend( clock_.Now(), NOT_RETRANSMISSION, kIgnored, NOT_HANDSHAKE).IsZero()); - manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); // Ack the packet we sent. ack.received_info.largest_observed = i + 100; @@ -141,11 +144,13 @@ TEST_F(QuicCongestionManagerTest, Rtt) { QuicPacketSequenceNumber sequence_number = 1; QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15); - EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _)) + .Times(1).WillOnce(Return(true)); EXPECT_CALL(*send_algorithm, OnIncomingAck(sequence_number, _, expected_rtt)).Times(1); - manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); QuicAckFrame ack; @@ -167,11 +172,13 @@ TEST_F(QuicCongestionManagerTest, RttWithInvalidDelta) { QuicPacketSequenceNumber sequence_number = 1; QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite(); - EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _)) + .Times(1).WillOnce(Return(true)); EXPECT_CALL(*send_algorithm, OnIncomingAck(sequence_number, _, expected_rtt)).Times(1); - manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); QuicAckFrame ack; @@ -193,11 +200,13 @@ TEST_F(QuicCongestionManagerTest, RttInfiniteDelta) { QuicPacketSequenceNumber sequence_number = 1; QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite(); - EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _)) + .Times(1).WillOnce(Return(true)); EXPECT_CALL(*send_algorithm, OnIncomingAck(sequence_number, _, expected_rtt)).Times(1); - manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); QuicAckFrame ack; @@ -218,11 +227,13 @@ TEST_F(QuicCongestionManagerTest, RttZeroDelta) { QuicPacketSequenceNumber sequence_number = 1; QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10); - EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1); - EXPECT_CALL(*send_algorithm, - OnIncomingAck(sequence_number, _, expected_rtt)).Times(1); + EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _, _)) + .Times(1).WillOnce(Return(true)); + EXPECT_CALL(*send_algorithm, OnIncomingAck(sequence_number, _, expected_rtt)) + .Times(1); - manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION); + manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(expected_rtt); QuicAckFrame ack; diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index 8896b2b..c29f225 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -55,11 +55,15 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { virtual void OnIncomingLoss(QuicTime ack_receive_time) = 0; // Inform that we sent x bytes to the wire, and if that was a retransmission. + // Returns true if the packet should be tracked by the congestion manager, + // false otherwise. This is used by implementations such as tcp_cubic_sender + // that do not count outgoing ACK packets against the congestion window. // Note: this function must be called for every packet sent to the wire. - virtual void SentPacket(QuicTime sent_time, + virtual bool SentPacket(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmission) = 0; + Retransmission is_retransmission, + HasRetransmittableData is_retransmittable) = 0; // Called when a packet is timed out. virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 438dbe9..52c910e 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -65,6 +65,7 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( void TcpCubicSender::OnIncomingAck( QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes, QuicTime::Delta rtt) { + DCHECK_GE(bytes_in_flight_, acked_bytes); bytes_in_flight_ -= acked_bytes; CongestionAvoidance(acked_sequence_number); AckAccounting(rtt); @@ -93,10 +94,16 @@ void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_; } -void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, +bool TcpCubicSender::SentPacket(QuicTime /*sent_time*/, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - Retransmission is_retransmission) { + Retransmission is_retransmission, + HasRetransmittableData is_retransmittable) { + // Only update bytes_in_flight_ for data packets. + if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { + return false; + } + bytes_in_flight_ += bytes; if (is_retransmission == NOT_RETRANSMISSION && update_end_sequence_number_) { end_sequence_number_ = sequence_number; @@ -105,10 +112,12 @@ void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, DLOG(INFO) << "Stop update end sequence number @" << sequence_number; } } + return true; } void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) { + DCHECK_GE(bytes_in_flight_, abandoned_bytes); bytes_in_flight_ -= abandoned_bytes; } diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index 8cea0aa..db829c2 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -41,10 +41,12 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { QuicByteCount acked_bytes, QuicTime::Delta rtt) OVERRIDE; virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE; - virtual void SentPacket(QuicTime sent_time, - QuicPacketSequenceNumber sequence_number, - QuicByteCount bytes, - Retransmission is_retransmission) OVERRIDE; + virtual bool SentPacket( + QuicTime sent_time, + QuicPacketSequenceNumber sequence_number, + QuicByteCount bytes, + Retransmission is_retransmission, + HasRetransmittableData is_retransmittable) OVERRIDE; virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index fb67fcd..c7046fc 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -45,7 +45,7 @@ class TcpCubicSenderTest : public ::testing::Test { while (bytes_to_send > 0) { QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send); sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, - NOT_RETRANSMISSION); + NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); bytes_to_send -= bytes_in_packet; if (bytes_to_send > 0) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, @@ -352,5 +352,22 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); } +TEST_F(TcpCubicSenderTest, CongestionWindowNotAffectedByAcks) { + QuicByteCount congestion_window = sender_->AvailableCongestionWindow(); + + // 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); + sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, + NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); + EXPECT_EQ(congestion_window, sender_->AvailableCongestionWindow()); + + // 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()); +} + } // namespace test } // namespace net diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index ec87d77..ca6941c 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc @@ -314,6 +314,12 @@ void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) { NotifyFactoryOfSessionCloseLater(); } +void QuicClientSession::OnSuccessfulVersionNegotiation( + const QuicVersion& version) { + logger_.OnSuccessfulVersionNegotiation(version); + QuicSession::OnSuccessfulVersionNegotiation(version); +} + void QuicClientSession::StartReading() { if (read_pending_) { return; diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h index a5973b6..d167237 100644 --- a/net/quic/quic_client_session.h +++ b/net/quic/quic_client_session.h @@ -113,6 +113,8 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession { // QuicConnectionVisitorInterface methods: virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE; + virtual void OnSuccessfulVersionNegotiation( + const QuicVersion& version) OVERRIDE; // Performs a crypto handshake with the server. int CryptoConnect(bool require_confirmation, diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 748821e..0633f90 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -19,6 +19,7 @@ using std::list; using std::make_pair; using std::min; using std::max; +using std::numeric_limits; using std::vector; using std::set; using std::string; @@ -282,6 +283,7 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) { } version_negotiation_state_ = NEGOTIATED_VERSION; + visitor_->OnSuccessfulVersionNegotiation(received_version); // Store the new version. framer_.set_version(received_version); @@ -380,6 +382,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { DCHECK_EQ(1u, header.public_header.versions.size()); DCHECK_EQ(header.public_header.versions[0], version()); version_negotiation_state_ = NEGOTIATED_VERSION; + visitor_->OnSuccessfulVersionNegotiation(version()); } } else { DCHECK(!header.public_header.version_flag); @@ -387,6 +390,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { // it should stop sending version since the version negotiation is done. packet_creator_.StopSendingVersion(); version_negotiation_state_ = NEGOTIATED_VERSION; + visitor_->OnSuccessfulVersionNegotiation(version()); } } @@ -781,7 +785,7 @@ void QuicConnection::MaybeSendInResponseToPacket( // Set the ack alarm for when any retransmittable frame is received. if (!ack_alarm_->IsSet()) { ack_alarm_->Set(clock_->ApproximateNow().Add( - congestion_manager_.DefaultRetransmissionTime())); + congestion_manager_.DelayedAckTime())); } } send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_; @@ -817,26 +821,51 @@ void QuicConnection::SendVersionNegotiationPacket() { delete encrypted; } -QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin) { - // To make reasoning about crypto frames easier, we don't combine them with - // any other frames in a single packet. - const bool crypto_frame_while_batch_mode = - id == kCryptoStreamId && packet_generator_.InBatchMode(); +QuicConsumedData QuicConnection::SendvStreamData(QuicStreamId id, + const struct iovec* iov, + int count, + QuicStreamOffset offset, + bool fin) { + // TODO(ianswett): Further improve sending by passing the iovec down + // instead of batching into multiple stream frames in a single packet. + const bool already_in_batch_mode = packet_generator_.InBatchMode(); + packet_generator_.StartBatchOperations(); - if (crypto_frame_while_batch_mode) { - // Flush pending frames to make room for a crypto frame. - packet_generator_.FinishBatchOperations(); + size_t bytes_written = 0; + bool fin_consumed = false; + for (int i = 0; i < count; ++i) { + bool send_fin = fin && (i == count - 1); + if (!send_fin && iov[i].iov_len == 0) { + LOG(DFATAL) << "Attempt to send empty stream frame"; + } + QuicConsumedData data_consumed = packet_generator_.ConsumeData( + id, + StringPiece(static_cast<char*>(iov[i].iov_base), iov[i].iov_len), + offset + bytes_written, + send_fin); + DCHECK_LE(data_consumed.bytes_consumed, numeric_limits<uint32>::max()); + bytes_written += data_consumed.bytes_consumed; + fin_consumed = data_consumed.fin_consumed; + // If no bytes were consumed, bail now, because the stream can not write + // more data. + if (data_consumed.bytes_consumed < iov[i].iov_len) { + break; + } } - QuicConsumedData consumed_data = - packet_generator_.ConsumeData(id, data, offset, fin); - if (crypto_frame_while_batch_mode) { - // Restore batch mode. - packet_generator_.StartBatchOperations(); + // Handle the 0 byte write properly. + if (count == 0) { + DCHECK(fin); + QuicConsumedData data_consumed = packet_generator_.ConsumeData( + id, StringPiece(), offset, fin); + fin_consumed = data_consumed.fin_consumed; } - return consumed_data; + + // Leave the generator in the original batch state. + if (!already_in_batch_mode) { + packet_generator_.FinishBatchOperations(); + } + DCHECK_EQ(already_in_batch_mode, packet_generator_.InBatchMode()); + return QuicConsumedData(bytes_written, fin_consumed); } QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked( @@ -845,6 +874,9 @@ QuicConsumedData QuicConnection::SendStreamDataAndNotifyWhenAcked( QuicStreamOffset offset, bool fin, QuicAckNotifier::DelegateInterface* delegate) { + if (!fin && data.empty()) { + LOG(DFATAL) << "Attempt to send empty stream frame"; + } // This notifier will be deleted in ProcessAckFrame once it has seen ACKs for // all the consumed data (or below if no data was consumed). QuicAckNotifier* notifier = new QuicAckNotifier(delegate); @@ -953,12 +985,12 @@ bool QuicConnection::DoWrite() { // write more. if (CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, maybe_handshake)) { - const bool in_batch_mode = packet_generator_.InBatchMode(); - if (!in_batch_mode) { + const bool already_in_batch_mode = packet_generator_.InBatchMode(); + if (!already_in_batch_mode) { packet_generator_.StartBatchOperations(); } bool all_bytes_written = visitor_->OnCanWrite(); - if (!in_batch_mode) { + if (!already_in_batch_mode) { packet_generator_.FinishBatchOperations(); } @@ -1305,7 +1337,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level, // If the socket buffers the the data, then the packet should not // be queued and sent again, which would result in an unnecessary // duplicate packet being sent. - return helper_->IsWriteBlockedDataBuffered(); + if (helper_->IsWriteBlockedDataBuffered()) { + delete packet; + return true; + } + return false; } // We can't send an error as the socket is presumably borked. CloseConnection(QUIC_PACKET_WRITE_ERROR, false); @@ -1323,11 +1359,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level, // TODO(ianswett): Change the sequence number length and other packet creator // options by a more explicit API than setting a struct value directly. - packet_creator_.options()->send_sequence_number_length = - CalculateSequenceNumberLength(sequence_number); + packet_creator_.UpdateSequenceNumberLength( + received_packet_manager_.least_packet_awaited_by_peer(), + congestion_manager_.BandwidthEstimate().ToBytesPerPeriod( + congestion_manager_.SmoothedRtt())); congestion_manager_.SentPacket(sequence_number, now, packet->length(), - retransmission); + retransmission, retransmittable); stats_.bytes_sent += encrypted->length(); ++stats_.packets_sent; @@ -1355,31 +1393,6 @@ int QuicConnection::WritePacketToWire(QuicPacketSequenceNumber sequence_number, return bytes_written; } -QuicSequenceNumberLength QuicConnection::CalculateSequenceNumberLength( - QuicPacketSequenceNumber sequence_number) { - DCHECK_LE(received_packet_manager_.least_packet_awaited_by_peer(), - sequence_number); - // Since the packet creator will not change sequence number length mid FEC - // group, include the size of an FEC group to be safe. - const QuicPacketSequenceNumber current_delta = - packet_creator_.options()->max_packets_per_fec_group + sequence_number - - received_packet_manager_.least_packet_awaited_by_peer(); - const uint64 congestion_window = - congestion_manager_.BandwidthEstimate().ToBytesPerPeriod( - congestion_manager_.SmoothedRtt()) / - packet_creator_.options()->max_packet_length; - const uint64 delta = max(current_delta, congestion_window); - - if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) { - return PACKET_1BYTE_SEQUENCE_NUMBER; - } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) { - return PACKET_2BYTE_SEQUENCE_NUMBER; - } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) { - return PACKET_4BYTE_SEQUENCE_NUMBER; - } - return PACKET_6BYTE_SEQUENCE_NUMBER; -} - bool QuicConnection::OnSerializedPacket( const SerializedPacket& serialized_packet) { if (serialized_packet.retransmittable_frames != NULL) { @@ -1716,6 +1729,14 @@ void QuicConnection::CloseFecGroupsBefore( } } +void QuicConnection::Flush() { + if (!packet_generator_.InBatchMode()) { + return; + } + packet_generator_.FinishBatchOperations(); + packet_generator_.StartBatchOperations(); +} + bool QuicConnection::HasQueuedData() const { return !queued_packets_.empty() || packet_generator_.HasQueuedFrames(); } diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index a23ecf0..8420752 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -24,6 +24,7 @@ #include <vector> #include "base/containers/hash_tables.h" +#include "net/base/iovec.h" #include "net/base/ip_endpoint.h" #include "net/base/linked_hash_map.h" #include "net/quic/congestion_control/quic_congestion_manager.h" @@ -76,6 +77,9 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when packets are acked by the peer. virtual void OnAck(const SequenceNumberSet& acked_packets) = 0; + // Called once a specific QUIC version is agreed by both endpoints. + virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0; + // Called when a blocked socket becomes writable. If all pending bytes for // this visitor are consumed by the connection successfully this should // return true, otherwise it should return false. @@ -205,15 +209,17 @@ class NET_EXPORT_PRIVATE QuicConnection QuicVersion version); virtual ~QuicConnection(); - // Send the data payload to the peer. + // Send the data in |iov| to the peer in as few packets as possible. // Returns a pair with the number of bytes consumed from data, and a boolean // indicating if the fin bit was consumed. This does not indicate the data // has been sent on the wire: it may have been turned into a packet and queued // if the socket was unexpectedly blocked. - QuicConsumedData SendStreamData(QuicStreamId id, - base::StringPiece data, - QuicStreamOffset offset, - bool fin); + QuicConsumedData SendvStreamData(QuicStreamId id, + const struct iovec* iov, + int count, + QuicStreamOffset offset, + bool fin); + // Same as above, except that the provided delegate will be informed once ACKs // have been received for all the packets written. // The |delegate| is not owned by the QuicConnection and must outlive it. @@ -240,7 +246,7 @@ class NET_EXPORT_PRIVATE QuicConnection virtual void SendConnectionCloseWithDetails(QuicErrorCode error, const std::string& details); // Notifies the visitor of the close and marks the connection as disconnected. - void CloseConnection(QuicErrorCode error, bool from_peer); + virtual void CloseConnection(QuicErrorCode error, bool from_peer) OVERRIDE; virtual void SendGoAway(QuicErrorCode error, QuicStreamId last_good_stream_id, const std::string& reason); @@ -335,6 +341,10 @@ class NET_EXPORT_PRIVATE QuicConnection // Testing only. size_t NumQueuedPackets() const { return queued_packets_.size(); } + // Flush any queued frames immediately. Preserves the batch write mode and + // does nothing if there are no pending frames. + void Flush(); + // Returns true if the connection has queued packets or frames. bool HasQueuedData() const; diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index 9f1bcac..366e97b 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -125,6 +125,8 @@ class QuicConnectionHelperTest : public ::testing::Test { testing::Return(QuicBandwidth::FromKBitsPerSecond(100))); EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly( testing::Return(QuicTime::Delta::FromMilliseconds(100))); + ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)) + .WillByDefault(testing::Return(true)); connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_)); connection_->set_visitor(&visitor_); connection_->SetSendAlgorithm(send_algorithm_); @@ -315,12 +317,14 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) { QuicTime::Delta::FromMilliseconds(500); QuicTime start = clock_.ApproximateNow(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)); // Send a packet. - connection_->SendStreamData(1, kData, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION)); + 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, _)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); @@ -343,11 +347,14 @@ TEST_F(QuicConnectionHelperTest, TestMultipleRetransmission) { QuicTime::Delta::FromMilliseconds(500); QuicTime start = clock_.ApproximateNow(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)); + // Send a packet. - connection_->SendStreamData(1, kData, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION)); + 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, _)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); @@ -357,7 +364,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, _, IS_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)); runner_->RunNextTask(); @@ -376,7 +383,7 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) { EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultInitialTimeoutSecs), runner_->GetPostedTasks().front().delay); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); // After we run the next task, we should close the connection. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); @@ -423,7 +430,8 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { // kDefaultInitialTimeoutSecs. clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000)); EXPECT_EQ(5000u, clock_.ApproximateNow().Subtract(start).ToMicroseconds()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, 1, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); // Send an ack so we don't set the retransmission alarm. connection_->SendAck(); @@ -439,7 +447,8 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, 2, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); runner_->RunNextTask(); EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000, clock_.ApproximateNow().Subtract( @@ -460,9 +469,10 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) { testing::Return(QuicTime::Delta::FromMicroseconds(1))); QuicPacket* packet = ConstructRawDataPacket(1); - connection_->SendOrQueuePacket( - ENCRYPTION_NONE, 1, packet, 0, HAS_RETRANSMITTABLE_DATA); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + connection_->SendOrQueuePacket(ENCRYPTION_NONE, 1, packet, 0, + HAS_RETRANSMITTABLE_DATA); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, + _)); EXPECT_EQ(1u, connection_->NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 2221b50..5195f43 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc @@ -12,6 +12,8 @@ #include "net/base/net_log.h" #include "net/quic/crypto/crypto_handshake.h" +using std::string; + namespace net { namespace { @@ -416,4 +418,11 @@ void QuicConnectionLogger::OnConnectionClose(QuicErrorCode error, base::Bind(&NetLogQuicConnectionClosedCallback, error, from_peer)); } +void QuicConnectionLogger::OnSuccessfulVersionNegotiation( + const QuicVersion& version) { + string quic_version = QuicVersionToString(version); + net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED, + NetLog::StringCallback("version", &quic_version)); +} + } // namespace net diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h index f9080d6..d498b12 100644 --- a/net/quic/quic_connection_logger.h +++ b/net/quic/quic_connection_logger.h @@ -56,6 +56,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger void OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& message); void OnConnectionClose(QuicErrorCode error, bool from_peer); + void OnSuccessfulVersionNegotiation(const QuicVersion& version); private: BoundNetLog net_log_; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index e57e7ae..147d8bc 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -389,6 +389,15 @@ class TestConnection : public QuicConnection { QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); } + QuicConsumedData SendStreamData(QuicStreamId id, + StringPiece data, + QuicStreamOffset offset, + bool fin) { + struct iovec iov = {const_cast<char*>(data.data()), + static_cast<size_t>(data.size())}; + return SendvStreamData(id, &iov, 1, offset, fin); + } + QuicConsumedData SendStreamData3() { return SendStreamData(kStreamId3, "food", 0, !kFin); } @@ -403,7 +412,11 @@ class TestConnection : public QuicConnection { // split needlessly across packet boundaries). As a result, we have separate // tests for some cases for this stream. QuicConsumedData SendCryptoStreamData() { - return SendStreamData(kCryptoStreamId, "chlo", 0, !kFin); + this->Flush(); + QuicConsumedData consumed = + SendStreamData(kCryptoStreamId, "chlo", 0, !kFin); + this->Flush(); + return consumed; } bool is_server() { @@ -467,13 +480,15 @@ class QuicConnectionTest : public ::testing::Test { QuicTime::Delta::Zero())); EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)).Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(Return( QuicBandwidth::FromKBitsPerSecond(100))); EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(Return( QuicTime::Delta::FromMilliseconds(100))); + ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)) + .WillByDefault(Return(true)); // TODO(rch): remove this. QuicConnection::g_acks_do_not_instigate_acks = true; } @@ -630,21 +645,21 @@ class QuicConnectionTest : public ::testing::Test { QuicStreamOffset offset, bool fin, QuicPacketSequenceNumber* last_packet) { QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce( - SaveArg<2>(&packet_size)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)) + .WillOnce(DoAll(SaveArg<2>(&packet_size), Return(true))); connection_.SendStreamData(id, data, offset, fin); if (last_packet != NULL) { *last_packet = QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number(); } - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber()); return packet_size; } void SendAckPacketToPeer() { - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); connection_.SendAck(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber()); } QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame, @@ -741,6 +756,8 @@ class QuicConnectionTest : public ::testing::Test { }; TEST_F(QuicConnectionTest, PacketsInOrder) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(1); EXPECT_EQ(1u, outgoing_ack()->received_info.largest_observed); EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size()); @@ -755,6 +772,8 @@ TEST_F(QuicConnectionTest, PacketsInOrder) { } TEST_F(QuicConnectionTest, PacketsRejected) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(1); EXPECT_EQ(1u, outgoing_ack()->received_info.largest_observed); EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size()); @@ -767,6 +786,8 @@ TEST_F(QuicConnectionTest, PacketsRejected) { } TEST_F(QuicConnectionTest, PacketsOutOfOrder) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed); EXPECT_TRUE(IsMissing(2)); @@ -784,6 +805,8 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrder) { } TEST_F(QuicConnectionTest, DuplicatePacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed); EXPECT_TRUE(IsMissing(2)); @@ -798,6 +821,8 @@ TEST_F(QuicConnectionTest, DuplicatePacket) { } TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed); EXPECT_TRUE(IsMissing(2)); @@ -833,6 +858,7 @@ TEST_F(QuicConnectionTest, RejectPacketTooFarOut) { } TEST_F(QuicConnectionTest, TruncatedAck) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnAck(_)).Times(testing::AnyNumber()); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); @@ -861,6 +887,8 @@ TEST_F(QuicConnectionTest, TruncatedAck) { } TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessPacket(1); // Delay sending, then queue up an ack. EXPECT_CALL(*send_algorithm_, @@ -880,11 +908,13 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) { } TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber largest_observed; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION)) - .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size))); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) + .WillOnce(DoAll(SaveArg<1>(&largest_observed), 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); @@ -895,13 +925,13 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { ProcessAckPacket(&frame, true); // Third nack should retransmit the largest observed packet. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size - kQuicVersionSize, - IS_RETRANSMISSION)); + IS_RETRANSMISSION, _)); ProcessAckPacket(&frame, 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)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); ProcessAckPacket(&frame, true); // But an ack with no new missing packest will not send an ack. @@ -911,6 +941,8 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { } TEST_F(QuicConnectionTest, LeastUnackedLower) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); @@ -930,12 +962,14 @@ TEST_F(QuicConnectionTest, LeastUnackedLower) { // Now claim it's one, but set the ordering so it was sent "after" the first // one. This should cause a connection error. EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); creator_.set_sequence_number(7); ProcessAckPacket(&frame2, false); } TEST_F(QuicConnectionTest, LargestObservedLower) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); @@ -955,8 +989,9 @@ TEST_F(QuicConnectionTest, LargestObservedLower) { } TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); // Create an ack with least_unacked is 2 in packet number 1. creator_.set_sequence_number(0); QuicAckFrame frame(0, QuicTime::Zero(), 2); @@ -965,12 +1000,14 @@ TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) { TEST_F(QuicConnectionTest, NackSequenceNumberGreaterThanLargestReceived) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); QuicAckFrame frame(0, QuicTime::Zero(), 1); frame.received_info.missing_packets.insert(3); ProcessAckPacket(&frame, false); @@ -979,12 +1016,14 @@ TEST_F(QuicConnectionTest, TEST_F(QuicConnectionTest, AckUnsentData) { // Ack a packet which has not been sent. EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); QuicAckFrame frame(1, QuicTime::Zero(), 0); ProcessAckPacket(&frame, false); } TEST_F(QuicConnectionTest, AckAll) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); creator_.set_sequence_number(1); @@ -1093,6 +1132,7 @@ TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) { } TEST_F(QuicConnectionTest, BasicSending) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6); QuicPacketSequenceNumber last_packet; SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 @@ -1162,7 +1202,7 @@ TEST_F(QuicConnectionTest, FECSending) { connection_.options()->max_packets_per_fec_group = 2; // Send 4 data packets and 2 FEC packets. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(6); // The first stream frame will consume 2 fewer bytes than the other three. const string payload(payload_length * 4 - 6, 'a'); connection_.SendStreamData(1, payload, 0, !kFin); @@ -1192,7 +1232,7 @@ TEST_F(QuicConnectionTest, FECQueueing) { TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) { connection_.options()->max_packets_per_fec_group = 1; // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(2); connection_.SendStreamData(1, "foo", 0, !kFin); // Larger timeout for FEC bytes to expire. @@ -1201,7 +1241,7 @@ TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) { clock_.AdvanceTime(retransmission_time); // Send only data packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); // Abandon both FEC and data packet. EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); @@ -1209,12 +1249,13 @@ TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) { } TEST_F(QuicConnectionTest, DontAbandonAckedFEC) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.options()->max_packets_per_fec_group = 1; const QuicPacketSequenceNumber sequence_number = QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number() + 1; // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(2); connection_.SendStreamData(1, "foo", 0, !kFin); QuicAckFrame ack_fec(2, QuicTime::Zero(), 1); @@ -1235,7 +1276,7 @@ TEST_F(QuicConnectionTest, DontAbandonAckedFEC) { // Abandon only data packet, FEC has been acked. EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1); // Send only data packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); connection_.OnRetransmissionTimeout(); } @@ -1256,7 +1297,7 @@ TEST_F(QuicConnectionTest, FramePacking) { // Unblock the connection. connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)) + SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .Times(1); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1289,7 +1330,7 @@ TEST_F(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { // Unblock the connection. connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)) + SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .Times(2); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1320,7 +1361,7 @@ TEST_F(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { // Unblock the connection. connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)) + SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .Times(3); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1352,7 +1393,7 @@ TEST_F(QuicConnectionTest, FramePackingFEC) { // Unblock the connection. connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)).Times(2); + SentPacket(_, _, _, NOT_RETRANSMISSION, _)).Times(2); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -1362,6 +1403,76 @@ TEST_F(QuicConnectionTest, FramePackingFEC) { EXPECT_EQ(0u, helper_->frame_count()); } +TEST_F(QuicConnectionTest, FramePackingSendv) { + // Send two stream frames in 1 packet by using writev. + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); + + char data[] = "ABCD"; + iovec iov[2] = { {static_cast<void*>(data), 2}, + {static_cast<void*>(data + 2), 2} }; + connection_.SendvStreamData(1, iov, 2, 0, !kFin); + + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + EXPECT_FALSE(connection_.HasQueuedData()); + + // Parse the last packet and ensure it's two stream frames from one stream. + // TODO(ianswett): Ideally this would arrive in one frame in the future. + EXPECT_EQ(2u, helper_->frame_count()); + EXPECT_EQ(2u, helper_->stream_frames()->size()); + EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id); + EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id); +} + +TEST_F(QuicConnectionTest, FramePackingSendvQueued) { + // Try to send two stream frames in 1 packet by using writev. + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); + + helper_->set_blocked(true); + char data[] = "ABCD"; + iovec iov[2] = { {static_cast<void*>(data), 2}, + {static_cast<void*>(data + 2), 2} }; + connection_.SendvStreamData(1, iov, 2, 0, !kFin); + + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + EXPECT_TRUE(connection_.HasQueuedData()); + + // Attempt to send all packets, but since we're actually still + // blocked, they should all remain queued. + EXPECT_FALSE(connection_.OnCanWrite()); + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + + // Unblock the writes and actually send. + helper_->set_blocked(false); + EXPECT_CALL(visitor_, OnCanWrite()); + EXPECT_TRUE(connection_.OnCanWrite()); + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + + // Parse the last packet and ensure it's two stream frames from one stream. + // TODO(ianswett): Ideally this would arrive in one frame in the future. + EXPECT_EQ(2u, helper_->frame_count()); + EXPECT_EQ(2u, helper_->stream_frames()->size()); + EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id); + EXPECT_EQ(1u, (*helper_->stream_frames())[1].stream_id); +} + +TEST_F(QuicConnectionTest, SendingZeroBytes) { + // Send a zero byte write with a fin using writev. + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)); + + iovec iov[1]; + connection_.SendvStreamData(1, iov, 0, 0, kFin); + + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + EXPECT_FALSE(connection_.HasQueuedData()); + + // Parse the last packet and ensure it's two stream frames from one stream. + // TODO(ianswett): Ideally this would arrive in one frame in the future. + EXPECT_EQ(1u, helper_->frame_count()); + EXPECT_EQ(1u, helper_->stream_frames()->size()); + EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id); + EXPECT_TRUE((*helper_->stream_frames())[0].fin); +} + TEST_F(QuicConnectionTest, OnCanWrite) { // Visitor's OnCanWill send data, but will return false. EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll( @@ -1399,6 +1510,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { SequenceNumberSet expected_acks; expected_acks.insert(1); EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); + 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. @@ -1427,16 +1539,18 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { // The third nack should trigger a retransimission. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, second_packet_size - kQuicVersionSize, - IS_RETRANSMISSION)).Times(1); + IS_RETRANSMISSION, _)).Times(1); ProcessAckPacket(&nack_two, true); } TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber largest_observed; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION)) - .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size))); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) + .WillOnce(DoAll(SaveArg<1>(&largest_observed), 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); @@ -1447,13 +1561,13 @@ 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)); + IS_RETRANSMISSION, _)); ProcessAckPacket(&frame, true); } TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) { for (int i = 0; i < 200; ++i) { - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); connection_.SendStreamData(1, "foo", i * 3, !kFin); } @@ -1468,6 +1582,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); EXPECT_CALL(visitor_, OnAck(_)).Times(1); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&frame, true); EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); @@ -1475,7 +1590,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) { 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); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(192); connection_.OnRetransmissionTimeout(); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds( @@ -1483,11 +1598,12 @@ TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) { // 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(192); connection_.OnRetransmissionTimeout(); } TEST_F(QuicConnectionTest, LimitPacketsPerNack) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(11); @@ -1515,11 +1631,11 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) { ProcessAckPacket(&nack, true); ProcessAckPacket(&nack, true); // The third call should trigger retransmitting 10 packets. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(10); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(10); ProcessAckPacket(&nack, true); // The fourth call should trigger retransmitting the 11th packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); ProcessAckPacket(&nack, true); } @@ -1556,6 +1672,8 @@ TEST_F(QuicConnectionTest, MultipleAcks) { expected_acks.insert(5); EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessAckPacket(&frame1, true); // Now the client implicitly acks 2, and explicitly acks 6 @@ -1582,6 +1700,7 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) { expected_acks.insert(1); // Peer acks packet 1. EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicAckFrame frame(1, QuicTime::Zero(), 0); frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( &connection_, 1); @@ -1606,12 +1725,16 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) { } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Don't send missing packet 1. ProcessFecPacket(2, 1, true, !kEntropyFlag, NULL); EXPECT_FALSE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessFecProtectedPacket(1, false, kEntropyFlag); // Don't send missing packet 2. ProcessFecPacket(3, 1, true, !kEntropyFlag, NULL); @@ -1619,6 +1742,8 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) { } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessFecProtectedPacket(1, false, !kEntropyFlag); // Don't send missing packet 2. ProcessFecProtectedPacket(3, false, !kEntropyFlag); @@ -1627,6 +1752,8 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) { } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Don't send missing packet 1. ProcessFecPacket(3, 1, false, !kEntropyFlag, NULL); // out of order @@ -1635,6 +1762,8 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) { } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + ProcessFecProtectedPacket(1, false, !kEntropyFlag); // Don't send missing packet 2. ProcessFecPacket(6, 1, false, kEntropyFlag, NULL); @@ -1655,7 +1784,7 @@ TEST_F(QuicConnectionTest, TestRetransmit) { connection_.GetRetransmissionAlarm()->deadline()); // Simulate the retransimission alarm firing clock_.AdvanceTime(DefaultRetransmissionTime()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); connection_.RetransmitPacket(1); EXPECT_EQ(2u, last_header()->packet_sequence_number); @@ -1684,12 +1813,12 @@ TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { clock_.AdvanceTime(DefaultRetransmissionTime()); EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); connection_.RetransmitPacket(1); // Packet should have been sent with ENCRYPTION_NONE. EXPECT_EQ(0x01010101u, final_bytes_of_last_packet()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); connection_.RetransmitPacket(2); // Packet should have been sent with ENCRYPTION_INITIAL. EXPECT_EQ(0x02020202u, final_bytes_of_last_packet()); @@ -1706,7 +1835,7 @@ TEST_F(QuicConnectionTest, new TaggingEncrypter(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(0); EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1); QuicTime default_retransmission_time = clock_.ApproximateNow().Add( @@ -1731,13 +1860,14 @@ TEST_F(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { SendStreamDataToPeer(2, "bar", 0, !kFin, NULL); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(1); connection_.RetransmitUnackedPackets(QuicConnection::INITIAL_ENCRYPTION_ONLY); } TEST_F(QuicConnectionTest, BufferNonDecryptablePackets) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); use_tagging_decrypter(); const uint8 tag = 0x07; @@ -1765,14 +1895,14 @@ TEST_F(QuicConnectionTest, BufferNonDecryptablePackets) { TEST_F(QuicConnectionTest, TestRetransmitOrder) { QuicByteCount first_packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce( - SaveArg<2>(&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; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce( - SaveArg<2>(&second_packet_size)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).WillOnce( + DoAll(SaveArg<2>(&second_packet_size), Return(true))); connection_.SendStreamData(1, "second_packet", 12, !kFin); EXPECT_NE(first_packet_size, second_packet_size); // Advance the clock by huge time to make sure packets will be retransmitted. @@ -1780,20 +1910,20 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) { { InSequence s; EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, first_packet_size, _)); + SentPacket(_, _, first_packet_size, _, _)); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, second_packet_size, _)); + SentPacket(_, _, second_packet_size, _, _)); } connection_.OnRetransmissionTimeout(); } 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(SaveArg<1>(&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)); @@ -1802,9 +1932,8 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { // Force retransmission due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); QuicPacketSequenceNumber rto_sequence_number; - EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, IS_RETRANSMISSION)) - .WillOnce(SaveArg<1>(&rto_sequence_number)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION, _)) + .WillOnce(DoAll(SaveArg<1>(&rto_sequence_number), Return(true))); connection_.OnRetransmissionTimeout(); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, original_sequence_number)); @@ -1816,10 +1945,10 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { QuicPacketSequenceNumber nack_sequence_number; // Ack packets might generate some other packets, which are not // retransmissions. (More ack packets). - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION)) + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, NOT_RETRANSMISSION, _)) .Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_RETRANSMISSION)) - .WillOnce(SaveArg<1>(&nack_sequence_number)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, IS_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(rto_sequence_number); @@ -1868,6 +1997,7 @@ TEST_F(QuicConnectionTest, TestQueued) { } TEST_F(QuicConnectionTest, CloseFecGroup) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Don't send missing packet 1 // Don't send missing packet 2 ProcessFecProtectedPacket(3, false, !kEntropyFlag); @@ -1900,10 +2030,12 @@ TEST_F(QuicConnectionTest, WithQuicCongestionFeedbackFrame) { TEST_F(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) { SendAckPacketToPeer(); EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); } TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendAckPacketToPeer(); // Process an FEC packet, and revive the missing data packet // but only contact the receive_algorithm once. @@ -1914,7 +2046,7 @@ TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) { TEST_F(QuicConnectionTest, InitialTimeout) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); QuicTime default_timeout = clock_.ApproximateNow().Add( QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs)); @@ -1953,7 +2085,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)), clock_.ApproximateNow()); @@ -1968,7 +2100,7 @@ TEST_F(QuicConnectionTest, SendScheduler) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); connection_.SendOrQueuePacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1980,7 +2112,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); connection_.SendOrQueuePacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -1991,7 +2123,7 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, IS_RETRANSMISSION, _, _)).Times(0); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); connection_.SendOrQueuePacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); // XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce); @@ -2004,7 +2136,7 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) { EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); connection_.SendOrQueuePacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2027,7 +2159,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { testing::Return(QuicTime::Delta::Zero())); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); connection_.GetSendAlarm()->Cancel(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2038,7 +2170,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { .WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, - SentPacket(_, 1, _, NOT_RETRANSMISSION)); + SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Advance the time for retransmission of lost packet. @@ -2058,7 +2190,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { // Ensure the scheduler is notified this is a retransmit. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, IS_RETRANSMISSION)); + SentPacket(_, _, _, IS_RETRANSMISSION, _)); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); connection_.GetSendAlarm()->Cancel(); EXPECT_CALL(visitor_, OnCanWrite()); @@ -2083,6 +2215,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) { } TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( @@ -2098,7 +2231,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, _)); + SentPacket(_, _, _, _, _)); ProcessAckPacket(&frame, true); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2107,6 +2240,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { } TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( @@ -2168,7 +2302,7 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { NOT_IN_FEC_GROUP, &payload_length); // Queue the first packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(7); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(7); // The first stream frame will consume 2 fewer bytes than the other six. const string payload(payload_length * 7 - 12, 'a'); EXPECT_EQ(payload.size(), @@ -2176,10 +2310,11 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { } TEST_F(QuicConnectionTest, NoAckForClose) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0); EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(0); ProcessClosePacket(2, 0); } @@ -2189,7 +2324,7 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) { connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false); EXPECT_FALSE(connection_.connected()); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _, _)).Times(0); connection_.SendOrQueuePacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); } @@ -2207,6 +2342,8 @@ TEST_F(QuicConnectionTest, PublicReset) { } TEST_F(QuicConnectionTest, GoAway) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + QuicGoAwayFrame goaway; goaway.last_good_stream_id = 1; goaway.error_code = QUIC_PEER_GOING_AWAY; @@ -2219,12 +2356,14 @@ TEST_F(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) { QuicAckFrame ack(0, QuicTime::Zero(), 4); // Set the sequence number of the ack packet to be least unacked (4) creator_.set_sequence_number(3); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&ack, true); EXPECT_TRUE(outgoing_ack()->received_info.missing_packets.empty()); } TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessDataPacket(1, 1, kEntropyFlag); ProcessDataPacket(4, 1, kEntropyFlag); ProcessDataPacket(3, 1, !kEntropyFlag); @@ -2234,6 +2373,7 @@ TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) { TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessDataPacket(1, 1, kEntropyFlag); ProcessDataPacket(5, 1, kEntropyFlag); ProcessDataPacket(4, 1, !kEntropyFlag); @@ -2254,6 +2394,7 @@ TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) { TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessDataPacket(1, 1, kEntropyFlag); ProcessDataPacket(5, 1, !kEntropyFlag); ProcessDataPacket(22, 1, kEntropyFlag); @@ -2273,6 +2414,7 @@ TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) { TEST_F(QuicConnectionTest, EntropyCalculationForTruncatedAck) { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketEntropyHash entropy[51]; entropy[0] = 0; for (int i = 1; i < 51; ++i) { @@ -2397,6 +2539,7 @@ TEST_F(QuicConnectionTest, ClientHandlesVersionNegotiation) { framer_.BuildUnsizedDataPacket(header, frames).packet); encrypted.reset(framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet)); EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(1); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); ASSERT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket( @@ -2431,18 +2574,18 @@ TEST_F(QuicConnectionTest, BadVersionNegotiation) { TEST_F(QuicConnectionTest, CheckSendStats) { EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)); + SentPacket(_, _, _, NOT_RETRANSMISSION, _)); connection_.SendStreamData(1u, "first", 0, !kFin); size_t first_packet_size = last_sent_packet_size(); EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, NOT_RETRANSMISSION)); + SentPacket(_, _, _, NOT_RETRANSMISSION, _)); connection_.SendStreamData(1u, "second", 0, !kFin); size_t second_packet_size = last_sent_packet_size(); // 2 retransmissions due to rto, 1 due to explicit nack. EXPECT_CALL(*send_algorithm_, - SentPacket(_, _, _, IS_RETRANSMISSION)).Times(3); + SentPacket(_, _, _, IS_RETRANSMISSION, _)).Times(3); // Retransmit due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); @@ -2460,6 +2603,7 @@ TEST_F(QuicConnectionTest, CheckSendStats) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); EXPECT_CALL(visitor_, OnCanWrite()).Times(3).WillRepeatedly(Return(true)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessFramePacket(frame); ProcessFramePacket(frame); @@ -2481,6 +2625,8 @@ TEST_F(QuicConnectionTest, CheckSendStats) { } TEST_F(QuicConnectionTest, CheckReceiveStats) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + size_t received_bytes = 0; received_bytes += ProcessFecProtectedPacket(1, false, !kEntropyFlag); received_bytes += ProcessFecProtectedPacket(3, false, !kEntropyFlag); @@ -2550,6 +2696,7 @@ TEST_F(QuicConnectionTest, DontProcessFramesIfPacketClosedConnection) { EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true)); EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(0); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); } @@ -2622,6 +2769,8 @@ TEST_F(QuicConnectionTest, ConnectionCloseWhenNothingPending) { } TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Create a delegate which we expect to be called. MockAckNotifierDelegate delegate; EXPECT_CALL(delegate, OnAckNotification()).Times(1);; @@ -2637,6 +2786,8 @@ TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) { } TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Create a delegate which we don't expect to be called. MockAckNotifierDelegate delegate; EXPECT_CALL(delegate, OnAckNotification()).Times(0);; @@ -2661,6 +2812,8 @@ TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) { } TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Create a delegate which we expect to be called. MockAckNotifierDelegate delegate; EXPECT_CALL(delegate, OnAckNotification()).Times(1);; @@ -2688,7 +2841,7 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) { // Advance time to trigger RTO, for packet 2 (which should be retransmitted as // packet 5). EXPECT_CALL(*send_algorithm_, AbandoningPacket(2, _)).Times(1); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(1); clock_.AdvanceTime(DefaultRetransmissionTime()); connection_.OnRetransmissionTimeout(); @@ -2702,6 +2855,7 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) { // TODO(rjshade): Add a similar test that FEC recovery on peer (and resulting // ACK) triggers notification on our end. TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnCanWrite()).Times(1).WillOnce(Return(true)); // Create a delegate which we expect to be called. @@ -2723,8 +2877,7 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) { frames.push_back(QuicFrame(&ack_frame)); // Dummy stream frame to satisfy expectations set elsewhere. - QuicFrame frame(&frame1_); - frames.push_back(frame); + frames.push_back(QuicFrame(&frame1_)); QuicPacketHeader ack_header; ack_header.public_header.guid = guid_; diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc index 569648f..3c10c5b 100644 --- a/net/quic/quic_crypto_stream.cc +++ b/net/quic/quic_crypto_stream.cc @@ -59,8 +59,12 @@ void QuicCryptoStream::SendHandshakeMessage( const CryptoHandshakeMessage& message) { session()->OnCryptoHandshakeMessageSent(message); const QuicData& data = message.GetSerialized(); + // To make reasoning about crypto frames easier, we don't combine them with + // any other frames in a single packet. + session()->connection()->Flush(); // TODO(wtc): check the return value. WriteData(string(data.data(), data.length()), false); + session()->connection()->Flush(); } const QuicCryptoNegotiatedParameters& diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index a91b9e2..0122c64 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc @@ -11,6 +11,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "net/quic/quic_client_session.h" +#include "net/quic/quic_http_utils.h" #include "net/quic/quic_reliable_client_stream.h" #include "net/quic/quic_utils.h" #include "net/socket/next_proto.h" @@ -29,6 +30,7 @@ QuicHttpStream::QuicHttpStream(const base::WeakPtr<QuicClientSession> session) stream_(NULL), request_info_(NULL), request_body_stream_(NULL), + priority_(MINIMUM_PRIORITY), response_info_(NULL), response_status_(OK), response_headers_received_(false), @@ -52,6 +54,7 @@ int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, stream_net_log_ = stream_net_log; request_info_ = request_info; + priority_ = priority; int rv = stream_request_.StartRequest( session_, &stream_, base::Bind(&QuicHttpStream::OnStreamReady, @@ -82,6 +85,8 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, CHECK(!callback.is_null()); CHECK(response); + QuicPriority priority = ConvertRequestPriorityToQuicPriority(priority_); + stream_->set_priority(priority); // Store the serialized request headers. SpdyHeaderBlock headers; CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, @@ -89,7 +94,8 @@ int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers, if (session_->connection()->version() < QUIC_VERSION_9) { request_ = stream_->compressor()->CompressHeaders(headers); } else { - request_ = stream_->compressor()->CompressHeadersWithPriority(0, headers); + request_ = stream_->compressor()->CompressHeadersWithPriority(priority, + headers); } // Log the actual request with the URL Request's net log. stream_net_log_.AddEvent( @@ -207,7 +213,7 @@ void QuicHttpStream::Close(bool not_reusable) { stream_->SetDelegate(NULL); // TODO(rch): use new CANCELLED error code here once quic 11 // is everywhere. - stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM); + stream_->Close(QUIC_ERROR_PROCESSING_STREAM); stream_ = NULL; } } @@ -264,7 +270,7 @@ void QuicHttpStream::Drain(HttpNetworkSession* session) { } void QuicHttpStream::SetPriority(RequestPriority priority) { - // Nothing to do here (yet). + priority_ = priority; } int QuicHttpStream::OnSendData() { @@ -336,6 +342,10 @@ void QuicHttpStream::OnError(int error) { DoCallback(response_status_); } +bool QuicHttpStream::HasSendHeadersComplete() { + return next_state_ > STATE_SEND_HEADERS_COMPLETE; +} + void QuicHttpStream::OnIOComplete(int rv) { rv = DoLoop(rv); diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h index cc2b973..71fb515 100644 --- a/net/quic/quic_http_stream.h +++ b/net/quic/quic_http_stream.h @@ -15,6 +15,10 @@ namespace net { +namespace test { +class QuicHttpStreamPeer; +} // namespace test + // The QuicHttpStream is a QUIC-specific HttpStream subclass. It holds a // non-owning pointer to a QuicReliableClientStream which it uses to // send and receive data. @@ -62,8 +66,11 @@ class NET_EXPORT_PRIVATE QuicHttpStream : virtual int OnDataReceived(const char* data, int length) OVERRIDE; virtual void OnClose(QuicErrorCode error) OVERRIDE; virtual void OnError(int error) OVERRIDE; + virtual bool HasSendHeadersComplete() OVERRIDE; private: + friend class test::QuicHttpStreamPeer; + enum State { STATE_NONE, STATE_SEND_HEADERS, @@ -106,6 +113,8 @@ class NET_EXPORT_PRIVATE QuicHttpStream : const HttpRequestInfo* request_info_; // The request body to send, if any, owned by the caller. UploadDataStream* request_body_stream_; + // The priority of the request. + RequestPriority priority_; // |response_info_| is the HTTP response data object which is filled in // when a the response headers are read. It is not owned by this stream. HttpResponseInfo* response_info_; diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 6a584f1..37242bf 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -19,6 +19,8 @@ #include "net/quic/quic_client_session.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_connection_helper.h" +#include "net/quic/quic_http_utils.h" +#include "net/quic/quic_reliable_client_stream.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_crypto_client_stream_factory.h" @@ -31,6 +33,7 @@ #include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_http_utils.h" #include "net/spdy/spdy_protocol.h" +#include "net/spdy/write_blocked_list.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -102,6 +105,14 @@ class AutoClosingStream : public QuicHttpStream { } // namespace +class QuicHttpStreamPeer { + public: + static QuicReliableClientStream* GetQuicReliableClientStream( + QuicHttpStream* stream) { + return stream->stream_; + } +}; + class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { protected: const static bool kFin = true; @@ -177,7 +188,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { receive_algorithm_ = new TestReceiveAlgorithm(NULL); EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)). Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _, _)). @@ -206,14 +217,16 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { new QuicHttpStream(session_->GetWeakPtr())); } - void SetRequestString(const std::string& method, const std::string& path) { + void SetRequestString(const std::string& method, + const std::string& path, + RequestPriority priority) { SpdyHeaderBlock headers; headers[":method"] = method; headers[":host"] = "www.google.com"; headers[":path"] = path; headers[":scheme"] = "http"; headers[":version"] = "HTTP/1.1"; - request_data_ = SerializeHeaderBlock(headers, true); + request_data_ = SerializeHeaderBlock(headers, true, priority); } void SetResponseString(const std::string& status, const std::string& body) { @@ -221,14 +234,17 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { headers[":status"] = status; headers[":version"] = "HTTP/1.1"; headers["content-type"] = "text/plain"; - response_data_ = SerializeHeaderBlock(headers, false) + body; + response_data_ = SerializeHeaderBlock(headers, false, DEFAULT_PRIORITY) + + body; } std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers, - bool write_priority) { + bool write_priority, + RequestPriority priority) { QuicSpdyCompressor compressor; if (framer_.version() >= QUIC_VERSION_9 && write_priority) { - return compressor.CompressHeadersWithPriority(0, headers); + return compressor.CompressHeadersWithPriority( + ConvertRequestPriorityToQuicPriority(priority), headers); } return compressor.CompressHeaders(headers); } @@ -249,7 +265,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { QuicEncryptedPacket* ConstructRstStreamPacket( QuicPacketSequenceNumber sequence_number) { InitializeHeader(sequence_number, false); - QuicRstStreamFrame frame(3, QUIC_SERVER_ERROR_PROCESSING_STREAM); + QuicRstStreamFrame frame(3, QUIC_ERROR_PROCESSING_STREAM); return ConstructPacket(header_, QuicFrame(&frame)); } @@ -350,7 +366,7 @@ TEST_F(QuicHttpStreamTest, IsConnectionReusable) { } TEST_F(QuicHttpStreamTest, GetRequest) { - SetRequestString("GET", "/"); + SetRequestString("GET", "/", DEFAULT_PRIORITY); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_)); Initialize(); @@ -393,7 +409,7 @@ TEST_F(QuicHttpStreamTest, GetRequest) { // Regression test for http://crbug.com/288128 TEST_F(QuicHttpStreamTest, GetRequestLargeResponse) { - SetRequestString("GET", "/"); + SetRequestString("GET", "/", DEFAULT_PRIORITY); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_)); Initialize(); @@ -440,7 +456,7 @@ TEST_F(QuicHttpStreamTest, GetRequestLargeResponse) { } TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) { - SetRequestString("GET", "/"); + SetRequestString("GET", "/", DEFAULT_PRIORITY); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_)); Initialize(); @@ -482,7 +498,7 @@ TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) { } TEST_F(QuicHttpStreamTest, SendPostRequest) { - SetRequestString("POST", "/"); + SetRequestString("POST", "/", DEFAULT_PRIORITY); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, !kFin, 0, request_data_)); AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, kFin, request_data_.length(), @@ -539,7 +555,7 @@ TEST_F(QuicHttpStreamTest, SendPostRequest) { } TEST_F(QuicHttpStreamTest, SendChunkedPostRequest) { - SetRequestString("POST", "/"); + SetRequestString("POST", "/", DEFAULT_PRIORITY); size_t chunk_size = strlen(kUploadData); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, !kFin, 0, request_data_)); AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, !kFin, @@ -601,7 +617,7 @@ TEST_F(QuicHttpStreamTest, SendChunkedPostRequest) { } TEST_F(QuicHttpStreamTest, DestroyedEarly) { - SetRequestString("GET", "/"); + SetRequestString("GET", "/", DEFAULT_PRIORITY); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_)); AddWrite(SYNCHRONOUS, ConstructRstStreamPacket(2)); use_closing_stream_ = true; @@ -613,9 +629,54 @@ TEST_F(QuicHttpStreamTest, DestroyedEarly) { EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, net_log_, callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, - callback_.callback())); + callback_.callback())); + EXPECT_EQ(&response_, stream_->GetResponseInfo()); + + // Ack the request. + scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0, 0)); + ProcessPacket(*ack); + EXPECT_EQ(ERR_IO_PENDING, + stream_->ReadResponseHeaders(callback_.callback())); + + // Send the response with a body. + SetResponseString("404 OK", "hello world!"); + scoped_ptr<QuicEncryptedPacket> resp( + ConstructDataPacket(2, false, kFin, 0, response_data_)); + + // In the course of processing this packet, the QuicHttpStream close itself. + ProcessPacket(*resp); + + EXPECT_TRUE(AtEof()); +} + +TEST_F(QuicHttpStreamTest, Priority) { + SetRequestString("GET", "/", MEDIUM); + AddWrite(SYNCHRONOUS, ConstructDataPacket(1, true, kFin, 0, request_data_)); + AddWrite(SYNCHRONOUS, ConstructRstStreamPacket(2)); + use_closing_stream_ = true; + Initialize(); + + request_.method = "GET"; + request_.url = GURL("http://www.google.com/"); + + EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, + net_log_, callback_.callback())); + + // Check that priority is highest. + QuicReliableClientStream* reliable_stream = + QuicHttpStreamPeer::GetQuicReliableClientStream(stream_.get()); + DCHECK(reliable_stream); + DCHECK_EQ(static_cast<QuicPriority>(kHighestPriority), + reliable_stream->EffectivePriority()); + + EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, + callback_.callback())); EXPECT_EQ(&response_, stream_->GetResponseInfo()); + // Check that priority has now dropped back to MEDIUM. + DCHECK_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority( + reliable_stream->EffectivePriority())); + // Ack the request. scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0, 0)); ProcessPacket(*ack); diff --git a/net/quic/quic_http_utils.cc b/net/quic/quic_http_utils.cc new file mode 100644 index 0000000..4a48626 --- /dev/null +++ b/net/quic/quic_http_utils.cc @@ -0,0 +1,23 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_http_utils.h" + +namespace net { + +QuicPriority ConvertRequestPriorityToQuicPriority( + const RequestPriority priority) { + DCHECK_GE(priority, MINIMUM_PRIORITY); + DCHECK_LT(priority, NUM_PRIORITIES); + return static_cast<QuicPriority>(HIGHEST - priority); +} + +NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority( + QuicPriority priority) { + // Handle invalid values gracefully. + return (priority >= 5) ? + IDLE : static_cast<RequestPriority>(HIGHEST - priority); +} + +} // namespace net diff --git a/net/quic/quic_http_utils.h b/net/quic/quic_http_utils.h new file mode 100644 index 0000000..c7e031a --- /dev/null +++ b/net/quic/quic_http_utils.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_HTTP_UTILS_H_ +#define NET_QUIC_QUIC_HTTP_UTILS_H_ + +#include "net/base/net_export.h" +#include "net/base/request_priority.h" +#include "net/quic/quic_protocol.h" + +namespace net { + +NET_EXPORT_PRIVATE QuicPriority ConvertRequestPriorityToQuicPriority( + RequestPriority priority); + +NET_EXPORT_PRIVATE RequestPriority ConvertQuicPriorityToRequestPriority( + QuicPriority priority); + +} // namespace net + +#endif // NET_QUIC_QUIC_HTTP_UTILS_H_ diff --git a/net/quic/quic_http_utils_test.cc b/net/quic/quic_http_utils_test.cc new file mode 100644 index 0000000..93b62e2 --- /dev/null +++ b/net/quic/quic_http_utils_test.cc @@ -0,0 +1,35 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_http_utils.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { + +TEST(QuicHttpUtilsTest, ConvertRequestPriorityToQuicPriority) { + EXPECT_EQ(0u, ConvertRequestPriorityToQuicPriority(HIGHEST)); + EXPECT_EQ(1u, ConvertRequestPriorityToQuicPriority(MEDIUM)); + EXPECT_EQ(2u, ConvertRequestPriorityToQuicPriority(LOW)); + EXPECT_EQ(3u, ConvertRequestPriorityToQuicPriority(LOWEST)); + EXPECT_EQ(4u, ConvertRequestPriorityToQuicPriority(IDLE)); +} + +TEST(QuicHttpUtilsTest, ConvertQuicPriorityToRequestPriority) { + EXPECT_EQ(HIGHEST, ConvertQuicPriorityToRequestPriority(0)); + EXPECT_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority(1)); + EXPECT_EQ(LOW, ConvertQuicPriorityToRequestPriority(2)); + EXPECT_EQ(LOWEST, ConvertQuicPriorityToRequestPriority(3)); + EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(4)); + // These are invalid values, but we should still handle them + // gracefully. TODO(rtenneti): should we test for all possible values of + // uint32? + for (int i = 5; i < kuint8max; ++i) { + EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(i)); + } +} + +} // namespace test +} // namespace net diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 801c7ef..a6cbff1 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -25,6 +25,7 @@ #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/quic_framer.h" +#include "net/quic/quic_http_utils.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_crypto_client_stream_factory.h" @@ -178,7 +179,8 @@ class QuicNetworkTransactionTest : public PlatformTest { std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) { QuicSpdyCompressor compressor; if (QuicVersionMax() >= QUIC_VERSION_9) { - return compressor.CompressHeadersWithPriority(0, headers); + return compressor.CompressHeadersWithPriority( + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers); } return compressor.CompressHeaders(headers); } diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index e1d0e21..819c872 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -12,6 +12,7 @@ using base::StringPiece; using std::make_pair; +using std::max; using std::min; using std::pair; using std::vector; @@ -71,6 +72,30 @@ void QuicPacketCreator::StopSendingVersion() { } } +void QuicPacketCreator::UpdateSequenceNumberLength( + QuicPacketSequenceNumber least_packet_awaited_by_peer, + QuicByteCount bytes_per_second) { + DCHECK_LE(least_packet_awaited_by_peer, sequence_number_ + 1); + // Since the packet creator will not change sequence number length mid FEC + // group, include the size of an FEC group to be safe. + const QuicPacketSequenceNumber current_delta = + options_.max_packets_per_fec_group + sequence_number_ + 1 + - least_packet_awaited_by_peer; + const uint64 congestion_window = + bytes_per_second / options_.max_packet_length; + const uint64 delta = max(current_delta, congestion_window); + + if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) { + options_.send_sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER; + } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) { + options_.send_sequence_number_length = PACKET_2BYTE_SEQUENCE_NUMBER; + } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) { + options_.send_sequence_number_length = PACKET_4BYTE_SEQUENCE_NUMBER; + } else { + options_.send_sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER; + } +} + bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) const { return BytesFree() > @@ -99,7 +124,12 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, StreamFramePacketOverhead( framer_->version(), PACKET_8BYTE_GUID, kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP)); - DCHECK(HasRoomForStreamFrame(id, offset)); + if (!HasRoomForStreamFrame(id, offset)) { + LOG(DFATAL) << "No room for Stream frame, BytesFree: " << BytesFree() + << " MinStreamFrameSize: " + << QuicFramer::GetMinStreamFrameSize( + framer_->version(), id, offset, true); + } const size_t free_bytes = BytesFree(); size_t bytes_consumed = 0; diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index 0e0a8c7..68b6216 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h @@ -70,6 +70,12 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { // Makes the framer not serialize the protocol version in sent packets. void StopSendingVersion(); + // Update the sequence number length to use in future packets as soon as it + // can be safely changed. + void UpdateSequenceNumberLength( + QuicPacketSequenceNumber least_packet_awaited_by_peer, + QuicByteCount bytes_per_second); + // The overhead the framing will add for a packet with one frame. static size_t StreamFramePacketOverhead( QuicVersion version, @@ -152,6 +158,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { QuicEncryptedPacket* SerializeVersionNegotiationPacket( const QuicVersionVector& supported_versions); + // Sequence number of the last created packet, or 0 if no packets have been + // created. QuicPacketSequenceNumber sequence_number() const { return sequence_number_; } diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index 193bb88..51133b6 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -333,6 +333,53 @@ TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) { client_framer_.ProcessPacket(*encrypted.get()); } +TEST_F(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) { + EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.set_sequence_number(64); + creator_.UpdateSequenceNumberLength(2, 10000); + EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.set_sequence_number(64 * 256); + creator_.UpdateSequenceNumberLength(2, 10000); + EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.set_sequence_number(64 * 256 * 256); + creator_.UpdateSequenceNumberLength(2, 10000); + EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.set_sequence_number(GG_UINT64_C(64) * 256 * 256 * 256 * 256); + creator_.UpdateSequenceNumberLength(2, 10000); + EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); +} + +TEST_F(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthBandwidth) { + EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.UpdateSequenceNumberLength(1, 10000); + EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.UpdateSequenceNumberLength(1, 10000 * 256); + EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.UpdateSequenceNumberLength(1, 10000 * 256 * 256); + EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); + + creator_.UpdateSequenceNumberLength( + 1, GG_UINT64_C(1000) * 256 * 256 * 256 * 256); + EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER, + creator_.options()->send_sequence_number_length); +} + INSTANTIATE_TEST_CASE_P(ToggleVersionSerialization, QuicPacketCreatorTest, ::testing::Values(false, true)); diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index 41161eb..4650068 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc @@ -88,6 +88,9 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, size_t total_bytes_consumed = 0; bool fin_consumed = false; + if (!packet_creator_->HasRoomForStreamFrame(id, offset)) { + SerializeAndSendPacket(); + } while (delegate_->CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, handshake)) { QuicFrame frame; @@ -100,8 +103,13 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, bytes_consumed = packet_creator_->CreateStreamFrame( id, data, offset + total_bytes_consumed, fin, &frame); } - bool success = AddFrame(frame); - DCHECK(success); + if (!AddFrame(frame)) { + LOG(DFATAL) << "Failed to add stream frame."; + // Inability to add a STREAM frame creates an unrecoverable hole in a + // the stream, so it's best to close the connection. + delegate_->CloseConnection(QUIC_INTERNAL_ERROR, false); + return QuicConsumedData(0, false); + } total_bytes_consumed += bytes_consumed; fin_consumed = fin && bytes_consumed == data.size(); diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index 75472a1..8d415bf 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h @@ -71,6 +71,7 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator { virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0; // Takes ownership of |packet.packet| and |packet.retransmittable_frames|. virtual bool OnSerializedPacket(const SerializedPacket& packet) = 0; + virtual void CloseConnection(QuicErrorCode error, bool from_peer) = 0; }; // Interface which gets callbacks from the QuicPacketGenerator at interesting diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index 8832042..eabbec1 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc @@ -40,6 +40,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface { MOCK_METHOD0(CreateAckFrame, QuicAckFrame*()); MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*()); MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet)); + MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool)); void SetCanWriteAnything() { EXPECT_CALL(*this, CanWrite(NOT_RETRANSMISSION, _, _)) @@ -455,6 +456,49 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) { CheckPacketIsFec(packet3_, 1); } +TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { + // Set the packet size be enough for two stream frames with 0 stream offset, + // but not enough for a stream frame of 0 offset and one with non-zero offset. + creator_.options()->max_packet_length = + NullEncrypter().GetCiphertextSize(0) + + GetPacketHeaderSize(creator_.options()->send_guid_length, + true, + creator_.options()->send_sequence_number_length, + NOT_IN_FEC_GROUP) + + // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger + // than the GetMinStreamFrameSize. + QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, false) + 3 + + QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, true) + 1; + delegate_.SetCanWriteAnything(); + { + InSequence dummy; + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet2_), Return(true))); + } + generator_.StartBatchOperations(); + // Queue enough data to prevent a stream frame with a non-zero offset from + // fitting. + QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 0, false); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(generator_.HasQueuedFrames()); + + // This frame will not fit with the existing frame, causing the queued frame + // to be serialized, and it will not fit with another frame like it, so it is + // serialized by itself. + consumed = generator_.ConsumeData(1, "bar", 3, true); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(generator_.HasQueuedFrames()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, packet_); + CheckPacketContains(contents, packet2_); +} + TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { delegate_.SetCanNotWrite(); diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 73a00c1..26e6c02 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -269,8 +269,8 @@ NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData( enum QuicRstStreamErrorCode { QUIC_STREAM_NO_ERROR = 0, - // There was some server error which halted stream processing. - QUIC_SERVER_ERROR_PROCESSING_STREAM, + // There was some error which halted stream processing. + QUIC_ERROR_PROCESSING_STREAM, // We got two fin or reset offsets which did not match. QUIC_MULTIPLE_TERMINATION_OFFSETS, // We got bad payload and can not respond to it at the protocol level. @@ -333,6 +333,8 @@ enum QuicErrorCode { QUIC_PEER_GOING_AWAY = 16, // A stream ID was invalid. QUIC_INVALID_STREAM_ID = 17, + // A priority was invalid. + QUIC_INVALID_PRIORITY = 49, // Too many streams already open. QUIC_TOO_MANY_OPEN_STREAMS = 18, // Received public reset for this connection. @@ -355,6 +357,8 @@ enum QuicErrorCode { QUIC_PACKET_WRITE_ERROR = 27, // There was an error while reading from the socket. QUIC_PACKET_READ_ERROR = 51, + // We received a STREAM_FRAME with no data and no fin flag set. + QUIC_INVALID_STREAM_FRAME = 50, // Crypto errors. diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc index 26e6815..0a3ec6d 100644 --- a/net/quic/quic_reliable_client_stream.cc +++ b/net/quic/quic_reliable_client_stream.cc @@ -7,6 +7,7 @@ #include "base/callback_helpers.h" #include "net/base/net_errors.h" #include "net/quic/quic_session.h" +#include "net/spdy/write_blocked_list.h" namespace net { @@ -54,6 +55,13 @@ void QuicReliableClientStream::OnCanWrite() { } } +QuicPriority QuicReliableClientStream::EffectivePriority() const { + if (delegate_->HasSendHeadersComplete()) { + return ReliableQuicStream::EffectivePriority(); + } + return kHighestPriority; +} + int QuicReliableClientStream::WriteStreamData( base::StringPiece data, bool fin, diff --git a/net/quic/quic_reliable_client_stream.h b/net/quic/quic_reliable_client_stream.h index c482ee6..bf3fc15 100644 --- a/net/quic/quic_reliable_client_stream.h +++ b/net/quic/quic_reliable_client_stream.h @@ -48,6 +48,9 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public ReliableQuicStream { // Called when the stream is closed because of an error. virtual void OnError(int error) = 0; + // Returns true if sending of headers has completed. + virtual bool HasSendHeadersComplete() = 0; + protected: virtual ~Delegate() {} @@ -65,6 +68,11 @@ class NET_EXPORT_PRIVATE QuicReliableClientStream : public ReliableQuicStream { virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE; virtual void TerminateFromPeer(bool half_close) OVERRIDE; virtual void OnCanWrite() OVERRIDE; + virtual QuicPriority EffectivePriority() const OVERRIDE; + + // While the server's set_priority shouldn't be called externally, the creator + // of client-side streams should be able to set the priority. + using ReliableQuicStream::set_priority; int WriteStreamData(base::StringPiece data, bool fin, diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc index 5041591..aaebda2 100644 --- a/net/quic/quic_reliable_client_stream_test.cc +++ b/net/quic/quic_reliable_client_stream_test.cc @@ -28,6 +28,7 @@ class MockDelegate : public QuicReliableClientStream::Delegate { MOCK_METHOD2(OnDataReceived, int(const char*, int)); MOCK_METHOD1(OnClose, void(QuicErrorCode)); MOCK_METHOD1(OnError, void(int)); + MOCK_METHOD0(HasSendHeadersComplete, bool()); private: DISALLOW_COPY_AND_ASSIGN(MockDelegate); @@ -86,7 +87,7 @@ TEST_F(QuicReliableClientStreamTest, WriteStreamData) { const size_t kDataLen = arraysize(kData1); // All data written. - EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce( + EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce( Return(QuicConsumedData(kDataLen, true))); TestCompletionCallback callback; EXPECT_EQ(OK, stream_.WriteStreamData(base::StringPiece(kData1, kDataLen), @@ -94,13 +95,14 @@ TEST_F(QuicReliableClientStreamTest, WriteStreamData) { } TEST_F(QuicReliableClientStreamTest, WriteStreamDataAsync) { + EXPECT_CALL(delegate_, HasSendHeadersComplete()); EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); const char kData1[] = "hello world"; const size_t kDataLen = arraysize(kData1); // No data written. - EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce( + EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce( Return(QuicConsumedData(0, false))); TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, @@ -109,7 +111,7 @@ TEST_F(QuicReliableClientStreamTest, WriteStreamDataAsync) { ASSERT_FALSE(callback.have_result()); // All data written. - EXPECT_CALL(session_, WriteData(stream_.id(), _, _, _)).WillOnce( + EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _)).WillOnce( Return(QuicConsumedData(kDataLen, true))); stream_.OnCanWrite(); ASSERT_TRUE(callback.have_result()); diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 5b7dc38..da980ca 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -63,6 +63,11 @@ class VisitorShim : public QuicConnectionVisitorInterface { return rc; } + virtual void OnSuccessfulVersionNegotiation( + const QuicVersion& version) OVERRIDE { + session_->OnSuccessfulVersionNegotiation(version); + } + virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE { session_->ConnectionClose(error, from_peer); // The session will go away, so don't bother with cleanup. @@ -233,11 +238,12 @@ bool QuicSession::OnCanWrite() { return !write_blocked_streams_.HasWriteBlockedStreams(); } -QuicConsumedData QuicSession::WriteData(QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin) { - return connection_->SendStreamData(id, data, offset, fin); +QuicConsumedData QuicSession::WritevData(QuicStreamId id, + const struct iovec* iov, + int count, + QuicStreamOffset offset, + bool fin) { + return connection_->SendvStreamData(id, iov, count, offset, fin); } void QuicSession::SendRstStream(QuicStreamId id, @@ -474,8 +480,8 @@ size_t QuicSession::GetNumOpenStreams() const { zombie_streams_.size(); } -void QuicSession::MarkWriteBlocked(QuicStreamId id) { - write_blocked_streams_.PushBack(id, 0); +void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { + write_blocked_streams_.PushBack(id, priority); } void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id, diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index c37b6e1..9916e58 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -66,6 +66,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE; virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE; virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE; + virtual void OnSuccessfulVersionNegotiation( + const QuicVersion& version) OVERRIDE{} // Not needed for HTTP. virtual void OnAck(const SequenceNumberSet& acked_packets) OVERRIDE {} virtual bool OnCanWrite() OVERRIDE; @@ -75,10 +77,12 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // indicating if the fin bit was consumed. This does not indicate the data // has been sent on the wire: it may have been turned into a packet and queued // if the socket was unexpectedly blocked. - virtual QuicConsumedData WriteData(QuicStreamId id, - base::StringPiece data, - QuicStreamOffset offset, - bool fin); + virtual QuicConsumedData WritevData(QuicStreamId id, + const struct iovec* iov, + int count, + QuicStreamOffset offset, + bool fin); + // Called by streams when they want to close the stream in both directions. virtual void SendRstStream(QuicStreamId id, QuicRstStreamErrorCode error); @@ -137,7 +141,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // been implicitly created. virtual size_t GetNumOpenStreams() const; - void MarkWriteBlocked(QuicStreamId id); + void MarkWriteBlocked(QuicStreamId id, QuicPriority priority); // Marks that |stream_id| is blocked waiting to decompress the // headers identified by |decompression_id|. diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index b7953ae..9d229a1 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -95,7 +95,7 @@ class TestSession : public QuicSession { // Helper method for gmock void MarkTwoWriteBlocked() { - this->MarkWriteBlocked(2); + this->MarkWriteBlocked(2, 0); } TestCryptoStream crypto_stream_; @@ -240,9 +240,9 @@ TEST_F(QuicSessionTest, OnCanWrite) { TestStream* stream4 = session_.CreateOutgoingReliableStream(); TestStream* stream6 = session_.CreateOutgoingReliableStream(); - session_.MarkWriteBlocked(2); - session_.MarkWriteBlocked(6); - session_.MarkWriteBlocked(4); + session_.MarkWriteBlocked(2, 0); + session_.MarkWriteBlocked(6, 0); + session_.MarkWriteBlocked(4, 0); InSequence s; EXPECT_CALL(*stream2, OnCanWrite()).WillOnce( @@ -259,9 +259,9 @@ TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) { TestStream* stream4 = session_.CreateOutgoingReliableStream(); session_.CreateOutgoingReliableStream(); // stream 6 - session_.MarkWriteBlocked(2); - session_.MarkWriteBlocked(6); - session_.MarkWriteBlocked(4); + session_.MarkWriteBlocked(2, 0); + session_.MarkWriteBlocked(6, 0); + session_.MarkWriteBlocked(4, 0); CloseStream(6); InSequence s; diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index fb9d474..a546d87 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -52,7 +52,7 @@ class QuicStreamFactoryTest : public ::testing::Test { header.fec_flag = false; header.fec_group = 0; - QuicRstStreamFrame rst(stream_id, QUIC_SERVER_ERROR_PROCESSING_STREAM); + QuicRstStreamFrame rst(stream_id, QUIC_ERROR_PROCESSING_STREAM); return scoped_ptr<QuicEncryptedPacket>( ConstructPacket(header, QuicFrame(&rst))); } diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index 7cf67d3..a57c05f 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc @@ -74,17 +74,21 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { return true; } - if (frame.fin) { - CloseStreamAtOffset(frame.offset + frame.data.size()); - } - QuicStreamOffset byte_offset = frame.offset; const char* data = frame.data.data(); size_t data_len = frame.data.size(); - if (data_len == 0) { - // TODO(rch): Close the stream if there was no data and no fin. - return true; + if (data_len == 0 && !frame.fin) { + // Stream frames must have data or a fin flag. + stream_->ConnectionClose(QUIC_INVALID_STREAM_FRAME, false); + return false; + } + + if (frame.fin) { + CloseStreamAtOffset(frame.offset + frame.data.size()); + if (data_len == 0) { + return true; + } } if (byte_offset == num_bytes_consumed_) { @@ -96,7 +100,7 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { return true; } if (bytes_consumed > data_len) { - stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM); + stream_->Close(QUIC_ERROR_PROCESSING_STREAM); return false; } else if (bytes_consumed == data_len) { FlushBufferedFrames(); @@ -211,7 +215,7 @@ void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) { << " end_offset: " << end_offset << " offset: " << it->first << " length: " << it->second.length(); - stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM); + stream_->Close(QUIC_ERROR_PROCESSING_STREAM); return; } @@ -262,7 +266,7 @@ void QuicStreamSequencer::FlushBufferedFrames() { return; } if (bytes_consumed > data->size()) { - stream_->Close(QUIC_SERVER_ERROR_PROCESSING_STREAM); // Programming error + stream_->Close(QUIC_ERROR_PROCESSING_STREAM); // Programming error return; } else if (bytes_consumed == data->size()) { frames_.erase(it); diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 878585b..21568d6 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -71,6 +71,7 @@ class MockStream : public ReliableQuicStream { MOCK_METHOD1(TerminateFromPeer, void(bool half_close)); MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len)); + MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer)); MOCK_METHOD1(Close, void(QuicRstStreamErrorCode error)); MOCK_METHOD0(OnCanWrite, void()); }; @@ -182,7 +183,8 @@ TEST_F(QuicStreamSequencerTest, FullFrameConsumed) { } TEST_F(QuicStreamSequencerTest, EmptyFrame) { - EXPECT_TRUE(sequencer_->OnFrame(0, "")); + EXPECT_CALL(stream_, ConnectionClose(QUIC_INVALID_STREAM_FRAME, false)); + EXPECT_FALSE(sequencer_->OnFrame(0, "")); EXPECT_EQ(0u, sequencer_->frames()->size()); EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); } @@ -399,7 +401,7 @@ TEST_F(QuicStreamSequencerTest, MarkConsumedError) { // Now, attempt to mark consumed more data than was readable // and expect the stream to be closed. - EXPECT_CALL(stream_, Close(QUIC_SERVER_ERROR_PROCESSING_STREAM)); + EXPECT_CALL(stream_, Close(QUIC_ERROR_PROCESSING_STREAM)); EXPECT_DFATAL(sequencer_->MarkConsumed(4), "Invalid argument to MarkConsumed. num_bytes_consumed_: 3 " "end_offset: 4 offset: 9 length: 17"); diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 74c90a0..cfb3cb7 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -120,7 +120,7 @@ const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) { switch (error) { RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR); RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR); - RETURN_STRING_LITERAL(QUIC_SERVER_ERROR_PROCESSING_STREAM); + RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM); RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS); RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD); RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY); @@ -171,6 +171,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP); RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND); RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID); + RETURN_STRING_LITERAL(QUIC_INVALID_PRIORITY); RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS); RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET); RETURN_STRING_LITERAL(QUIC_INVALID_VERSION); @@ -182,6 +183,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_ADDRESS); RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR); RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR); + RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_FRAME); RETURN_STRING_LITERAL(QUIC_PROOF_INVALID); RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG); RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT); diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 45b4fce..7a44713 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -6,6 +6,7 @@ #include "net/quic/quic_session.h" #include "net/quic/quic_spdy_decompressor.h" +#include "net/spdy/write_blocked_list.h" using base::StringPiece; using std::min; @@ -193,6 +194,12 @@ QuicConsumedData ReliableQuicStream::WriteData(StringPiece data, bool fin) { return WriteOrBuffer(data, fin); } + +void ReliableQuicStream::set_priority(QuicPriority priority) { + DCHECK_EQ(0u, stream_bytes_written_); + priority_ = priority; +} + QuicConsumedData ReliableQuicStream::WriteOrBuffer(StringPiece data, bool fin) { DCHECK(!fin_buffered_); @@ -235,27 +242,43 @@ void ReliableQuicStream::OnCanWrite() { QuicConsumedData ReliableQuicStream::WriteDataInternal( StringPiece data, bool fin) { + struct iovec iov = {const_cast<char*>(data.data()), + static_cast<size_t>(data.size())}; + return WritevDataInternal(&iov, 1, fin); +} + +QuicConsumedData ReliableQuicStream::WritevDataInternal(const struct iovec* iov, + int count, + bool fin) { if (write_side_closed_) { DLOG(ERROR) << "Attempt to write when the write side is closed"; return QuicConsumedData(0, false); } + size_t write_length = 0u; + for (int i = 0; i < count; ++i) { + write_length += iov[i].iov_len; + } QuicConsumedData consumed_data = - session()->WriteData(id(), data, stream_bytes_written_, fin); + session()->WritevData(id(), iov, count, stream_bytes_written_, fin); stream_bytes_written_ += consumed_data.bytes_consumed; - if (consumed_data.bytes_consumed == data.length()) { + if (consumed_data.bytes_consumed == write_length) { if (fin && consumed_data.fin_consumed) { fin_sent_ = true; CloseWriteSide(); } else if (fin && !consumed_data.fin_consumed) { - session_->MarkWriteBlocked(id()); + session_->MarkWriteBlocked(id(), EffectivePriority()); } } else { - session_->MarkWriteBlocked(id()); + session_->MarkWriteBlocked(id(), EffectivePriority()); } return consumed_data; } +QuicPriority ReliableQuicStream::EffectivePriority() const { + return priority(); +} + void ReliableQuicStream::CloseReadSide() { if (read_side_closed_) { return; @@ -283,7 +306,7 @@ uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) { total_bytes_consumed += StripPriorityAndHeaderId(data, data_len); data += total_bytes_consumed; data_len -= total_bytes_consumed; - if (data_len == 0) { + if (data_len == 0 || !session_->connection()->connected()) { return total_bytes_consumed; } } @@ -465,11 +488,18 @@ uint32 ReliableQuicStream::StripPriorityAndHeaderId( if (!priority_parsed_ && session_->connection()->version() >= QUIC_VERSION_9 && session_->connection()->is_server()) { + QuicPriority temporary_priority = priority_; total_bytes_parsed = StripUint32( - data, data_len, &headers_id_and_priority_buffer_, &priority_); + data, data_len, &headers_id_and_priority_buffer_, &temporary_priority); if (total_bytes_parsed > 0 && headers_id_and_priority_buffer_.size() == 0) { - // TODO(alyssar) check for priority out of bounds. priority_parsed_ = true; + // Spdy priorities are inverted, so the highest numerical value is the + // lowest legal priority. + if (temporary_priority > static_cast<QuicPriority>(kLowestPriority)) { + session_->connection()->SendConnectionClose(QUIC_INVALID_PRIORITY); + return 0; + } + priority_ = temporary_priority; } data += total_bytes_parsed; data_len -= total_bytes_parsed; diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 7ba5428..4fe4134 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -95,6 +95,12 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public // becomes unblocked. virtual void OnDecompressorAvailable(); + // By default, this is the same as priority(), however it allows streams + // to temporarily alter effective priority. For example if a SPDY stream has + // compressed but not written headers it can write the headers with a higher + // priority. + virtual QuicPriority EffectivePriority() const; + QuicStreamId id() const { return id_; } QuicRstStreamErrorCode stream_error() const { return stream_error_; } @@ -116,7 +122,6 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public bool GetSSLInfo(SSLInfo* ssl_info); bool headers_decompressed() const { return headers_decompressed_; } - QuicPriority priority() const { return priority_; } protected: // Returns a pair with the number of bytes consumed from data, and a boolean @@ -141,6 +146,13 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public QuicSession* session() { return session_; } + // Sets priority_ to priority. This should only be called before bytes are + // written to the server. + void set_priority(QuicPriority priority); + // This is protected because external classes should use EffectivePriority + // instead. + QuicPriority priority() const { return priority_; } + // Sends as much of 'data' to the connection as the connection will consume, // and then buffers any remaining data in queued_data_. // Returns (data.size(), true) as it always consumed all data: it returns for @@ -151,6 +163,13 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public // Returns the number of bytes consumed by the connection. QuicConsumedData WriteDataInternal(base::StringPiece data, bool fin); + // Sends as many bytes in the first |count| buffers of |iov| to the connection + // as the connection will consume. + // Returns the number of bytes consumed by the connection. + QuicConsumedData WritevDataInternal(const struct iovec* iov, + int count, + bool fin); + private: friend class test::ReliableQuicStreamPeer; friend class QuicStreamUtils; diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 1df13cf..063554d 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -126,9 +126,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) { 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); - // TODO(rch): figure out how to get StrEq working here. - //EXPECT_CALL(*session_, WriteData(kStreamId, StrEq(kData1), _, _)).WillOnce( - EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce( Return(QuicConsumedData(kDataLen, true))); EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed); EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams()); @@ -142,7 +140,7 @@ TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) { // Write no data and no fin. If we consume nothing we should not be write // blocked. EXPECT_DEBUG_DEATH({ - EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce( Return(QuicConsumedData(0, false))); stream_->WriteData(StringPiece(), false); EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams()); @@ -155,7 +153,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) { // Write some data and no fin. If we consume some but not all of the data, // we should be write blocked a not all the data was consumed. - EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce( Return(QuicConsumedData(1, false))); stream_->WriteData(StringPiece(kData1, 2), false); ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams()); @@ -169,7 +167,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) { // we should be write blocked because the fin was not consumed. // (This should never actually happen as the fin should be sent out with the // last data) - EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce( Return(QuicConsumedData(2, false))); stream_->WriteData(StringPiece(kData1, 2), true); ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams()); @@ -180,7 +178,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) { // Write no data and a fin. If we consume nothing we should be write blocked, // as the fin was not consumed. - EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _)).WillOnce( Return(QuicConsumedData(0, false))); stream_->WriteData(StringPiece(), true); ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams()); @@ -194,9 +192,7 @@ TEST_F(ReliableQuicStreamTest, WriteData) { 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); - // TODO(rch): figure out how to get StrEq working here. - //EXPECT_CALL(*session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( - EXPECT_CALL(*session_, WriteData(_, _, _, _)).WillOnce( + EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)).WillOnce( Return(QuicConsumedData(kDataLen - 1, false))); // The return will be kDataLen, because the last byte gets buffered. EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed); @@ -207,17 +203,14 @@ TEST_F(ReliableQuicStreamTest, WriteData) { // Make sure we get the tail of the first write followed by the bytes_consumed InSequence s; - //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData1[kDataLen - 1]), _, _)). - EXPECT_CALL(*session_, WriteData(_, _, _, _)). + EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)). WillOnce(Return(QuicConsumedData(1, false))); - //EXPECT_CALL(*session_, WriteData(_, StrEq(kData2), _, _)). - EXPECT_CALL(*session_, WriteData(_, _, _, _)). + EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)). WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); stream_->OnCanWrite(); - // And finally the end of the bytes_consumed - //EXPECT_CALL(*session_, WriteData(_, StrEq(&kData2[kDataLen - 2]), _, _)). - EXPECT_CALL(*session_, WriteData(_, _, _, _)). + // And finally the end of the bytes_consumed. + EXPECT_CALL(*session_, WritevData(_, _, 1, _, _)). WillOnce(Return(QuicConsumedData(2, true))); stream_->OnCanWrite(); } @@ -238,19 +231,20 @@ TEST_F(ReliableQuicStreamTest, ProcessHeaders) { Initialize(kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame(kStreamId, false, 0, compressed_headers); stream_->OnStreamFrame(frame); EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_), stream_->data()); - EXPECT_EQ(0u, stream_->priority()); + EXPECT_EQ(static_cast<QuicPriority>(kHighestPriority), + stream_->EffectivePriority()); } TEST_F(ReliableQuicStreamTest, ProcessHeadersWithInvalidHeaderId) { Initialize(kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); compressed_headers.replace(4, 1, 1, '\xFF'); // Illegal header id. QuicStreamFrame frame(kStreamId, false, 0, compressed_headers); @@ -262,7 +256,7 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBody) { Initialize(kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); string body = "this is the body"; string data = compressed_headers + body; QuicStreamFrame frame(kStreamId, false, 0, data); @@ -276,7 +270,7 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) { Initialize(kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(7, headers_); + compressor_->CompressHeadersWithPriority(kLowestPriority, headers_); string body = "this is the body"; string data = compressed_headers + body; @@ -308,14 +302,15 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) { ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, stream_->data()) << "split_point: " << split_point; } - EXPECT_EQ(7u, stream_->priority()); + EXPECT_EQ(static_cast<QuicPriority>(kLowestPriority), + stream_->EffectivePriority()); } TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) { Initialize(!kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); string body = "this is the body"; string data = compressed_headers + body; QuicStreamFrame frame(kStreamId, false, 0, data); @@ -345,7 +340,7 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyIncrementalReadv) { Initialize(!kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); string body = "this is the body"; string data = compressed_headers + body; QuicStreamFrame frame(kStreamId, false, 0, data); @@ -371,7 +366,7 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { Initialize(!kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); string body = "this is the body"; string data = compressed_headers + body; QuicStreamFrame frame(kStreamId, false, 0, data); @@ -401,14 +396,14 @@ TEST_F(ReliableQuicStreamTest, ProcessCorruptHeadersEarly) { Initialize(kShouldProcessData); string compressed_headers1 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); string decompressed_headers1 = SpdyUtils::SerializeUncompressedHeaders(headers_); headers_["content-type"] = "text/plain"; string compressed_headers2 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); // Corrupt the compressed data. compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1; QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); @@ -441,14 +436,14 @@ TEST_F(ReliableQuicStreamTest, ProcessPartialHeadersEarly) { Initialize(kShouldProcessData); string compressed_headers1 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); string decompressed_headers1 = SpdyUtils::SerializeUncompressedHeaders(headers_); headers_["content-type"] = "text/plain"; string compressed_headers2 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); string partial_compressed_headers = compressed_headers2.substr(0, compressed_headers2.length() / 2); QuicStreamFrame frame2(stream2_->id(), false, 0, partial_compressed_headers); @@ -492,14 +487,14 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { Initialize(kShouldProcessData); string compressed_headers1 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers1); string decompressed_headers1 = SpdyUtils::SerializeUncompressedHeaders(headers_); headers_["content-type"] = "text/plain"; string compressed_headers2 = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame2(stream2_->id(), false, 0, compressed_headers2); string decompressed_headers2 = SpdyUtils::SerializeUncompressedHeaders(headers_); @@ -528,7 +523,7 @@ TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) { Initialize(!kShouldProcessData); string compressed_headers = - compressor_->CompressHeadersWithPriority(0, headers_); + compressor_->CompressHeadersWithPriority(kHighestPriority, headers_); QuicStreamFrame frame1(stream_->id(), false, 0, compressed_headers); string decompressed_headers = SpdyUtils::SerializeUncompressedHeaders(headers_); diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 9381e05..750f9c7 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -254,7 +254,7 @@ bool PacketSavingConnection::SendOrQueuePacket( MockSession::MockSession(QuicConnection* connection, bool is_server) : QuicSession(connection, DefaultQuicConfig(), is_server) { - ON_CALL(*this, WriteData(_, _, _, _)) + ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index a90b212..38aa852 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -184,6 +184,8 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer)); MOCK_METHOD1(OnAck, void(const SequenceNumberSet& acked_packets)); MOCK_METHOD0(OnCanWrite, bool()); + MOCK_METHOD1(OnSuccessfulVersionNegotiation, + void(const QuicVersion& version)); private: DISALLOW_COPY_AND_ASSIGN(MockConnectionVisitor); @@ -285,10 +287,11 @@ class MockSession : public QuicSession { ReliableQuicStream*(QuicStreamId id)); MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*()); MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); - MOCK_METHOD4(WriteData, QuicConsumedData(QuicStreamId id, - base::StringPiece data, - QuicStreamOffset offset, - bool fin)); + MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id, + const struct iovec* iov, + int count, + QuicStreamOffset offset, + bool fin)); MOCK_METHOD0(IsHandshakeComplete, bool()); private: @@ -327,8 +330,9 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_METHOD3(OnIncomingAck, void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta)); MOCK_METHOD1(OnIncomingLoss, void(QuicTime)); - MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber, - QuicByteCount, Retransmission)); + MOCK_METHOD5(SentPacket, + bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount, + Retransmission, HasRetransmittableData)); MOCK_METHOD2(AbandoningPacket, void(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes)); MOCK_METHOD4(TimeUntilSend, QuicTime::Delta(QuicTime now, Retransmission, diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc index 6d6ea13..9f0321a 100644 --- a/net/tools/quic/quic_epoll_connection_helper_test.cc +++ b/net/tools/quic/quic_epoll_connection_helper_test.cc @@ -91,6 +91,8 @@ class QuicEpollConnectionHelperTest : public ::testing::Test { QuicBandwidth::FromKBitsPerSecond(100))); EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(Return( QuicTime::Delta::FromMilliseconds(100))); + ON_CALL(*send_algorithm_, SentPacket(_, _, _, _, _)) + .WillByDefault(Return(true)); } QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number, @@ -136,12 +138,14 @@ TEST_F(QuicEpollConnectionHelperTest, DISABLED_TestRetransmission) { arraysize(buffer) - 1; EXPECT_CALL(*send_algorithm_, - SentPacket(_, 1, packet_size, NOT_RETRANSMISSION)); + SentPacket(_, 1, packet_size, NOT_RETRANSMISSION, _)); EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, packet_size)); - connection_.SendStreamData(1, buffer, 0, false); + struct iovec iov = {const_cast<char*>(buffer), + static_cast<size_t>(3)}; + connection_.SendvStreamData(1, &iov, 1, 0, false); EXPECT_EQ(1u, helper_->header()->packet_sequence_number); EXPECT_CALL(*send_algorithm_, - SentPacket(_, 2, packet_size, IS_RETRANSMISSION)); + SentPacket(_, 2, packet_size, IS_RETRANSMISSION, _)); epoll_server_.AdvanceByAndCallCallbacks(kDefaultRetransmissionTimeMs * 1000); EXPECT_EQ(2u, helper_->header()->packet_sequence_number); @@ -150,7 +154,7 @@ TEST_F(QuicEpollConnectionHelperTest, DISABLED_TestRetransmission) { TEST_F(QuicEpollConnectionHelperTest, InitialTimeout) { EXPECT_TRUE(connection_.connected()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, _)); EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer)); epoll_server_.WaitForEventsAndExecuteCallbacks(); EXPECT_FALSE(connection_.connected()); @@ -167,7 +171,8 @@ TEST_F(QuicEpollConnectionHelperTest, TimeoutAfterSend) { EXPECT_EQ(5000, epoll_server_.NowInUsec()); // Send an ack so we don't set the retransmission alarm. - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, 1, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); connection_.SendAck(); // The original alarm will fire. We should not time out because we had a @@ -177,7 +182,8 @@ TEST_F(QuicEpollConnectionHelperTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, + SentPacket(_, 2, _, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); epoll_server_.WaitForEventsAndExecuteCallbacks(); EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000, epoll_server_.NowInUsec()); @@ -191,17 +197,19 @@ TEST_F(QuicEpollConnectionHelperTest, SendSchedulerDelayThenSend) { QuicPacket* packet = ConstructDataPacket(1, 0); EXPECT_CALL( *send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( - testing::Return(QuicTime::Delta::FromMicroseconds(1))); + Return(QuicTime::Delta::FromMicroseconds(1))); connection_.SendOrQueuePacket(ENCRYPTION_NONE, 1, packet, 0, HAS_RETRANSMITTABLE_DATA); - EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION, + _)); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)). - WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true)); + EXPECT_CALL(*send_algorithm_, + TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( + Return(QuicTime::Delta::Zero())); + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true)); epoll_server_.AdvanceByAndCallCallbacks(1); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } diff --git a/net/tools/quic/quic_reliable_server_stream_test.cc b/net/tools/quic/quic_reliable_server_stream_test.cc index b946d94..8e4ae4c 100644 --- a/net/tools/quic/quic_reliable_server_stream_test.cc +++ b/net/tools/quic/quic_reliable_server_stream_test.cc @@ -58,7 +58,9 @@ class QuicReliableServerStreamTest : public ::testing::Test { stream_.reset(new QuicSpdyServerStream(3, &session_)); } - QuicConsumedData ValidateHeaders(StringPiece headers) { + QuicConsumedData ValidateHeaders(const struct iovec* iov) { + StringPiece headers = + StringPiece(static_cast<const char*>(iov[0].iov_base), iov[0].iov_len); headers_string_ = SpdyUtils::SerializeResponseHeaders( response_headers_); QuicSpdyDecompressor decompressor; @@ -119,13 +121,17 @@ class QuicReliableServerStreamTest : public ::testing::Test { string body_; }; -QuicConsumedData ConsumeAllData(QuicStreamId id, StringPiece data, - QuicStreamOffset offset, bool fin) { - return QuicConsumedData(data.size(), fin); +QuicConsumedData ConsumeAllData(QuicStreamId id, const struct iovec* iov, + int count, QuicStreamOffset offset, bool fin) { + ssize_t consumed_length = 0; + for (int i = 0; i < count; ++i) { + consumed_length += iov[i].iov_len; + } + return QuicConsumedData(consumed_length, fin); } TEST_F(QuicReliableServerStreamTest, TestFraming) { - EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()). + EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(AnyNumber()). WillRepeatedly(Invoke(ConsumeAllData)); EXPECT_EQ(headers_string_.size(), stream_->ProcessData( @@ -138,7 +144,7 @@ TEST_F(QuicReliableServerStreamTest, TestFraming) { } TEST_F(QuicReliableServerStreamTest, TestFramingOnePacket) { - EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(AnyNumber()). + EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(AnyNumber()). WillRepeatedly(Invoke(ConsumeAllData)); string message = headers_string_ + body_; @@ -156,7 +162,7 @@ TEST_F(QuicReliableServerStreamTest, TestFramingExtraData) { string large_body = "hello world!!!!!!"; // We'll automatically write out an error (headers + body) - EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(2). + EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(2). WillRepeatedly(Invoke(ConsumeAllData)); EXPECT_EQ(headers_string_.size(), stream_->ProcessData( @@ -183,11 +189,11 @@ TEST_F(QuicReliableServerStreamTest, TestSendResponse) { response_headers_.ReplaceOrAppendHeader("content-length", "3"); InSequence s; - EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1) + EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1) .WillOnce(WithArgs<1>(Invoke( this, &QuicReliableServerStreamTest::ValidateHeaders))); - StringPiece kBody = "Yum"; - EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1). + + EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1). WillOnce(Return(QuicConsumedData(3, true))); stream_->SendResponse(); @@ -201,11 +207,11 @@ TEST_F(QuicReliableServerStreamTest, TestSendErrorResponse) { response_headers_.ReplaceOrAppendHeader("content-length", "3"); InSequence s; - EXPECT_CALL(session_, WriteData(_, _, _, _)).Times(1) + EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1) .WillOnce(WithArgs<1>(Invoke( this, &QuicReliableServerStreamTest::ValidateHeaders))); - StringPiece kBody = "bad"; - EXPECT_CALL(session_, WriteData(_, kBody, _, _)).Times(1). + + EXPECT_CALL(session_, WritevData(_, _, 1, _, _)).Times(1). WillOnce(Return(QuicConsumedData(3, true))); stream_->SendErrorResponse(); diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h index ec4d257..5d32b30 100644 --- a/net/tools/quic/quic_spdy_client_stream.h +++ b/net/tools/quic/quic_spdy_client_stream.h @@ -34,6 +34,10 @@ class QuicSpdyClientStream : public QuicReliableClientStream { base::StringPiece body, bool fin) OVERRIDE; + // While the server's set_priority shouldn't be called externally, the creator + // of client-side streams should be able to set the priority. + using QuicReliableClientStream::set_priority; + private: int ParseResponseHeaders(); diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 03600f2..272786e 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -11,6 +11,7 @@ #include "net/quic/crypto/proof_verifier.h" #include "net/tools/flip_server/balsa_headers.h" #include "net/tools/quic/quic_epoll_connection_helper.h" +#include "net/tools/quic/quic_spdy_client_stream.h" #include "net/tools/quic/test_tools/http_message_test_utils.h" #include "url/gurl.h" @@ -157,6 +158,7 @@ void QuicTestClient::Initialize(IPEndPoint address, server_address_ = address; stream_ = NULL; stream_error_ = QUIC_STREAM_NO_ERROR; + priority_ = 3; bytes_read_ = 0; bytes_written_= 0; never_connected_ = true; @@ -243,10 +245,13 @@ QuicReliableClientStream* QuicTestClient::GetOrCreateStream() { } if (!stream_) { stream_ = client_->CreateReliableClientStream(); - if (stream_ != NULL) { - stream_->set_visitor(this); + if (stream_ == NULL) { + return NULL; } + stream_->set_visitor(this); + reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_); } + return stream_; } diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 74bfc24..3cd71d5 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -107,6 +107,8 @@ class QuicTestClient : public ReliableQuicStream::Visitor { void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; } + void set_priority(QuicPriority priority) { priority_ = priority; } + private: void Initialize(IPEndPoint address, const string& hostname, bool secure); @@ -118,6 +120,8 @@ class QuicTestClient : public ReliableQuicStream::Visitor { QuicRstStreamErrorCode stream_error_; BalsaHeaders headers_; + QuicPriority priority_; + string response_; uint64 bytes_read_; uint64 bytes_written_; |