diff options
Diffstat (limited to 'net')
90 files changed, 1188 insertions, 621 deletions
diff --git a/net/net.gyp b/net/net.gyp index 5782b7a..4e362539 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -913,6 +913,8 @@ 'quic/quic_time.h', 'quic/quic_utils.cc', 'quic/quic_utils.h', + 'quic/quic_write_blocked_list.cc', + 'quic/quic_write_blocked_list.h', 'quic/reliable_quic_stream.cc', 'quic/reliable_quic_stream.h', 'quic/spdy_utils.cc', @@ -1865,8 +1867,6 @@ 'quic/test_tools/quic_test_packet_maker.h', 'quic/test_tools/quic_test_utils.cc', 'quic/test_tools/quic_test_utils.h', - 'quic/test_tools/quic_test_writer.cc', - 'quic/test_tools/quic_test_writer.h', 'quic/test_tools/reliable_quic_stream_peer.cc', 'quic/test_tools/reliable_quic_stream_peer.h', 'quic/test_tools/simple_quic_framer.cc', @@ -1906,6 +1906,7 @@ 'quic/quic_stream_sequencer_test.cc', 'quic/quic_time_test.cc', 'quic/quic_utils_test.cc', + 'quic/quic_write_blocked_list_test.cc', 'quic/reliable_quic_stream_test.cc', 'server/http_server_response_info_unittest.cc', 'server/http_server_unittest.cc', @@ -2906,6 +2907,8 @@ 'tools/quic/quic_epoll_connection_helper.h', 'tools/quic/quic_in_memory_cache.cc', 'tools/quic/quic_in_memory_cache.h', + 'tools/quic/quic_packet_writer_wrapper.cc', + 'tools/quic/quic_packet_writer_wrapper.h', 'tools/quic/quic_server.cc', 'tools/quic/quic_server.h', 'tools/quic/quic_server_session.cc', diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index e9c219bd..9e198e9 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -58,16 +58,8 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame( void FixRateSender::OnPacketAcked( QuicPacketSequenceNumber /*acked_sequence_number*/, - QuicByteCount bytes_acked, - QuicTime::Delta rtt) { - // RTT can't be negative. - DCHECK_LE(0, rtt.ToMicroseconds()); - + QuicByteCount bytes_acked) { data_in_flight_ -= bytes_acked; - if (rtt.IsInfinite()) { - return; - } - latest_rtt_ = rtt; } void FixRateSender::OnPacketLost(QuicPacketSequenceNumber /*sequence_number*/, @@ -127,6 +119,15 @@ QuicBandwidth FixRateSender::BandwidthEstimate() const { return bitrate_; } +void FixRateSender::UpdateRtt(QuicTime::Delta rtt_sample) { + // RTT can't be negative. + DCHECK_LE(0, rtt_sample.ToMicroseconds()); + if (rtt_sample.IsInfinite()) { + return; + } + latest_rtt_ = rtt_sample; +} + QuicTime::Delta FixRateSender::SmoothedRtt() const { // TODO(satyamshekhar): Calculate and return smoothed rtt. return latest_rtt_; diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 0ce8016..688cf3a 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -31,8 +31,7 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { QuicTime feedback_receive_time, const SentPacketsMap& sent_packets) OVERRIDE; virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) OVERRIDE; + QuicByteCount acked_bytes) OVERRIDE; virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number, QuicTime ack_receive_time) OVERRIDE; virtual bool OnPacketSent( @@ -50,6 +49,7 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; + virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta SmoothedRtt() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index 752d37f..70cbb96 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -29,14 +29,12 @@ class FixRateReceiverPeer : public FixRateReceiver { class FixRateTest : public ::testing::Test { protected: FixRateTest() - : rtt_(QuicTime::Delta::FromMilliseconds(30)), - sender_(new FixRateSender(&clock_)), + : sender_(new FixRateSender(&clock_)), receiver_(new FixRateReceiverPeer()), start_(clock_.Now()) { // Make sure clock does not start at 0. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); } - const QuicTime::Delta rtt_; MockClock clock_; SendAlgorithmInterface::SentPacketsMap unused_packet_map_; scoped_ptr<FixRateSender> sender_; @@ -78,9 +76,9 @@ TEST_F(FixRateTest, SenderAPI) { EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); - sender_->OnPacketAcked(1, kDefaultMaxPacketSize, rtt_); - sender_->OnPacketAcked(2, kDefaultMaxPacketSize, rtt_); - sender_->OnPacketAcked(3, 600, rtt_); + sender_->OnPacketAcked(1, kDefaultMaxPacketSize); + sender_->OnPacketAcked(2, kDefaultMaxPacketSize); + sender_->OnPacketAcked(3, 600); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); } @@ -110,8 +108,8 @@ TEST_F(FixRateTest, FixRatePacing) { QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); clock_.AdvanceTime(advance_time); - sender_->OnPacketAcked(sequence_number - 1, packet_size, rtt_); - sender_->OnPacketAcked(sequence_number - 2, packet_size, rtt_); + sender_->OnPacketAcked(sequence_number - 1, packet_size); + sender_->OnPacketAcked(sequence_number - 2, packet_size); acc_advance_time = acc_advance_time.Add(advance_time); } EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(), diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc index 1b86b63..b0698ac 100644 --- a/net/quic/congestion_control/inter_arrival_sender.cc +++ b/net/quic/congestion_control/inter_arrival_sender.cc @@ -216,27 +216,10 @@ bool InterArrivalSender::ProbingPhase(QuicTime feedback_receive_time) { void InterArrivalSender::OnPacketAcked( QuicPacketSequenceNumber /*acked_sequence_number*/, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) { - // RTT can't be negative. - DCHECK_LE(0, rtt.ToMicroseconds()); - + QuicByteCount acked_bytes) { if (probing_) { probe_->OnAcknowledgedPacket(acked_bytes); } - - if (rtt.IsInfinite()) { - return; - } - - if (smoothed_rtt_.IsZero()) { - smoothed_rtt_ = rtt; - } else { - smoothed_rtt_ = QuicTime::Delta::FromMicroseconds( - kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() + - kAlpha * rtt.ToMicroseconds()); - } - state_machine_->set_rtt(smoothed_rtt_); } void InterArrivalSender::OnPacketLost( @@ -337,6 +320,24 @@ QuicBandwidth InterArrivalSender::BandwidthEstimate() const { return current_bandwidth_; } +void InterArrivalSender::UpdateRtt(QuicTime::Delta rtt) { + // RTT can't be negative. + DCHECK_LE(0, rtt.ToMicroseconds()); + + if (rtt.IsInfinite()) { + return; + } + + if (smoothed_rtt_.IsZero()) { + smoothed_rtt_ = rtt; + } else { + smoothed_rtt_ = QuicTime::Delta::FromMicroseconds( + kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() + + kAlpha * rtt.ToMicroseconds()); + } + state_machine_->set_rtt(smoothed_rtt_); +} + QuicTime::Delta InterArrivalSender::SmoothedRtt() const { if (smoothed_rtt_.IsZero()) { return QuicTime::Delta::FromMilliseconds(kInitialRttMs); diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h index ac1c262..7760cef 100644 --- a/net/quic/congestion_control/inter_arrival_sender.h +++ b/net/quic/congestion_control/inter_arrival_sender.h @@ -39,8 +39,7 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { QuicTime feedback_receive_time, const SentPacketsMap& sent_packets) OVERRIDE; virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) OVERRIDE; + QuicByteCount acked_bytes) OVERRIDE; virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number, QuicTime ack_receive_time) OVERRIDE; virtual bool OnPacketSent( @@ -58,6 +57,7 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; + virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta SmoothedRtt() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; diff --git a/net/quic/congestion_control/inter_arrival_sender_test.cc b/net/quic/congestion_control/inter_arrival_sender_test.cc index ff83b48..61655dd 100644 --- a/net/quic/congestion_control/inter_arrival_sender_test.cc +++ b/net/quic/congestion_control/inter_arrival_sender_test.cc @@ -18,8 +18,7 @@ namespace test { class InterArrivalSenderTest : public ::testing::Test { protected: InterArrivalSenderTest() - : rtt_(QuicTime::Delta::FromMilliseconds(60)), - one_ms_(QuicTime::Delta::FromMilliseconds(1)), + : one_ms_(QuicTime::Delta::FromMilliseconds(1)), one_s_(QuicTime::Delta::FromMilliseconds(1000)), nine_ms_(QuicTime::Delta::FromMilliseconds(9)), send_start_time_(send_clock_.Now()), @@ -54,7 +53,7 @@ class InterArrivalSenderTest : public ::testing::Test { void AckNPackets(int n) { for (int i = 0; i < n; ++i) { sender_.OnPacketAcked( - acked_sequence_number_++, kDefaultMaxPacketSize, rtt_); + acked_sequence_number_++, kDefaultMaxPacketSize); } } @@ -106,7 +105,6 @@ class InterArrivalSenderTest : public ::testing::Test { return send_clock_.ApproximateNow().Subtract(send_start_time_); } - const QuicTime::Delta rtt_; const QuicTime::Delta one_ms_; const QuicTime::Delta one_s_; const QuicTime::Delta nine_ms_; @@ -504,6 +502,7 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToDelay) { } TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { + sender_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60)); QuicBandwidth expected_min_bitrate = QuicBandwidth::FromKBitsPerSecond(10); QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. @@ -541,7 +540,7 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); - sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize, rtt_); + sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize); acked_sequence_number_ += 2; // Create a loss by not acking both packets. SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_); } @@ -556,7 +555,7 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); - sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize, rtt_); + sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize); acked_sequence_number_ += 2; // Create a loss by not acking both packets. SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_); diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc index cbd2d12..8d346ab 100644 --- a/net/quic/congestion_control/pacing_sender.cc +++ b/net/quic/congestion_control/pacing_sender.cc @@ -36,9 +36,8 @@ void PacingSender::OnIncomingQuicCongestionFeedbackFrame( void PacingSender::OnPacketAcked( QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) { - sender_->OnPacketAcked(acked_sequence_number, acked_bytes, rtt); + QuicByteCount acked_bytes) { + sender_->OnPacketAcked(acked_sequence_number, acked_bytes); } void PacingSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, @@ -123,6 +122,10 @@ QuicBandwidth PacingSender::BandwidthEstimate() const { return sender_->BandwidthEstimate(); } +void PacingSender::UpdateRtt(QuicTime::Delta rtt_sample) { + sender_->UpdateRtt(rtt_sample); +} + QuicTime::Delta PacingSender::SmoothedRtt() const { return sender_->SmoothedRtt(); } diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h index 621c7c6..c8ffe0b 100644 --- a/net/quic/congestion_control/pacing_sender.h +++ b/net/quic/congestion_control/pacing_sender.h @@ -37,8 +37,7 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface { QuicTime feedback_receive_time, const SendAlgorithmInterface::SentPacketsMap& sent_packets) OVERRIDE; virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) OVERRIDE; + QuicByteCount acked_bytes) OVERRIDE; virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number, QuicTime ack_receive_time) OVERRIDE; virtual bool OnPacketSent(QuicTime sent_time, @@ -55,6 +54,7 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface { HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; + virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta SmoothedRtt() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index 35460da..df63bba 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -63,8 +63,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Called for each received ACK, with sequence number from remote peer. virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) = 0; + QuicByteCount acked_bytes) = 0; // Indicates a loss event of one packet. |sequence_number| is the // sequence number of the lost packet. @@ -101,6 +100,9 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Returns 0 when it does not have an estimate. virtual QuicBandwidth BandwidthEstimate() const = 0; + // Updates the smoothed RTT based on a new sample. + virtual void UpdateRtt(QuicTime::Delta rtt_sample) = 0; + // TODO(satyamshekhar): Monitor MinRtt. virtual QuicTime::Delta SmoothedRtt() const = 0; diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 1c4a655..5e6e3e3 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -89,15 +89,12 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( } void TcpCubicSender::OnPacketAcked( - QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) { + QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes) { DCHECK_GE(bytes_in_flight_, acked_bytes); bytes_in_flight_ -= acked_bytes; largest_acked_sequence_number_ = max(acked_sequence_number, largest_acked_sequence_number_); CongestionAvoidance(acked_sequence_number); - AckAccounting(rtt); if (end_sequence_number_ == acked_sequence_number) { DVLOG(1) << "Start update end sequence number @" << acked_sequence_number; update_end_sequence_number_ = true; @@ -286,7 +283,7 @@ void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { } } -void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) { +void TcpCubicSender::UpdateRtt(QuicTime::Delta rtt) { if (rtt.IsInfinite() || rtt.IsZero()) { DVLOG(1) << "Ignoring rtt, because it's " << (rtt.IsZero() ? "Zero" : "Infinite"); diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index fcb370d..0554428 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -43,8 +43,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { QuicTime feedback_receive_time, const SentPacketsMap& sent_packets) OVERRIDE; virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number, - QuicByteCount acked_bytes, - QuicTime::Delta rtt) OVERRIDE; + QuicByteCount acked_bytes) OVERRIDE; virtual void OnPacketLost(QuicPacketSequenceNumber largest_loss, QuicTime ack_receive_time) OVERRIDE; virtual bool OnPacketSent(QuicTime sent_time, @@ -61,6 +60,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { HasRetransmittableData has_retransmittable_data, IsHandshake handshake) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; + virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta SmoothedRtt() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; @@ -72,7 +72,6 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { QuicByteCount AvailableSendWindow(); QuicByteCount SendWindow(); void Reset(); - void AckAccounting(QuicTime::Delta rtt); void CongestionAvoidance(QuicPacketSequenceNumber ack); bool IsCwndLimited() const; void OnTimeOut(); diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index c76040a..f17dda7 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -35,14 +35,12 @@ class TcpCubicSenderPeer : public TcpCubicSender { using TcpCubicSender::AvailableSendWindow; using TcpCubicSender::SendWindow; - using TcpCubicSender::AckAccounting; }; class TcpCubicSenderTest : public ::testing::Test { protected: TcpCubicSenderTest() - : rtt_(QuicTime::Delta::FromMilliseconds(60)), - one_ms_(QuicTime::Delta::FromMilliseconds(1)), + : one_ms_(QuicTime::Delta::FromMilliseconds(1)), sender_(new TcpCubicSenderPeer(&clock_, true, kDefaultMaxCongestionWindowTCP)), receiver_(new TcpReceiver()), @@ -67,12 +65,12 @@ class TcpCubicSenderTest : public ::testing::Test { void AckNPackets(int n) { for (int i = 0; i < n; ++i) { acked_sequence_number_++; - sender_->OnPacketAcked(acked_sequence_number_, kDefaultTCPMSS, rtt_); + sender_->UpdateRtt(QuicTime::Delta::FromMilliseconds(60)); + sender_->OnPacketAcked(acked_sequence_number_, kDefaultTCPMSS); } clock_.AdvanceTime(one_ms_); // 1 millisecond. } - const QuicTime::Delta rtt_; const QuicTime::Delta one_ms_; MockClock clock_; SendAlgorithmInterface::SentPacketsMap not_used_; @@ -158,12 +156,8 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAck); EXPECT_EQ(expected_send_window, sender_->SendWindow()); EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - // We should now have fallen out of slow start. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->SendWindow()); + // We should now have fallen out of slow start. // Testing Reno phase. // We should need 141(65*2+1+10) ACK:ed packets before increasing window by // one. @@ -261,7 +255,7 @@ TEST_F(TcpCubicSenderTest, RetransmissionDelay) { const int64 kDeviationMs = 3; EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay()); - sender_->AckAccounting(QuicTime::Delta::FromMilliseconds(kRttMs)); + sender_->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs)); // Initial value is to set the median deviation to half of the initial // rtt, the median in then multiplied by a factor of 4 and finally the @@ -272,9 +266,9 @@ TEST_F(TcpCubicSenderTest, RetransmissionDelay) { for (int i = 0; i < 100; ++i) { // Run to make sure that we converge. - sender_->AckAccounting( + sender_->UpdateRtt( QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs)); - sender_->AckAccounting( + sender_->UpdateRtt( QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs)); } expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4); diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc index 07c3ea4..1d32093 100644 --- a/net/quic/crypto/crypto_server_test.cc +++ b/net/quic/crypto/crypto_server_test.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/basictypes.h" #include "base/strings/string_number_conversions.h" #include "crypto/secure_hash.h" #include "net/quic/crypto/crypto_utils.h" diff --git a/net/quic/crypto/curve25519_key_exchange.cc b/net/quic/crypto/curve25519_key_exchange.cc index 3b888045..8ed95aa 100644 --- a/net/quic/crypto/curve25519_key_exchange.cc +++ b/net/quic/crypto/curve25519_key_exchange.cc @@ -4,6 +4,7 @@ #include "net/quic/crypto/curve25519_key_exchange.h" +#include "base/basictypes.h" #include "base/logging.h" #include "crypto/curve25519.h" #include "net/quic/crypto/quic_random.h" diff --git a/net/quic/crypto/local_strike_register_client.h b/net/quic/crypto/local_strike_register_client.h index abd610b..fe8ae93 100644 --- a/net/quic/crypto/local_strike_register_client.h +++ b/net/quic/crypto/local_strike_register_client.h @@ -5,6 +5,7 @@ #ifndef NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_ #define NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_ +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "base/synchronization/lock.h" #include "net/base/net_export.h" diff --git a/net/quic/crypto/strike_register_client.h b/net/quic/crypto/strike_register_client.h index 3555e85..e37827a 100644 --- a/net/quic/crypto/strike_register_client.h +++ b/net/quic/crypto/strike_register_client.h @@ -7,6 +7,7 @@ #include <string> +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/quic/quic_time.h" diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h index 943c206..ebc7092 100644 --- a/net/quic/quic_client_session.h +++ b/net/quic/quic_client_session.h @@ -12,12 +12,14 @@ #include <string> +#include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "net/base/completion_callback.h" #include "net/proxy/proxy_server.h" #include "net/quic/quic_connection_logger.h" #include "net/quic/quic_crypto_client_stream.h" +#include "net/quic/quic_protocol.h" #include "net/quic/quic_reliable_client_stream.h" #include "net/quic/quic_session.h" diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 51991be..479373e 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -166,7 +166,6 @@ QuicConnection::QuicConnection(QuicGuid guid, peer_address_(address), largest_seen_packet_with_ack_(0), pending_version_negotiation_packet_(false), - write_blocked_(false), received_packet_manager_(kTCP), ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))), @@ -772,9 +771,6 @@ void QuicConnection::SendVersionNegotiationPacket() { WriteResult result = writer_->WritePacket(version_packet->data(), version_packet->length(), self_address().address(), peer_address(), this); - if (result.status == WRITE_STATUS_BLOCKED) { - write_blocked_ = true; - } if (result.status == WRITE_STATUS_OK || (result.status == WRITE_STATUS_BLOCKED && writer_->IsWriteBlockedDataBuffered())) { @@ -881,21 +877,9 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, } bool QuicConnection::OnCanWrite() { - write_blocked_ = false; - return DoWrite(); -} - -bool QuicConnection::WriteIfNotBlocked() { - if (write_blocked_) { - return false; - } - return DoWrite(); -} + DCHECK(!writer_->IsWriteBlocked()); -bool QuicConnection::DoWrite() { - DCHECK(!write_blocked_); WriteQueuedPackets(); - WritePendingRetransmissions(); IsHandshake pending_handshake = visitor_->HasPendingHandshake() ? @@ -925,7 +909,13 @@ bool QuicConnection::DoWrite() { } } - return !write_blocked_; + return !writer_->IsWriteBlocked(); +} + +void QuicConnection::WriteIfNotBlocked() { + if (!writer_->IsWriteBlocked()) { + OnCanWrite(); + } } bool QuicConnection::ProcessValidatedPacket() { @@ -946,15 +936,16 @@ bool QuicConnection::ProcessValidatedPacket() { return true; } -bool QuicConnection::WriteQueuedPackets() { - DCHECK(!write_blocked_); +void QuicConnection::WriteQueuedPackets() { + DCHECK(!writer_->IsWriteBlocked()); if (pending_version_negotiation_packet_) { SendVersionNegotiationPacket(); } QueuedPacketList::iterator packet_iterator = queued_packets_.begin(); - while (!write_blocked_ && packet_iterator != queued_packets_.end()) { + while (!writer_->IsWriteBlocked() && + packet_iterator != queued_packets_.end()) { if (WritePacket(packet_iterator->encryption_level, packet_iterator->sequence_number, packet_iterator->packet, @@ -962,15 +953,14 @@ bool QuicConnection::WriteQueuedPackets() { packet_iterator->retransmittable, packet_iterator->handshake, packet_iterator->forced)) { + delete packet_iterator->packet; packet_iterator = queued_packets_.erase(packet_iterator); } else { // Continue, because some queued packets may still be writable. - // This can happen if a retransmit send fail. + // This can happen if a retransmit send fails. ++packet_iterator; } } - - return !write_blocked_; } void QuicConnection::WritePendingRetransmissions() { @@ -1035,7 +1025,7 @@ bool QuicConnection::ShouldGeneratePacket( bool QuicConnection::CanWrite(TransmissionType transmission_type, HasRetransmittableData retransmittable, IsHandshake handshake) { - if (write_blocked_) { + if (writer_->IsWriteBlocked()) { return false; } @@ -1073,16 +1063,13 @@ bool QuicConnection::WritePacket(EncryptionLevel level, IsHandshake handshake, Force forced) { if (ShouldDiscardPacket(level, sequence_number, retransmittable)) { - delete packet; return true; } - // If we're write blocked, we know we can't write. - if (write_blocked_) { - return false; - } - - // If we are not forced and we can't write, then simply return false; + // If the writer is blocked, we must not write. However, if the packet is + // forced (i.e., it's the ConnectionClose packet), we still need to encrypt it + // and hand it off to TimeWaitListManager. + // We check nonforced packets here and forced after encryption. if (forced == NO_FORCE && !CanWrite(transmission_type, retransmittable, handshake)) { return false; @@ -1098,20 +1085,29 @@ bool QuicConnection::WritePacket(EncryptionLevel level, sequence_number_of_last_inorder_packet_ = sequence_number; } - scoped_ptr<QuicEncryptedPacket> encrypted( - framer_.EncryptPacket(level, sequence_number, *packet)); - if (encrypted.get() == NULL) { + QuicEncryptedPacket* encrypted = + framer_.EncryptPacket(level, sequence_number, *packet); + if (encrypted == NULL) { LOG(DFATAL) << ENDPOINT << "Failed to encrypt packet number " << sequence_number; + // CloseConnection does not send close packet, so no infinite loop here. CloseConnection(QUIC_ENCRYPTION_FAILURE, false); return false; } - // If it's the ConnectionClose packet, the only FORCED frame type, - // clone a copy for resending later by the TimeWaitListManager. - if (forced == FORCE) { + // Forced packets are eventually owned by TimeWaitListManager; nonforced are + // deleted at the end of this call. + scoped_ptr<QuicEncryptedPacket> encrypted_deleter; + if (forced == NO_FORCE) { + encrypted_deleter.reset(encrypted); + } else { // forced == FORCE DCHECK(connection_close_packet_.get() == NULL); - connection_close_packet_.reset(encrypted->Clone()); + connection_close_packet_.reset(encrypted); + // This assures we won't try to write *forced* packets when blocked. + // Return true to stop processing. + if (writer_->IsWriteBlocked()) { + return true; + } } if (encrypted->length() > options()->max_packet_length) { @@ -1153,16 +1149,11 @@ bool QuicConnection::WritePacket(EncryptionLevel level, debug_visitor_->OnPacketSent(sequence_number, level, *encrypted, result); } if (result.status == WRITE_STATUS_BLOCKED) { - // TODO(satyashekhar): It might be more efficient (fewer system calls), if - // all connections share this variable i.e this becomes a part of - // PacketWriterInterface. - write_blocked_ = true; // 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. The helper must call OnPacketSent // when the packet is actually sent. if (writer_->IsWriteBlockedDataBuffered()) { - delete packet; return true; } pending_write_.reset(); @@ -1170,7 +1161,6 @@ bool QuicConnection::WritePacket(EncryptionLevel level, } if (OnPacketSent(result)) { - delete packet; return true; } return false; @@ -1196,19 +1186,15 @@ bool QuicConnection::ShouldDiscardPacket( return true; } - if (retransmittable == HAS_RETRANSMITTABLE_DATA) { - if (!sent_packet_manager_.IsUnacked(sequence_number)) { - // This is a crazy edge case, but if we retransmit a packet, - // (but have to queue it for some reason) then receive an ack - // for the previous transmission (but not the retransmission) - // then receive a truncated ACK which causes us to raise the - // high water mark, all before we're able to send the packet - // then we can simply drop it. - DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number - << " since it has already been acked."; - return true; - } + // If the packet has been discarded before sending, don't send it. + // This occurs if a packet gets serialized, queued, then discarded. + if (!sent_packet_manager_.IsUnacked(sequence_number)) { + DVLOG(1) << ENDPOINT << "Dropping packet before sending: " + << sequence_number << " since it has already been discarded."; + return true; + } + if (retransmittable == HAS_RETRANSMITTABLE_DATA) { if (sent_packet_manager_.IsPreviousTransmission(sequence_number)) { // If somehow we have already retransmitted this packet *before* // we actually send it for the first time (I think this is probably @@ -1322,6 +1308,7 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level, packet.entropy_hash); if (WritePacket(level, packet.sequence_number, packet.packet, transmission_type, retransmittable, handshake, forced)) { + delete packet.packet; return true; } queued_packets_.push_back(QueuedPacket(packet.sequence_number, packet.packet, @@ -1491,9 +1478,9 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) { void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, const string& details) { - if (!write_blocked_) { - SendConnectionClosePacket(error, details); - } + // If we're write blocked, WritePacket() will not send, but will capture the + // serialized packet. + SendConnectionClosePacket(error, details); CloseConnection(error, false); } @@ -1566,6 +1553,21 @@ bool QuicConnection::HasQueuedData() const { !queued_packets_.empty() || packet_generator_.HasQueuedFrames(); } +bool QuicConnection::CanWriteStreamData() { + if (HasQueuedData()) { + return false; + } + + IsHandshake pending_handshake = visitor_->HasPendingHandshake() ? + IS_HANDSHAKE : NOT_HANDSHAKE; + // Sending queued packets may have caused the socket to become write blocked, + // or the congestion manager to prohibit sending. If we've sent everything + // we had queued and we're still not blocked, let the visitor know it can + // write more. + return ShouldGeneratePacket(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, + pending_handshake); +} + void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) { if (timeout < idle_network_timeout_) { idle_network_timeout_ = timeout; diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 9a71201..4aa5129 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -75,8 +75,10 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when the connection is closed either locally by the framer, or // remotely by the peer. - virtual void OnConnectionClosed(QuicErrorCode error, - bool from_peer) = 0; + virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) = 0; + + // Called when the connection failed to write because the socket was blocked. + virtual void OnWriteBlocked() = 0; // Called once a specific QUIC version is agreed by both endpoints. virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0; @@ -249,9 +251,8 @@ class NET_EXPORT_PRIVATE QuicConnection // Called when a packet has been finally sent to the network. bool OnPacketSent(WriteResult result); - // If the socket is not blocked, this allows queued writes to happen. Returns - // false if the socket has become blocked. - bool WriteIfNotBlocked(); + // If the socket is not blocked, writes queued packets. + void WriteIfNotBlocked(); // Do any work which logically would be done in OnPacket but can not be // safely done until the packet is validated. Returns true if the packet @@ -339,6 +340,11 @@ class NET_EXPORT_PRIVATE QuicConnection // does nothing if there are no pending frames. void Flush(); + // Returns true if the underlying UDP socket is writable, there is + // no queued data and the connection is not congestion-control + // blocked. + bool CanWriteStreamData(); + // Returns true if the connection has queued packets or frames. bool HasQueuedData() const; @@ -411,8 +417,8 @@ class NET_EXPORT_PRIVATE QuicConnection // Send a packet to the peer using encryption |level|. If |sequence_number| // is present in the |retransmission_map_|, then contents of this packet will // be retransmitted with a new sequence number if it's not acked by the peer. - // Deletes |packet| via WritePacket call or transfers ownership to - // QueuedPacket, ultimately deleted via WritePacket. Updates the + // Deletes |packet| if WritePacket call succeeds, or transfers ownership to + // QueuedPacket, ultimately deleted in WriteQueuedPackets. Updates the // entropy map corresponding to |sequence_number| using |entropy_hash|. // |transmission_type| and |retransmittable| are supplied to the congestion // manager, and when |forced| is true, it bypasses the congestion manager. @@ -425,7 +431,7 @@ class NET_EXPORT_PRIVATE QuicConnection // of helper. Returns true on successful write, false otherwise. However, // behavior is undefined if connection is not established or broken. In any // circumstances, a return value of true implies that |packet| has been - // deleted and should not be accessed. If |sequence_number| is present in + // transmitted and may be destroyed. If |sequence_number| is present in // |retransmission_map_| it also sets up retransmission of the given packet // in case of successful write. If |force| is FORCE, then the packet will be // sent immediately and the send scheduler will not be consulted. @@ -532,10 +538,6 @@ class NET_EXPORT_PRIVATE QuicConnection // Clears any accumulated frames from the last received packet. void ClearLastFrames(); - // Called from OnCanWrite and WriteIfNotBlocked to write queued packets. - // Returns false if the socket has become blocked. - bool DoWrite(); - // Calculates the smallest sequence number length that can also represent four // times the maximum of the congestion window and the difference between the // least_packet_awaited_by_peer_ and |sequence_number|. @@ -550,7 +552,7 @@ class NET_EXPORT_PRIVATE QuicConnection // Writes as many queued packets as possible. The connection must not be // blocked when this is called. - bool WriteQueuedPackets(); + void WriteQueuedPackets(); // Writes as many pending retransmissions as possible. void WritePendingRetransmissions(); @@ -640,9 +642,6 @@ class NET_EXPORT_PRIVATE QuicConnection // Contains the connection close packet if the connection has been closed. scoped_ptr<QuicEncryptedPacket> connection_close_packet_; - // True when the socket becomes unwritable. - bool write_blocked_; - FecGroupMap group_map_; QuicReceivedPacketManager received_packet_manager_; diff --git a/net/quic/quic_connection_helper.h b/net/quic/quic_connection_helper.h index 3354656..fa866f2 100644 --- a/net/quic/quic_connection_helper.h +++ b/net/quic/quic_connection_helper.h @@ -12,6 +12,7 @@ #include <set> +#include "base/basictypes.h" #include "base/memory/weak_ptr.h" #include "net/base/ip_endpoint.h" #include "net/quic/quic_protocol.h" diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 3487cd0..6ad02c7 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -274,6 +274,7 @@ class TestPacketWriter : public QuicPacketWriter { TestPacketWriter() : last_packet_size_(0), write_blocked_(false), + block_next_write_(false), is_write_blocked_data_buffered_(false), is_server_(true), final_bytes_of_last_packet_(0), @@ -282,7 +283,7 @@ class TestPacketWriter : public QuicPacketWriter { packets_write_attempts_(0) { } - // QuicPacketWriter + // QuicPacketWriter interface virtual WriteResult WritePacket( const char* buffer, size_t buf_len, const IPAddressNumber& self_address, @@ -304,6 +305,10 @@ class TestPacketWriter : public QuicPacketWriter { visitor_.Reset(); framer.set_visitor(&visitor_); EXPECT_TRUE(framer.ProcessPacket(packet)); + if (block_next_write_) { + write_blocked_ = true; + block_next_write_ = false; + } if (IsWriteBlocked()) { return WriteResult(WRITE_STATUS_BLOCKED, -1); } @@ -319,7 +324,7 @@ class TestPacketWriter : public QuicPacketWriter { virtual void SetWritable() OVERRIDE { write_blocked_ = false; } - void SetWriteBlocked() { write_blocked_ = true; } + void BlockNextWrite() { block_next_write_ = true; } // Resets the visitor's state by clearing out the headers and frames. void Reset() { @@ -375,6 +380,7 @@ class TestPacketWriter : public QuicPacketWriter { FramerVisitorCapturingFrames visitor_; size_t last_packet_size_; bool write_blocked_; + bool block_next_write_; bool is_write_blocked_data_buffered_; bool is_server_; uint32 final_bytes_of_last_packet_; @@ -824,6 +830,17 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> { } } + void TriggerConnectionClose() { + // Send an erroneous packet to close the connection. + EXPECT_CALL(visitor_, + OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); + // Call ProcessDataPacket rather than ProcessPacket, as we should not get a + // packet call to the visitor. + ProcessDataPacket(6000, 0, !kEntropyFlag); + EXPECT_FALSE( + QuicConnectionPeer::GetConnectionClosePacket(&connection_) == NULL); + } + QuicGuid guid_; QuicFramer framer_; QuicPacketCreator creator_; @@ -944,10 +961,13 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) { } TEST_F(QuicConnectionTest, RejectPacketTooFarOut) { + EXPECT_CALL(visitor_, + OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); ProcessDataPacket(6000, 0, !kEntropyFlag); + EXPECT_FALSE( + QuicConnectionPeer::GetConnectionClosePacket(&connection_) == NULL); } TEST_F(QuicConnectionTest, TruncatedAck) { @@ -964,7 +984,8 @@ TEST_F(QuicConnectionTest, TruncatedAck) { } EXPECT_CALL(entropy_calculator_, EntropyHash(511)).WillOnce(testing::Return(0)); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(256); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(256); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2); ProcessAckPacket(&frame); @@ -978,7 +999,8 @@ TEST_F(QuicConnectionTest, TruncatedAck) { AckPacket(192, &frame); // Removing one missing packet allows us to ack 192 and one more range. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2); ProcessAckPacket(&frame); @@ -1040,6 +1062,7 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { QuicAckFrame frame = InitAckFrame(original, 1); NackPacket(original, &frame); // First nack triggers early retransmit. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); QuicPacketSequenceNumber retransmission; EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, packet_size - kQuicVersionSize, @@ -1050,7 +1073,8 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) { QuicAckFrame frame2 = InitAckFrame(retransmission, 1); NackPacket(original, &frame2); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)); ProcessAckPacket(&frame2); // Now if the peer sends an ack which still reports the retransmitted packet @@ -1099,7 +1123,8 @@ TEST_F(QuicConnectionTest, LargestObservedLower) { SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2); // Start out saying the largest observed is 2. QuicAckFrame frame1 = InitAckFrame(1, 0); @@ -1233,7 +1258,8 @@ TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) { TEST_F(QuicConnectionTest, BasicSending) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(6); +// EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); +// EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(6); QuicPacketSequenceNumber last_packet; SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); @@ -1249,6 +1275,9 @@ TEST_F(QuicConnectionTest, BasicSending) { SendAckPacketToPeer(); // Packet 5 EXPECT_EQ(1u, last_ack()->sent_info.least_unacked); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3); + // Peer acks up to packet 3. QuicAckFrame frame = InitAckFrame(3, 0); ProcessAckPacket(&frame); @@ -1258,6 +1287,9 @@ TEST_F(QuicConnectionTest, BasicSending) { // ack for 4. EXPECT_EQ(4u, last_ack()->sent_info.least_unacked); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3); + // Peer acks up to packet 4, the last packet. QuicAckFrame frame2 = InitAckFrame(6, 0); ProcessAckPacket(&frame2); // Acks don't instigate acks. @@ -1309,7 +1341,7 @@ TEST_F(QuicConnectionTest, FECQueueing) { connection_.options()->max_packets_per_fec_group = 2; EXPECT_EQ(0u, connection_.NumQueuedPackets()); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); const string payload(payload_length, 'a'); connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL); EXPECT_FALSE(creator_.ShouldSendFec(true)); @@ -1351,7 +1383,8 @@ TEST_F(QuicConnectionTest, DontAbandonAckedFEC) { // received, it would cause the covered packet to be acked as well. NackPacket(1, &ack_fec); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); ProcessAckPacket(&ack_fec); clock_.AdvanceTime(DefaultRetransmissionTime()); @@ -1381,7 +1414,8 @@ TEST_F(QuicConnectionTest, AbandonAllFEC) { NackPacket(4, &ack_fec); // Lose the first FEC packet and ack the three data packets. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(3); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)); EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)); ProcessAckPacket(&ack_fec); @@ -1577,7 +1611,7 @@ TEST_F(QuicConnectionTest, FramePackingSendvQueued) { // Try to send two stream frames in 1 packet by using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); char data[] = "ABCD"; IOVector data_iov; data_iov.AppendNoCoalesce(data, 2); @@ -1587,11 +1621,6 @@ TEST_F(QuicConnectionTest, FramePackingSendvQueued) { 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. writer_->SetWritable(); EXPECT_TRUE(connection_.OnCanWrite()); @@ -1643,7 +1672,8 @@ TEST_F(QuicConnectionTest, OnCanWrite) { } TEST_F(QuicConnectionTest, RetransmitOnNack) { - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)).Times(1); QuicPacketSequenceNumber last_packet; @@ -1667,6 +1697,8 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { QuicAckFrame nack_two = InitAckFrame(3, 0); NackPacket(2, &nack_two); // The third nack should trigger a retransmission. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, second_packet_size - kQuicVersionSize, NACK_RETRANSMISSION, _)).Times(1); @@ -1674,7 +1706,8 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { } TEST_F(QuicConnectionTest, DiscardRetransmit) { - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)).Times(1); QuicPacketSequenceNumber last_packet; @@ -1697,7 +1730,9 @@ TEST_F(QuicConnectionTest, DiscardRetransmit) { NackPacket(2, &nack_two); // The first nack should trigger a fast retransmission, but we'll be // write blocked, so the packet will be queued. - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)); ProcessAckPacket(&nack_two); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -1731,6 +1766,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { QuicAckFrame frame = InitAckFrame(1, largest_observed); NackPacket(largest_observed, &frame); // The first nack should retransmit the largest observed packet. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, packet_size - kQuicVersionSize, NACK_RETRANSMISSION, _)); @@ -1744,7 +1780,7 @@ TEST_F(QuicConnectionTest, QueueAfterTwoRTOs) { } // Block the congestion window and ensure they're queued. - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); clock_.AdvanceTime(DefaultRetransmissionTime()); // Only one packet should be retransmitted. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); @@ -1763,9 +1799,9 @@ TEST_F(QuicConnectionTest, QueueAfterTwoRTOs) { } TEST_F(QuicConnectionTest, WriteBlockedThenSent) { - writer_->SetWriteBlocked(); - + writer_->BlockNextWrite(); writer_->set_is_write_blocked_data_buffered(true); + connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -1774,21 +1810,68 @@ TEST_F(QuicConnectionTest, WriteBlockedThenSent) { EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } -TEST_F(QuicConnectionTest, ResumptionAlarmThenWriteBlocked) { - // Set the send and resumption alarm, then block the connection. +TEST_F(QuicConnectionTest, WriteBlockedAckedThenSent) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + writer_->BlockNextWrite(); + + writer_->set_is_write_blocked_data_buffered(true); + connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); + + // Ack the sent packet before the callback returns, which happens in + // rare circumstances with write blocked sockets. + QuicAckFrame ack = InitAckFrame(1, 0); + ProcessAckPacket(&ack); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0)); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); +} + +TEST_F(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + + writer_->BlockNextWrite(); + writer_->set_is_write_blocked_data_buffered(true); + + // Simulate the retransmission alarm firing. + EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)); + clock_.AdvanceTime(DefaultRetransmissionTime()); + connection_.GetRetransmissionAlarm()->Fire(); + + // Ack the sent packet before the callback returns, which happens in + // rare circumstances with write blocked sockets. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + QuicAckFrame ack = InitAckFrame(1, 0); + ProcessAckPacket(&ack); + + connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0)); + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); +} + +TEST_F(QuicConnectionTest, ResumptionAlarmWhenWriteBlocked) { + // Block the connection. + writer_->BlockNextWrite(); + connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); + EXPECT_EQ(1u, writer_->packets_write_attempts()); + EXPECT_TRUE(writer_->IsWriteBlocked()); + + // Set the send and resumption alarms. Fire the alarms and ensure they don't + // attempt to write. connection_.GetResumeWritesAlarm()->Set(clock_.ApproximateNow()); connection_.GetSendAlarm()->Set(clock_.ApproximateNow()); - QuicConnectionPeer::SetIsWriteBlocked(&connection_, true); - - // Fire the alarms and ensure the connection is still write blocked. connection_.GetResumeWritesAlarm()->Fire(); connection_.GetSendAlarm()->Fire(); - EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_)); + EXPECT_TRUE(writer_->IsWriteBlocked()); + EXPECT_EQ(1u, writer_->packets_write_attempts()); } TEST_F(QuicConnectionTest, LimitPacketsPerNack) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(15, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(15, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(4); int offset = 0; // Send packets 1 to 15. @@ -1816,7 +1899,6 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) { // Test sending multiple acks from the connection to the session. TEST_F(QuicConnectionTest, MultipleAcks) { - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(6); QuicPacketSequenceNumber last_packet; SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); @@ -1831,18 +1913,23 @@ TEST_F(QuicConnectionTest, MultipleAcks) { EXPECT_EQ(6u, last_packet); // Client will ack packets 1, 2, [!3], 4, 5. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(4); QuicAckFrame frame1 = InitAckFrame(5, 0); NackPacket(3, &frame1); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessAckPacket(&frame1); // Now the client implicitly acks 3, and explicitly acks 6. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2); QuicAckFrame frame2 = InitAckFrame(6, 0); ProcessAckPacket(&frame2); } TEST_F(QuicConnectionTest, DontLatchUnackedPacket) { - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); // Packet 1; // From now on, we send acks, so the send algorithm won't save them. ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) @@ -2145,6 +2232,7 @@ TEST_F(QuicConnectionTest, RetransmissionCountCalculation) { EXPECT_TRUE(QuicConnectionPeer::IsRetransmission( &connection_, rto_sequence_number)); // Once by explicit nack. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)).Times(3); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(rto_sequence_number, _)).Times(1); @@ -2172,7 +2260,7 @@ TEST_F(QuicConnectionTest, RetransmissionCountCalculation) { } TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) { - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); // Make sure that RTO is not started when the packet is queued. EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); @@ -2195,7 +2283,8 @@ TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) { // Advance the time right before the RTO, then receive an ack for the first // packet to delay the RTO. clock_.AdvanceTime(DefaultRetransmissionTime()); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); QuicAckFrame ack = InitAckFrame(1, 0); ProcessAckPacket(&ack); EXPECT_TRUE(retransmission_alarm->IsSet()); @@ -2222,15 +2311,10 @@ TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) { TEST_F(QuicConnectionTest, TestQueued) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); EXPECT_EQ(1u, connection_.NumQueuedPackets()); - // 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. writer_->SetWritable(); EXPECT_TRUE(connection_.OnCanWrite()); @@ -2382,7 +2466,7 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) { TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); @@ -2633,7 +2717,7 @@ TEST_F(QuicConnectionTest, DontSendDelayedAckOnOutgoingCryptoPacket) { TEST_F(QuicConnectionTest, NoAckForClose) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(0); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, true)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); ProcessClosePacket(2, 0); @@ -2857,11 +2941,10 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { framer_.set_version(QuicVersionMax()); connection_.set_is_server(true); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); EXPECT_EQ(0u, writer_->last_packet_size()); EXPECT_TRUE(connection_.HasQueuedData()); - EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_)); writer_->SetWritable(); connection_.OnCanWrite(); @@ -2902,12 +2985,11 @@ TEST_F(QuicConnectionTest, framer_.set_version(QuicVersionMax()); connection_.set_is_server(true); - writer_->SetWriteBlocked(); + writer_->BlockNextWrite(); writer_->set_is_write_blocked_data_buffered(true); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); EXPECT_EQ(0u, writer_->last_packet_size()); EXPECT_FALSE(connection_.HasQueuedData()); - EXPECT_TRUE(QuicConnectionPeer::IsWriteBlocked(&connection_)); } TEST_F(QuicConnectionTest, ClientHandlesVersionNegotiation) { @@ -3007,7 +3089,8 @@ TEST_F(QuicConnectionTest, CheckSendStats) { NackPacket(3, &nack_three); NackPacket(1, &nack_three); QuicFrame frame(&nack_three); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1); EXPECT_CALL(visitor_, OnCanWrite()).Times(4).WillRepeatedly(Return(true)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -3136,41 +3219,32 @@ TEST_F(QuicConnectionTest, SelectMutualVersion) { EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version)); } -TEST_F(QuicConnectionTest, ConnectionCloseWhenNotWriteBlocked) { - writer_->SetWritable(); // Already default. +TEST_F(QuicConnectionTest, ConnectionCloseWhenWritable) { + EXPECT_FALSE(writer_->IsWriteBlocked()); - // Send a packet (but write will not block). + // Send a packet. connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_EQ(1u, writer_->packets_write_attempts()); - // Send an erroneous packet to close the connection. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); - ProcessDataPacket(6000, 0, !kEntropyFlag); + TriggerConnectionClose(); EXPECT_EQ(2u, writer_->packets_write_attempts()); } -TEST_F(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) { - EXPECT_EQ(0u, connection_.NumQueuedPackets()); - writer_->SetWriteBlocked(); +TEST_F(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) { + writer_->BlockNextWrite(); + TriggerConnectionClose(); + EXPECT_EQ(1u, writer_->packets_write_attempts()); + EXPECT_TRUE(writer_->IsWriteBlocked()); +} - // Send a packet to so that write will really block. +TEST_F(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) { + writer_->BlockNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); EXPECT_EQ(1u, connection_.NumQueuedPackets()); EXPECT_EQ(1u, writer_->packets_write_attempts()); - - // Send an erroneous packet to close the connection. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); - ProcessDataPacket(6000, 0, !kEntropyFlag); - EXPECT_EQ(1u, writer_->packets_write_attempts()); -} - -TEST_F(QuicConnectionTest, ConnectionCloseWhenNothingPending) { - writer_->SetWriteBlocked(); - - // Send an erroneous packet to close the connection. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false)); - ProcessDataPacket(6000, 0, !kEntropyFlag); + EXPECT_TRUE(writer_->IsWriteBlocked()); + TriggerConnectionClose(); EXPECT_EQ(1u, writer_->packets_write_attempts()); } @@ -3179,13 +3253,14 @@ TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) { // Create a delegate which we expect to be called. scoped_refptr<MockAckNotifierDelegate> delegate(new MockAckNotifierDelegate); - EXPECT_CALL(*delegate, OnAckNotification()).Times(1);; + EXPECT_CALL(*delegate, OnAckNotification()).Times(1); // Send some data, which will register the delegate to be notified. connection_.SendStreamDataWithString(1, "foo", 0, !kFin, delegate.get()); // Process an ACK from the server which should trigger the callback. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); QuicAckFrame frame = InitAckFrame(1, 0); ProcessAckPacket(&frame); } @@ -3195,9 +3270,10 @@ TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) { // Create a delegate which we don't expect to be called. scoped_refptr<MockAckNotifierDelegate> delegate(new MockAckNotifierDelegate); - EXPECT_CALL(*delegate, OnAckNotification()).Times(0);; + EXPECT_CALL(*delegate, OnAckNotification()).Times(0); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2); // Send some data, which will register the delegate to be notified. This will // not be ACKed and so the delegate should never be called. @@ -3221,10 +3297,11 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) { // Create a delegate which we expect to be called. scoped_refptr<MockAckNotifierDelegate> delegate(new MockAckNotifierDelegate); - EXPECT_CALL(*delegate, OnAckNotification()).Times(1);; + EXPECT_CALL(*delegate, OnAckNotification()).Times(1); // In total expect ACKs for all 4 packets. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(4); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)).Times(2); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(4); // Send four packets, and register to be notified on ACK of packet 2. connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); @@ -3254,10 +3331,11 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) { // Create a delegate which we expect to be called. scoped_refptr<MockAckNotifierDelegate> delegate(new MockAckNotifierDelegate); - EXPECT_CALL(*delegate, OnAckNotification()).Times(1);; + EXPECT_CALL(*delegate, OnAckNotification()).Times(1); // Expect ACKs for 1 packet. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); // Send one packet, and register to be notified on ACK. connection_.SendStreamDataWithString(1, "foo", 0, !kFin, delegate.get()); diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h index a082d50..b29580b 100644 --- a/net/quic/quic_crypto_stream.h +++ b/net/quic/quic_crypto_stream.h @@ -5,6 +5,7 @@ #ifndef NET_QUIC_QUIC_CRYPTO_STREAM_H_ #define NET_QUIC_QUIC_CRYPTO_STREAM_H_ +#include "base/basictypes.h" #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_utils.h" #include "net/quic/quic_config.h" diff --git a/net/quic/quic_data_stream.cc b/net/quic/quic_data_stream.cc index 0e450f1..a537d81 100644 --- a/net/quic/quic_data_stream.cc +++ b/net/quic/quic_data_stream.cc @@ -7,7 +7,7 @@ #include "base/logging.h" #include "net/quic/quic_session.h" #include "net/quic/quic_spdy_decompressor.h" -#include "net/spdy/write_blocked_list.h" +#include "net/quic/quic_write_blocked_list.h" using base::StringPiece; using std::min; diff --git a/net/quic/quic_data_stream.h b/net/quic/quic_data_stream.h index 9e8c10e..ce4ac4f 100644 --- a/net/quic/quic_data_stream.h +++ b/net/quic/quic_data_stream.h @@ -13,10 +13,12 @@ #include <list> +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "net/base/iovec.h" #include "net/base/net_export.h" #include "net/quic/quic_ack_notifier.h" +#include "net/quic/quic_protocol.h" #include "net/quic/quic_spdy_compressor.h" #include "net/quic/quic_spdy_decompressor.h" #include "net/quic/quic_stream_sequencer.h" diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc index 25144f8..e767a46 100644 --- a/net/quic/quic_data_stream_test.cc +++ b/net/quic/quic_data_stream_test.cc @@ -9,6 +9,7 @@ #include "net/quic/quic_spdy_compressor.h" #include "net/quic/quic_spdy_decompressor.h" #include "net/quic/quic_utils.h" +#include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -119,7 +120,7 @@ class QuicDataStreamTest : public ::testing::TestWithParam<QuicVersion> { scoped_ptr<QuicSpdyCompressor> compressor_; scoped_ptr<QuicSpdyDecompressor> decompressor_; SpdyHeaderBlock headers_; - WriteBlockedList<QuicStreamId>* write_blocked_list_; + QuicWriteBlockedList* write_blocked_list_; }; INSTANTIATE_TEST_CASE_P(Tests, QuicDataStreamTest, diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc index 4be4810..8e37044 100644 --- a/net/quic/quic_fec_group.cc +++ b/net/quic/quic_fec_group.cc @@ -6,6 +6,7 @@ #include <limits> +#include "base/basictypes.h" #include "base/logging.h" using base::StringPiece; diff --git a/net/quic/quic_fec_group_test.cc b/net/quic/quic_fec_group_test.cc index 3de40b1..02ed5c9 100644 --- a/net/quic/quic_fec_group_test.cc +++ b/net/quic/quic_fec_group_test.cc @@ -5,6 +5,7 @@ #include <algorithm> #include <vector> +#include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "net/quic/quic_fec_group.h" diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 7f07b96..b1ceb49 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "net/quic/quic_framer.h" + #include <algorithm> #include <map> #include <string> @@ -14,7 +16,6 @@ #include "base/stl_util.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" -#include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/quic_framer_peer.h" diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 22ed3b8..a49d6bb 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -22,6 +22,7 @@ #include "net/quic/quic_default_packet_writer.h" #include "net/quic/quic_http_utils.h" #include "net/quic/quic_reliable_client_stream.h" +#include "net/quic/quic_write_blocked_list.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" @@ -35,7 +36,6 @@ #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" @@ -662,7 +662,7 @@ TEST_P(QuicHttpStreamTest, Priority) { QuicReliableClientStream* reliable_stream = QuicHttpStreamPeer::GetQuicReliableClientStream(stream_.get()); DCHECK(reliable_stream); - DCHECK_EQ(static_cast<QuicPriority>(kHighestPriority), + DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, reliable_stream->EffectivePriority()); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, @@ -709,13 +709,13 @@ TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) { DCHECK(reliable_stream); QuicReliableClientStream::Delegate* delegate = reliable_stream->GetDelegate(); DCHECK(delegate); - DCHECK_EQ(static_cast<QuicPriority>(kHighestPriority), + DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, reliable_stream->EffectivePriority()); // Set Delegate to NULL and make sure EffectivePriority returns highest // priority. reliable_stream->SetDelegate(NULL); - DCHECK_EQ(static_cast<QuicPriority>(kHighestPriority), + DCHECK_EQ(QuicWriteBlockedList::kHighestPriority, reliable_stream->EffectivePriority()); reliable_stream->SetDelegate(delegate); } diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index cb37cc2..2ac8747 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -4,6 +4,7 @@ #include "net/quic/quic_packet_creator.h" +#include "base/basictypes.h" #include "base/logging.h" #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_ack_notifier.h" diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index 3785f7d..4c65734 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc @@ -4,6 +4,7 @@ #include "net/quic/quic_packet_generator.h" +#include "base/basictypes.h" #include "base/logging.h" #include "net/quic/quic_fec_group.h" #include "net/quic/quic_utils.h" diff --git a/net/quic/quic_packet_writer.h b/net/quic/quic_packet_writer.h index fbea660..a4b26d6c 100644 --- a/net/quic/quic_packet_writer.h +++ b/net/quic/quic_packet_writer.h @@ -26,8 +26,8 @@ class NET_EXPORT_PRIVATE QuicPacketWriter { // and error_code is populated. virtual WriteResult WritePacket( const char* buffer, size_t buf_len, - const net::IPAddressNumber& self_address, - const net::IPEndPoint& peer_address, + const IPAddressNumber& self_address, + const IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) = 0; // Returns true if the writer buffers and subsequently rewrites data diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc index af12b8b..996a5c5 100644 --- a/net/quic/quic_reliable_client_stream.cc +++ b/net/quic/quic_reliable_client_stream.cc @@ -7,7 +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" +#include "net/quic/quic_write_blocked_list.h" namespace net { @@ -59,7 +59,7 @@ QuicPriority QuicReliableClientStream::EffectivePriority() const { if (delegate_ && delegate_->HasSendHeadersComplete()) { return QuicDataStream::EffectivePriority(); } - return kHighestPriority; + return QuicWriteBlockedList::kHighestPriority; } int QuicReliableClientStream::WriteStreamData( diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc index 79579e4..b01d0fd 100644 --- a/net/quic/quic_reliable_client_stream_test.cc +++ b/net/quic/quic_reliable_client_stream_test.cc @@ -12,6 +12,7 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" +using testing::AnyNumber; using testing::Return; using testing::StrEq; using testing::_; @@ -41,9 +42,10 @@ class QuicReliableClientStreamTest : public ::testing::TestWithParam<QuicVersion> { public: QuicReliableClientStreamTest() - : session_(new MockConnection(false, SupportedVersions(GetParam()))), - stream_(kStreamId, &session_, BoundNetLog()) { - stream_.SetDelegate(&delegate_); + : session_(new MockConnection(false, SupportedVersions(GetParam()))) { + stream_ = new QuicReliableClientStream(kStreamId, &session_, BoundNetLog()); + session_.ActivateStream(stream_); + stream_->SetDelegate(&delegate_); } void InitializeHeaders() { @@ -78,7 +80,7 @@ class QuicReliableClientStreamTest testing::StrictMock<MockDelegate> delegate_; MockSession session_; - QuicReliableClientStream stream_; + QuicReliableClientStream* stream_; QuicCryptoClientConfig crypto_config_; SpdyHeaderBlock headers_; }; @@ -94,21 +96,21 @@ TEST_P(QuicReliableClientStreamTest, OnFinRead) { uncompressed_headers.size())); QuicStreamOffset offset = 0; if (GetParam() > QUIC_VERSION_12) { - stream_.OnStreamHeaders(uncompressed_headers); - stream_.OnStreamHeadersComplete(false, uncompressed_headers.length()); + stream_->OnStreamHeaders(uncompressed_headers); + stream_->OnStreamHeadersComplete(false, uncompressed_headers.length()); } else { QuicSpdyCompressor compressor; string compressed_headers = compressor.CompressHeaders(headers_); QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(compressed_headers)); - stream_.OnStreamFrame(frame1); + stream_->OnStreamFrame(frame1); offset = compressed_headers.length(); } IOVector iov; QuicStreamFrame frame2(kStreamId, true, offset, iov); EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); - stream_.OnStreamFrame(frame2); + stream_->OnStreamFrame(frame2); } TEST_P(QuicReliableClientStreamTest, ProcessData) { @@ -116,7 +118,7 @@ TEST_P(QuicReliableClientStreamTest, ProcessData) { EXPECT_CALL(delegate_, OnDataReceived(StrEq(data), arraysize(data))); EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); - EXPECT_EQ(arraysize(data), stream_.ProcessData(data, arraysize(data))); + EXPECT_EQ(arraysize(data), stream_->ProcessData(data, arraysize(data))); } TEST_P(QuicReliableClientStreamTest, ProcessDataWithError) { @@ -127,14 +129,14 @@ TEST_P(QuicReliableClientStreamTest, ProcessDataWithError) { EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); - EXPECT_EQ(0u, stream_.ProcessData(data, arraysize(data))); + EXPECT_EQ(0u, stream_->ProcessData(data, arraysize(data))); } TEST_P(QuicReliableClientStreamTest, OnError) { EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)); - stream_.OnError(ERR_INTERNET_DISCONNECTED); - EXPECT_FALSE(stream_.GetDelegate()); + stream_->OnError(ERR_INTERNET_DISCONNECTED); + EXPECT_FALSE(stream_->GetDelegate()); } TEST_P(QuicReliableClientStreamTest, WriteStreamData) { @@ -144,33 +146,33 @@ TEST_P(QuicReliableClientStreamTest, WriteStreamData) { const size_t kDataLen = arraysize(kData1); // All data written. - EXPECT_CALL(session_, WritevData(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), - true, callback.callback())); + EXPECT_EQ(OK, stream_->WriteStreamData(base::StringPiece(kData1, kDataLen), + true, callback.callback())); } TEST_P(QuicReliableClientStreamTest, WriteStreamDataAsync) { - EXPECT_CALL(delegate_, HasSendHeadersComplete()); + EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber()); EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); const char kData1[] = "hello world"; const size_t kDataLen = arraysize(kData1); // No data written. - EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _, _)).WillOnce( + EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)).WillOnce( Return(QuicConsumedData(0, false))); TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - stream_.WriteStreamData(base::StringPiece(kData1, kDataLen), - true, callback.callback())); + stream_->WriteStreamData(base::StringPiece(kData1, kDataLen), + true, callback.callback())); ASSERT_FALSE(callback.have_result()); // All data written. - EXPECT_CALL(session_, WritevData(stream_.id(), _, _, _, _, _)).WillOnce( + EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)).WillOnce( Return(QuicConsumedData(kDataLen, true))); - stream_.OnCanWrite(); + stream_->OnCanWrite(); ASSERT_TRUE(callback.have_result()); EXPECT_EQ(OK, callback.WaitForResult()); } diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index af9a507a..8208004 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -104,6 +104,7 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { << "Client did not set an initial RTT, but did negotiate one."; rtt_sample_ = QuicTime::Delta::FromMicroseconds(config.initial_round_trip_time_us()); + send_algorithm_->UpdateRtt(rtt_sample_); } if (config.congestion_control() == kPACE) { MaybeEnablePacing(); @@ -181,19 +182,17 @@ void QuicSentPacketManager::OnRetransmittedPacket( bool QuicSentPacketManager::OnIncomingAck( const ReceivedPacketInfo& received_info, QuicTime ack_receive_time) { - // Determine if the least unacked sequence number is being acked. - QuicPacketSequenceNumber least_unacked_sent_before = - GetLeastUnackedSentPacket(); - // TODO(ianswett): Consider a non-TCP metric for determining the connection - // is making progress, since QUIC has out of order delivery. - bool new_least_unacked = !IsAwaitingPacket(received_info, - least_unacked_sent_before); - + // We rely on delta_time_largest_observed to compute an RTT estimate, so + // we only update rtt when the largest observed gets acked. + bool largest_observed_acked = + ContainsKey(unacked_packets_, received_info.largest_observed); MaybeUpdateRTT(received_info, ack_receive_time); HandleAckForSentPackets(received_info); MaybeRetransmitOnAckFrame(received_info, ack_receive_time); - if (new_least_unacked) { + // Anytime we are making forward progress and have a new RTT estimate, reset + // the backoff counters. + if (largest_observed_acked) { // Reset all retransmit counters any time a new packet is acked. consecutive_rto_count_ = 0; consecutive_tlp_count_ = 0; @@ -304,15 +303,9 @@ void QuicSentPacketManager::RetransmitUnackedPackets( unacked_it != unacked_packets_.end(); ++unacked_it) { const RetransmittableFrames* frames = unacked_it->second.retransmittable_frames; - if (frames == NULL) { - continue; - } if (retransmission_type == ALL_PACKETS || - frames->encryption_level() == ENCRYPTION_INITIAL) { - // TODO(satyamshekhar): Think about congestion control here. - // Specifically, about the retransmission count of packets being sent - // proactively to achieve 0 (minimal) RTT. - if (unacked_it->second.retransmittable_frames) { + (frames != NULL && frames->encryption_level() == ENCRYPTION_INITIAL)) { + if (frames) { OnPacketAbandoned(unacked_it); MarkForRetransmission(unacked_it->first, NACK_RETRANSMISSION); } else { @@ -398,7 +391,7 @@ QuicSentPacketManager::MarkPacketHandled( if (it->second.pending) { size_t bytes_sent = packet_history_map_[sequence_number]->bytes_sent(); if (received_by_peer == RECEIVED_BY_PEER) { - send_algorithm_->OnPacketAcked(sequence_number, bytes_sent, rtt_sample_); + send_algorithm_->OnPacketAcked(sequence_number, bytes_sent); } else { // It's been abandoned. send_algorithm_->OnPacketAbandoned(sequence_number, bytes_sent); @@ -550,18 +543,13 @@ bool QuicSentPacketManager::OnPacketSent( TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) { DCHECK_LT(0u, sequence_number); - // In some edge cases, on some platforms (such as Windows), it is possible - // that we were write-blocked when we tried to send a packet, and then decided - // not to send the packet (such as when the encryption key changes, and we - // "discard" the unsent packet). In that rare case, we may indeed - // asynchronously (later) send the packet, calling this method, but the - // sequence number may already be erased from unacked_packets_ map. In that - // case, we can just return false since the packet will not be tracked for - // retransmission. - if (!ContainsKey(unacked_packets_, sequence_number)) - return false; - DCHECK(!unacked_packets_[sequence_number].pending); UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); + // In rare circumstances, the packet could be serialized, sent, and then acked + // before OnPacketSent is called. + if (it == unacked_packets_.end()) { + return false; + } + DCHECK(!it->second.pending); // Only track packets the send algorithm wants us to track. if (!send_algorithm_->OnPacketSent(sent_time, sequence_number, bytes, @@ -805,6 +793,10 @@ void QuicSentPacketManager::MaybeUpdateRTT( if (transmission_info == NULL) { return; } + // Don't update the RTT if it hasn't been sent. + if (transmission_info->sent_time == QuicTime::Zero()) { + return; + } QuicTime::Delta send_delta = ack_receive_time.Subtract(transmission_info->sent_time); @@ -817,6 +809,7 @@ void QuicSentPacketManager::MaybeUpdateRTT( // approximation until we get a better estimate. rtt_sample_ = send_delta; } + send_algorithm_->UpdateRtt(rtt_sample_); } QuicTime::Delta QuicSentPacketManager::TimeUntilSend( diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index b0e861d..14ab403 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc @@ -32,6 +32,8 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_); // Disable tail loss probes for most tests. QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 0); + // Advance the time 1s so the send times are never QuicTime::Zero. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); } ~QuicSentPacketManagerTest() { @@ -242,12 +244,15 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) { TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { SendDataPacket(1); RetransmitPacket(1, 2); + QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15); + clock_.AdvanceTime(rtt); // Ack 1 but not 2. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)); ReceivedPacketInfo received_info; received_info.largest_observed = 1; - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); // 2 remains unacked, but no packets have retransmittable data. QuicPacketSequenceNumber unacked[] = { 2 }; @@ -267,31 +272,39 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { .WillOnce(Return(true)); manager_.OnPacketSent(2, clock_.ApproximateNow(), 1000, NACK_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15); + clock_.AdvanceTime(rtt); // First, ACK packet 1 which makes packet 2 non-retransmittable. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)); ReceivedPacketInfo received_info; received_info.largest_observed = 1; - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); SendDataPacket(3); SendDataPacket(4); SendDataPacket(5); + clock_.AdvanceTime(rtt); + // Next, NACK packet 2 three times. received_info.largest_observed = 3; received_info.missing_packets.insert(2); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _, _)); - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _)); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); received_info.largest_observed = 4; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _, _)); - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _)); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); received_info.largest_observed = 5; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _)); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)); EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)); - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); // No packets remain unacked. VerifyUnackedPackets(NULL, 0); @@ -317,7 +330,8 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckPreviousBeforeSend) { // send algorithm is not informed that it has been ACK'd. ReceivedPacketInfo received_info; received_info.largest_observed = 1; - EXPECT_TRUE(manager_.OnIncomingAck(received_info, QuicTime::Zero())); + EXPECT_CALL(*send_algorithm_, UpdateRtt(QuicTime::Delta::Zero())); + EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow())); // Since 2 was marked for retransmit, when 1 is acked, 2 is discarded. VerifyUnackedPackets(NULL, 0); @@ -333,12 +347,15 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { SendDataPacket(1); RetransmitPacket(1, 2); RetransmitPacket(2, 3); + QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15); + clock_.AdvanceTime(rtt); // Ack 1 but not 2 or 3. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)); ReceivedPacketInfo received_info; received_info.largest_observed = 1; - manager_.OnIncomingAck(received_info, QuicTime::Zero()); + manager_.OnIncomingAck(received_info, clock_.ApproximateNow()); // 3 remains unacked, but no packets have retransmittable data. QuicPacketSequenceNumber unacked[] = { 3 }; @@ -643,7 +660,8 @@ TEST_F(QuicSentPacketManagerTest, NackRetransmit1Packet) { received_info.missing_packets.insert(1); for (QuicPacketSequenceNumber i = 1; i <= 3; ++i) { received_info.largest_observed = i + 1; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(i + 1, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(i + 1, _)).Times(1); if (i == 3) { EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); @@ -671,7 +689,8 @@ TEST_F(QuicSentPacketManagerTest, NackRetransmit1PacketWith1StretchAck) { QuicTime::Delta::FromMilliseconds(5); received_info.missing_packets.insert(1); received_info.largest_observed = kNumSentPackets; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(3); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -696,7 +715,8 @@ TEST_F(QuicSentPacketManagerTest, NackRetransmit1PacketSingleAck) { received_info.missing_packets.insert(2); received_info.missing_packets.insert(3); received_info.largest_observed = 4; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -718,7 +738,8 @@ TEST_F(QuicSentPacketManagerTest, EarlyRetransmit1Packet) { QuicTime::Delta::FromMilliseconds(5); received_info.missing_packets.insert(1); received_info.largest_observed = kNumSentPackets; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(kNumSentPackets, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(kNumSentPackets, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -744,7 +765,8 @@ TEST_F(QuicSentPacketManagerTest, DontEarlyRetransmitPacket) { received_info.missing_packets.insert(3); received_info.missing_packets.insert(4); received_info.largest_observed = kNumSentPackets; - EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -768,8 +790,9 @@ TEST_F(QuicSentPacketManagerTest, NackRetransmit2Packets) { for (size_t i = 1; i < kNumSentPackets; ++i) { received_info.missing_packets.insert(i); } + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); EXPECT_CALL(*send_algorithm_, - OnPacketAcked(kNumSentPackets, _, _)).Times(1); + OnPacketAcked(kNumSentPackets, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -839,8 +862,9 @@ TEST_F(QuicSentPacketManagerTest, NackTwiceThenAck) { received_info.largest_observed = i + 1; received_info.delta_time_largest_observed = QuicTime::Delta::FromMilliseconds(5); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); EXPECT_CALL(*send_algorithm_, - OnPacketAcked(_, _, _)).Times(i == 3 ? 2 : 1); + OnPacketAcked(_, _)).Times(i == 3 ? 2 : 1); manager_.OnIncomingAck(received_info, clock_.Now()); EXPECT_FALSE(manager_.HasPendingRetransmissions()); // The nack count remains at 2 when the packet is acked. @@ -855,8 +879,9 @@ TEST_F(QuicSentPacketManagerTest, Rtt) { SendDataPacket(sequence_number); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(expected_rtt)); EXPECT_CALL(*send_algorithm_, - OnPacketAcked(sequence_number, _, expected_rtt)).Times(1); + OnPacketAcked(sequence_number, _)).Times(1); ReceivedPacketInfo received_info; received_info.largest_observed = sequence_number; received_info.delta_time_largest_observed = @@ -874,8 +899,9 @@ TEST_F(QuicSentPacketManagerTest, RttWithInvalidDelta) { SendDataPacket(sequence_number); clock_.AdvanceTime(expected_rtt); + EXPECT_CALL(*send_algorithm_, UpdateRtt(expected_rtt)); EXPECT_CALL(*send_algorithm_, - OnPacketAcked(sequence_number, _, expected_rtt)).Times(1); + OnPacketAcked(sequence_number, _)).Times(1); ReceivedPacketInfo received_info; received_info.largest_observed = sequence_number; received_info.delta_time_largest_observed = @@ -892,8 +918,9 @@ TEST_F(QuicSentPacketManagerTest, RttWithInfiniteDelta) { SendDataPacket(sequence_number); clock_.AdvanceTime(expected_rtt); + EXPECT_CALL(*send_algorithm_, UpdateRtt(expected_rtt)); EXPECT_CALL(*send_algorithm_, - OnPacketAcked(sequence_number, _, expected_rtt)).Times(1); + OnPacketAcked(sequence_number, _)).Times(1); ReceivedPacketInfo received_info; received_info.largest_observed = sequence_number; received_info.delta_time_largest_observed = QuicTime::Delta::Infinite(); @@ -909,7 +936,8 @@ TEST_F(QuicSentPacketManagerTest, RttZeroDelta) { SendDataPacket(sequence_number); clock_.AdvanceTime(expected_rtt); - EXPECT_CALL(*send_algorithm_, OnPacketAcked(sequence_number, _, expected_rtt)) + EXPECT_CALL(*send_algorithm_, UpdateRtt(expected_rtt)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(sequence_number, _)) .Times(1); ReceivedPacketInfo received_info; received_info.largest_observed = sequence_number; @@ -937,7 +965,8 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) { // Ack the third and ensure the first two are considered lost, but they were // already abandoned, so that won't occur again. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _, _)); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _)); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2); ReceivedPacketInfo received_info; @@ -1007,7 +1036,8 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { // Now ack the two crypto packets and the speculatively encrypted request, // and ensure the first four crypto packets get abandoned, but not lost. - EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _, _)).Times(5); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(5); ReceivedPacketInfo received_info; received_info.largest_observed = 9; received_info.missing_packets.insert(1); @@ -1155,6 +1185,16 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeRTO) { // The delay should double the second time. expected_time = clock_.Now().Add(expected_rto_delay).Add(expected_rto_delay); EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); + + // Ack a packet and ensure the RTO goes back to the original value. + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + received_info.missing_packets.insert(1); + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + manager_.OnIncomingAck(received_info, clock_.ApproximateNow()); + + expected_time = clock_.Now().Add(expected_rto_delay); + EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) { diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 5ac6a9d..9be3a3b 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -64,12 +64,16 @@ class VisitorShim : public QuicConnectionVisitorInterface { session_->OnConfigNegotiated(); } - virtual void OnConnectionClosed(QuicErrorCode error, - bool from_peer) OVERRIDE { + virtual void OnConnectionClosed( + QuicErrorCode error, bool from_peer) OVERRIDE { session_->OnConnectionClosed(error, from_peer); // The session will go away, so don't bother with cleanup. } + virtual void OnWriteBlocked() OVERRIDE { + session_->OnWriteBlocked(); + } + virtual bool HasPendingHandshake() const OVERRIDE { return session_->HasPendingHandshake(); } @@ -269,16 +273,14 @@ bool QuicSession::OnCanWrite() { // may be modifying the list as we loop. int remaining_writes = write_blocked_streams_.NumBlockedStreams(); - while (!connection_->HasQueuedData() && - remaining_writes > 0) { + while (remaining_writes > 0 && connection_->CanWriteStreamData()) { DCHECK(write_blocked_streams_.HasWriteBlockedStreams()); if (!write_blocked_streams_.HasWriteBlockedStreams()) { LOG(DFATAL) << "WriteBlockedStream is missing"; connection_->CloseConnection(QUIC_INTERNAL_ERROR, false); return true; // We have no write blocked streams. } - int index = write_blocked_streams_.GetHighestPriorityWriteBlockedList(); - QuicStreamId stream_id = write_blocked_streams_.PopFront(index); + QuicStreamId stream_id = write_blocked_streams_.PopFront(); if (stream_id == kCryptoStreamId) { has_pending_handshake_ = false; // We just popped it. } @@ -588,6 +590,17 @@ size_t QuicSession::GetNumOpenStreams() const { } void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { +#ifndef NDEBUG + ReliableQuicStream* stream = GetStream(id); + if (stream != NULL) { + LOG_IF(DFATAL, priority != stream->EffectivePriority()) + << "Priorities do not match. Got: " << priority + << " Expected: " << stream->EffectivePriority(); + } else { + LOG(DFATAL) << "Marking unknown stream " << id << " blocked."; + } +#endif + if (id == kCryptoStreamId) { DCHECK(!has_pending_handshake_); has_pending_handshake_ = true; @@ -596,11 +609,11 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { // kHighestPriority. priority = kHighestPriority; } - write_blocked_streams_.PushBack(id, priority); + write_blocked_streams_.PushBack(id, priority, connection()->version()); } -bool QuicSession::HasQueuedData() const { - return write_blocked_streams_.NumBlockedStreams() || +bool QuicSession::HasDataToWrite() const { + return write_blocked_streams_.HasWriteBlockedStreams() || connection_->HasQueuedData(); } diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index a071587..a8ed206 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -21,8 +21,8 @@ #include "net/quic/quic_protocol.h" #include "net/quic/quic_spdy_compressor.h" #include "net/quic/quic_spdy_decompressor.h" +#include "net/quic/quic_write_blocked_list.h" #include "net/quic/reliable_quic_stream.h" -#include "net/spdy/write_blocked_list.h" namespace net { @@ -65,10 +65,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE; virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE; virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE; + virtual void OnWriteBlocked() OVERRIDE {} virtual void OnSuccessfulVersionNegotiation( const QuicVersion& version) OVERRIDE {} virtual void OnConfigNegotiated() OVERRIDE; - // Not needed for HTTP. virtual bool OnCanWrite() OVERRIDE; virtual bool HasPendingHandshake() const OVERRIDE; @@ -171,7 +171,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. - bool HasQueuedData() const; + bool HasDataToWrite() const; // Marks that |stream_id| is blocked waiting to decompress the // headers identified by |decompression_id|. @@ -303,7 +303,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { base::hash_set<QuicStreamId> implicitly_created_streams_; // A list of streams which need to write more data. - WriteBlockedList<QuicStreamId> write_blocked_streams_; + QuicWriteBlockedList write_blocked_streams_; // A map of headers waiting to be compressed, and the streams // they are associated with. diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 9d4acbf..2d362fd 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -7,7 +7,9 @@ #include <set> #include <vector> +#include "base/basictypes.h" #include "base/containers/hash_tables.h" +#include "net/quic/crypto/crypto_protocol.h" #include "net/quic/quic_crypto_stream.h" #include "net/quic/quic_protocol.h" #include "net/quic/reliable_quic_stream.h" @@ -26,13 +28,15 @@ using std::vector; using testing::_; using testing::InSequence; using testing::InvokeWithoutArgs; +using testing::Return; using testing::StrictMock; namespace net { namespace test { namespace { -const QuicPriority kSomeMiddlePriority = 2; +const QuicPriority kHighestPriority = 0; +const QuicPriority kSomeMiddlePriority = 3; class TestCryptoStream : public QuicCryptoStream { public: @@ -279,6 +283,32 @@ TEST_P(QuicSessionTest, DecompressionError) { } } +TEST_P(QuicSessionTest, DebugDFatalIfMarkingClosedStreamWriteBlocked) { + TestStream* stream2 = session_.CreateOutgoingDataStream(); + // Close the stream. + stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); + // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. + /* + QuicStreamId kClosedStreamId = stream2->id(); + EXPECT_DEBUG_DFATAL( + session_.MarkWriteBlocked(kClosedStreamId, kSomeMiddlePriority), + "Marking unknown stream 2 blocked."); + */ +} + +TEST_P(QuicSessionTest, DebugDFatalIfMarkWriteBlockedCalledWithWrongPriority) { + const QuicPriority kDifferentPriority = 0; + + TestStream* stream2 = session_.CreateOutgoingDataStream(); + EXPECT_NE(kDifferentPriority, stream2->EffectivePriority()); + // TODO(rtenneti): enable when chromium supports EXPECT_DEBUG_DFATAL. + /* + EXPECT_DEBUG_DFATAL( + session_.MarkWriteBlocked(stream2->id(), kDifferentPriority), + "Priorities do not match. Got: 0 Expected: 3"); + */ +} + TEST_P(QuicSessionTest, OnCanWrite) { TestStream* stream2 = session_.CreateOutgoingDataStream(); TestStream* stream4 = session_.CreateOutgoingDataStream(); @@ -299,6 +329,49 @@ TEST_P(QuicSessionTest, OnCanWrite) { EXPECT_FALSE(session_.OnCanWrite()); } +TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) { + InSequence s; + + // Drive congestion control manually. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + + TestStream* stream2 = session_.CreateOutgoingDataStream(); + TestStream* stream4 = session_.CreateOutgoingDataStream(); + TestStream* stream6 = session_.CreateOutgoingDataStream(); + + session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); + session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); + session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); + + StreamBlocker stream2_blocker(&session_, stream2->id()); + EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return( + QuicTime::Delta::Zero())); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return( + QuicTime::Delta::Zero())); + EXPECT_CALL(*stream6, OnCanWrite()); + EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return( + QuicTime::Delta::Infinite())); + // stream4->OnCanWrite is not called. + + // TODO(avd) change return value to 'true', since the connection + // can't write because it is congestion control blocked. + EXPECT_FALSE(session_.OnCanWrite()); + + // Still congestion-control blocked. + EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return( + QuicTime::Delta::Infinite())); + EXPECT_FALSE(session_.OnCanWrite()); + + // stream4->OnCanWrite is called once the connection stops being + // congestion-control blocked. + EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _, _)).WillOnce(Return( + QuicTime::Delta::Zero())); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_TRUE(session_.OnCanWrite()); +} + TEST_P(QuicSessionTest, BufferedHandshake) { EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. @@ -314,7 +387,7 @@ TEST_P(QuicSessionTest, BufferedHandshake) { EXPECT_FALSE(session_.HasPendingHandshake()); // Blocking (due to buffering of) the Crypto stream is detected. - session_.MarkWriteBlocked(kCryptoStreamId, kSomeMiddlePriority); + session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority); EXPECT_TRUE(session_.HasPendingHandshake()); TestStream* stream4 = session_.CreateOutgoingDataStream(); diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index cc21176..51b3487 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -7,6 +7,7 @@ #include <utility> #include <vector> +#include "base/logging.h" #include "base/rand_util.h" #include "net/base/ip_endpoint.h" #include "net/quic/reliable_quic_stream.h" diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index a2662c5..30ce560 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -8,11 +8,12 @@ #include <algorithm> +#include "base/basictypes.h" #include "base/logging.h" #include "base/port.h" #include "base/strings/stringprintf.h" #include "base/strings/string_number_conversions.h" -#include "net/spdy/write_blocked_list.h" +#include "net/quic/quic_write_blocked_list.h" using base::StringPiece; using std::string; @@ -285,12 +286,12 @@ string QuicUtils::StringToHexASCIIDump(StringPiece in_buffer) { // static QuicPriority QuicUtils::LowestPriority() { - return static_cast<QuicPriority>(kLowestPriority); + return QuicWriteBlockedList::kLowestPriority; } // static QuicPriority QuicUtils::HighestPriority() { - return static_cast<QuicPriority>(kHighestPriority); + return QuicWriteBlockedList::kHighestPriority; } } // namespace net diff --git a/net/quic/quic_write_blocked_list.cc b/net/quic/quic_write_blocked_list.cc new file mode 100644 index 0000000..cdca06f --- /dev/null +++ b/net/quic/quic_write_blocked_list.cc @@ -0,0 +1,21 @@ +// Copyright 2014 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_write_blocked_list.h" + +namespace net { + +const QuicPriority QuicWriteBlockedList::kHighestPriority = + static_cast<QuicPriority>(net::kHighestPriority); +const QuicPriority QuicWriteBlockedList::kLowestPriority = + static_cast<QuicPriority>(net::kLowestPriority); + +QuicWriteBlockedList::QuicWriteBlockedList() + : crypto_stream_blocked_(false), + headers_stream_blocked_(false) { +} + +QuicWriteBlockedList::~QuicWriteBlockedList() {} + +} // namespace net diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h new file mode 100644 index 0000000..3848b08 --- /dev/null +++ b/net/quic/quic_write_blocked_list.h @@ -0,0 +1,90 @@ +// Copyright 2014 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_WRITE_BLOCKED_LIST_H_ +#define NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_ + +#include "net/base/net_export.h" +#include "net/quic/quic_protocol.h" +#include "net/spdy/write_blocked_list.h" + +namespace net { + +// Keeps tracks of the QUIC streams that have data to write, sorted by +// priority. QUIC stream priority order is: +// Crypto stream > Headers stream > Data streams by requested priority. +class NET_EXPORT_PRIVATE QuicWriteBlockedList { + private: + typedef WriteBlockedList<QuicStreamId> QuicWriteBlockedListBase; + + public: + static const QuicPriority kHighestPriority; + static const QuicPriority kLowestPriority; + + QuicWriteBlockedList(); + ~QuicWriteBlockedList(); + + bool HasWriteBlockedStreams() const { + return crypto_stream_blocked_ || + headers_stream_blocked_ || + base_write_blocked_list_.HasWriteBlockedStreams(); + } + + size_t NumBlockedStreams() const { + size_t num_blocked = base_write_blocked_list_.NumBlockedStreams(); + if (crypto_stream_blocked_) { + ++num_blocked; + } + if (headers_stream_blocked_) { + ++num_blocked; + } + + return num_blocked; + } + + QuicStreamId PopFront() { + if (crypto_stream_blocked_) { + crypto_stream_blocked_ = false; + return kCryptoStreamId; + } else if (headers_stream_blocked_) { + headers_stream_blocked_ = false; + return kHeadersStreamId; + } else { + SpdyPriority priority = + base_write_blocked_list_.GetHighestPriorityWriteBlockedList(); + return base_write_blocked_list_.PopFront(priority); + } + } + + // TODO(avd) Remove version argument when QUIC_VERSION_12 is deprecated. + void PushBack(QuicStreamId stream_id, + QuicPriority priority, + QuicVersion version) { + if (stream_id == kCryptoStreamId) { + DCHECK_EQ(kHighestPriority, priority); + // TODO(avd) Add DCHECK(!crypto_stream_blocked_) + crypto_stream_blocked_ = true; + } else if (version > QUIC_VERSION_12 && + stream_id == kHeadersStreamId) { + DCHECK_EQ(kHighestPriority, priority); + // TODO(avd) Add DCHECK(!headers_stream_blocked_); + headers_stream_blocked_ = true; + } else { + base_write_blocked_list_.PushBack( + stream_id, static_cast<SpdyPriority>(priority)); + } + } + + private: + QuicWriteBlockedListBase base_write_blocked_list_; + bool crypto_stream_blocked_; + bool headers_stream_blocked_; + + DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList); +}; + +} // namespace net + + +#endif // NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_ diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc new file mode 100644 index 0000000..541e01f --- /dev/null +++ b/net/quic/quic_write_blocked_list_test.cc @@ -0,0 +1,106 @@ +// Copyright 2014 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_write_blocked_list.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { +namespace test { +namespace { + +TEST(QuicWriteBlockedListTest, PriorityOrder) { + QuicWriteBlockedList write_blocked_list; + + // Mark streams blocked in roughly reverse priority order, and + // verify that streams are sorted. + write_blocked_list.PushBack(40, + QuicWriteBlockedList::kLowestPriority, + QUIC_VERSION_13); + write_blocked_list.PushBack(23, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + write_blocked_list.PushBack(17, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + write_blocked_list.PushBack(kHeadersStreamId, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + write_blocked_list.PushBack(kCryptoStreamId, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + + EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams()); + // The Crypto stream is highest priority. + EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront()); + // Followed by the Headers stream. + EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); + // Streams with same priority are popped in the order they were inserted. + EXPECT_EQ(23u, write_blocked_list.PopFront()); + EXPECT_EQ(17u, write_blocked_list.PopFront()); + // Low priority stream appears last. + EXPECT_EQ(40u, write_blocked_list.PopFront()); + + EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams()); +} + +TEST(QuicWriteBlockedListTest, CryptoStream) { + QuicWriteBlockedList write_blocked_list; + write_blocked_list.PushBack(kCryptoStreamId, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + + EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams()); + EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront()); + EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams()); +} + +TEST(QuicWriteBlockedListTest, HeadersStream) { + QuicWriteBlockedList write_blocked_list; + write_blocked_list.PushBack(kHeadersStreamId, + QuicWriteBlockedList::kHighestPriority, + QUIC_VERSION_13); + + EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams()); + EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); + EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams()); +} + +TEST(QuicWriteBlockedListTest, NoHeadersStreamInVersion12) { + for (int idx = 0; idx < 2; ++idx) { + QuicVersion version = ((idx == 0) ? QUIC_VERSION_13 : QUIC_VERSION_12); + QuicWriteBlockedList write_blocked_list; + write_blocked_list.PushBack(5, + QuicWriteBlockedList::kHighestPriority, + version); + write_blocked_list.PushBack(kHeadersStreamId, + QuicWriteBlockedList::kHighestPriority, + version); + + EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams()); + if (version > QUIC_VERSION_12) { + // In newer QUIC versions, there is a headers stream which is + // higher priority than data streams. + EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); + EXPECT_EQ(5u, write_blocked_list.PopFront()); + } else { + // In older QUIC versions, there is no reserved headers stream id. + EXPECT_EQ(5u, write_blocked_list.PopFront()); + EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); + } + EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams()); + } +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index a04dc75..fc11f0b 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -7,7 +7,7 @@ #include "base/logging.h" #include "net/quic/quic_session.h" #include "net/quic/quic_spdy_decompressor.h" -#include "net/spdy/write_blocked_list.h" +#include "net/quic/quic_write_blocked_list.h" using base::StringPiece; using std::min; diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index e29005d..822baeb 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -11,6 +11,7 @@ #include <list> +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "net/base/iovec.h" #include "net/base/net_export.h" diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 7e82f53..ce352a7 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -9,6 +9,7 @@ #include "net/quic/quic_spdy_compressor.h" #include "net/quic/quic_spdy_decompressor.h" #include "net/quic/quic_utils.h" +#include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -117,7 +118,7 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { scoped_ptr<QuicSpdyCompressor> compressor_; scoped_ptr<QuicSpdyDecompressor> decompressor_; SpdyHeaderBlock headers_; - WriteBlockedList<QuicStreamId>* write_blocked_list_; + QuicWriteBlockedList* write_blocked_list_; }; TEST_F(ReliableQuicStreamTest, WriteAllData) { diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index 60674a9..65ba9ee 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h @@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "base/basictypes.h" #include "base/logging.h" #include "base/strings/string_piece.h" #include "net/quic/crypto/crypto_framer.h" diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index a7dcca5..83b3884 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -12,7 +12,6 @@ #include "net/quic/quic_received_packet_manager.h" #include "net/quic/test_tools/quic_framer_peer.h" #include "net/quic/test_tools/quic_sent_packet_manager_peer.h" -#include "net/quic/test_tools/quic_test_writer.h" namespace net { namespace test { @@ -116,17 +115,6 @@ QuicPacketEntropyHash QuicConnectionPeer::ReceivedEntropyHash( } // static -bool QuicConnectionPeer::IsWriteBlocked(QuicConnection* connection) { - return connection->write_blocked_; -} - -// static -void QuicConnectionPeer::SetIsWriteBlocked(QuicConnection* connection, - bool write_blocked) { - connection->write_blocked_ = write_blocked; -} - -// static bool QuicConnectionPeer::IsServer(QuicConnection* connection) { return connection->is_server_; } @@ -207,7 +195,7 @@ QuicPacketWriter* QuicConnectionPeer::GetWriter(QuicConnection* connection) { // static void QuicConnectionPeer::SetWriter(QuicConnection* connection, - QuicTestWriter* writer) { + QuicPacketWriter* writer) { connection->writer_ = writer; } @@ -216,5 +204,11 @@ void QuicConnectionPeer::CloseConnection(QuicConnection* connection) { connection->connected_ = false; } +// static +QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket( + QuicConnection* connection) { + return connection->connection_close_packet_.get(); +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 5b75b77..dc675a2 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -18,6 +18,7 @@ class QuicAlarm; class QuicConnection; class QuicConnectionHelperInterface; class QuicConnectionVisitorInterface; +class QuicEncryptedPacket; class QuicFecGroup; class QuicFramer; class QuicPacketCreator; @@ -29,8 +30,6 @@ class SendAlgorithmInterface; namespace test { -class QuicTestWriter; - // Peer to make public a number of otherwise private QuicConnection methods. class QuicConnectionPeer { public: @@ -77,10 +76,6 @@ class QuicConnectionPeer { QuicConnection* connection, QuicPacketSequenceNumber sequence_number); - static bool IsWriteBlocked(QuicConnection* connection); - - static void SetIsWriteBlocked(QuicConnection* connection, bool write_blocked); - static bool IsServer(QuicConnection* connection); static void SetIsServer(QuicConnection* connection, bool is_server); @@ -107,8 +102,10 @@ class QuicConnectionPeer { static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection); static QuicPacketWriter* GetWriter(QuicConnection* connection); - static void SetWriter(QuicConnection* connection, QuicTestWriter* writer); + static void SetWriter(QuicConnection* connection, QuicPacketWriter* writer); static void CloseConnection(QuicConnection* connection); + static QuicEncryptedPacket* GetConnectionClosePacket( + QuicConnection* connection); private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer); @@ -118,4 +115,4 @@ class QuicConnectionPeer { } // namespace net -#endif // NET_QUIC_TEST_TOOLS_QUIC_TEST_PEER_H_ +#endif // NET_QUIC_TEST_TOOLS_QUIC_CONNECTION_PEER_H_ diff --git a/net/quic/test_tools/quic_data_stream_peer.h b/net/quic/test_tools/quic_data_stream_peer.h index bfaf826..914b87d 100644 --- a/net/quic/test_tools/quic_data_stream_peer.h +++ b/net/quic/test_tools/quic_data_stream_peer.h @@ -6,7 +6,6 @@ #define NET_QUIC_TEST_TOOLS_QUIC_DATA_STREAM_PEER_H_ #include "base/basictypes.h" -#include "net/quic/quic_protocol.h" namespace net { diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc index 4cb38ca..080643b 100644 --- a/net/quic/test_tools/quic_session_peer.cc +++ b/net/quic/test_tools/quic_session_peer.cc @@ -27,7 +27,7 @@ QuicHeadersStream* QuicSessionPeer::GetHeadersStream(QuicSession* session) { } // static -WriteBlockedList<QuicStreamId>* QuicSessionPeer::GetWriteblockedStreams( +QuicWriteBlockedList* QuicSessionPeer::GetWriteblockedStreams( QuicSession* session) { return &session->write_blocked_streams_; } diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h index e432f9d..d8f1c75 100644 --- a/net/quic/test_tools/quic_session_peer.h +++ b/net/quic/test_tools/quic_session_peer.h @@ -6,7 +6,7 @@ #define NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_ #include "net/quic/quic_protocol.h" -#include "net/spdy/write_blocked_list.h" +#include "net/quic/quic_write_blocked_list.h" namespace net { @@ -21,8 +21,7 @@ class QuicSessionPeer { static void SetNextStreamId(QuicSession* session, QuicStreamId id); static void SetMaxOpenStreams(QuicSession* session, uint32 max_streams); static QuicHeadersStream* GetHeadersStream(QuicSession* session); - static WriteBlockedList<QuicStreamId>* GetWriteblockedStreams( - QuicSession* session); + static QuicWriteBlockedList* GetWriteblockedStreams(QuicSession* session); static QuicDataStream* GetIncomingDataStream(QuicSession* session, QuicStreamId stream_id); diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 188adad..bc1e151 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -226,6 +226,7 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame)); MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame)); MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer)); + MOCK_METHOD0(OnWriteBlocked, void()); MOCK_METHOD0(OnCanWrite, bool()); MOCK_CONST_METHOD0(HasPendingHandshake, bool()); MOCK_METHOD1(OnSuccessfulVersionNegotiation, @@ -353,6 +354,8 @@ class MockSession : public QuicSession { MOCK_METHOD0(IsHandshakeComplete, bool()); MOCK_METHOD0(IsCryptoHandshakeConfirmed, bool()); + using QuicSession::ActivateStream; + private: DISALLOW_COPY_AND_ASSIGN(MockSession); }; @@ -401,8 +404,8 @@ class MockSendAlgorithm : public SendAlgorithmInterface { void(const QuicCongestionFeedbackFrame&, QuicTime feedback_receive_time, const SentPacketsMap&)); - MOCK_METHOD3(OnPacketAcked, - void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta)); + MOCK_METHOD2(OnPacketAcked, + void(QuicPacketSequenceNumber, QuicByteCount)); MOCK_METHOD2(OnPacketLost, void(QuicPacketSequenceNumber, QuicTime)); MOCK_METHOD5(OnPacketSent, bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount, @@ -414,6 +417,7 @@ class MockSendAlgorithm : public SendAlgorithmInterface { HasRetransmittableData, IsHandshake)); MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void)); + MOCK_METHOD1(UpdateRtt, void(QuicTime::Delta rtt_sample)); MOCK_CONST_METHOD0(SmoothedRtt, QuicTime::Delta(void)); MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void)); MOCK_CONST_METHOD0(GetCongestionWindow, QuicByteCount()); diff --git a/net/quic/test_tools/quic_test_writer.cc b/net/quic/test_tools/quic_test_writer.cc deleted file mode 100644 index a1cd786..0000000 --- a/net/quic/test_tools/quic_test_writer.cc +++ /dev/null @@ -1,31 +0,0 @@ -// 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/test_tools/quic_test_writer.h" - -namespace net { -namespace test { - -QuicTestWriter::QuicTestWriter() {} - -QuicTestWriter::~QuicTestWriter() {} - -bool QuicTestWriter::IsWriteBlocked() const { - return writer_->IsWriteBlocked(); -} - -void QuicTestWriter::SetWritable() { - writer_->SetWritable(); -} - -QuicPacketWriter* QuicTestWriter::writer() { - return writer_.get(); -} - -void QuicTestWriter::set_writer(QuicPacketWriter* writer) { - writer_.reset(writer); -} - -} // namespace test -} // namespace net diff --git a/net/quic/test_tools/quic_test_writer.h b/net/quic/test_tools/quic_test_writer.h deleted file mode 100644 index 1fa655c..0000000 --- a/net/quic/test_tools/quic_test_writer.h +++ /dev/null @@ -1,37 +0,0 @@ -// 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_TEST_TOOLS_QUIC_TEST_WRITER_H_ -#define NET_QUIC_TEST_TOOLS_QUIC_TEST_WRITER_H_ - -#include "base/memory/scoped_ptr.h" -#include "net/quic/quic_packet_writer.h" - -namespace net { -namespace test { - -// Allows setting a writer for a QuicConnection, to allow -// fine-grained control of writes. -class QuicTestWriter : public QuicPacketWriter { - public: - QuicTestWriter(); - virtual ~QuicTestWriter(); - - virtual bool IsWriteBlocked() const OVERRIDE; - virtual void SetWritable() OVERRIDE; - - // Takes ownership of |writer|. - void set_writer(QuicPacketWriter* writer); - - protected: - QuicPacketWriter* writer(); - - private: - scoped_ptr<QuicPacketWriter> writer_; -}; - -} // namespace test -} // namespace net - -#endif // NET_QUIC_TEST_TOOLS_QUIC_TEST_WRITER_H_ diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h index 3a112e1..fe742ca 100644 --- a/net/quic/test_tools/simple_quic_framer.h +++ b/net/quic/test_tools/simple_quic_framer.h @@ -7,6 +7,7 @@ #include <vector> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 70f0325..437aa991 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -6,6 +6,7 @@ #include <string> #include <vector> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" #include "base/strings/string_number_conversions.h" @@ -21,10 +22,10 @@ #include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_test_utils.h" -#include "net/quic/test_tools/quic_test_writer.h" #include "net/quic/test_tools/reliable_quic_stream_peer.h" #include "net/tools/quic/quic_epoll_connection_helper.h" #include "net/tools/quic/quic_in_memory_cache.h" +#include "net/tools/quic/quic_packet_writer_wrapper.h" #include "net/tools/quic/quic_server.h" #include "net/tools/quic/quic_socket_utils.h" #include "net/tools/quic/quic_spdy_client_stream.h" @@ -42,7 +43,6 @@ using base::StringPiece; using base::WaitableEvent; using net::test::QuicConnectionPeer; using net::test::QuicSessionPeer; -using net::test::QuicTestWriter; using net::test::ReliableQuicStreamPeer; using net::tools::test::PacketDroppingTestWriter; using net::tools::test::QuicDispatcherPeer; @@ -179,7 +179,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> { QuicInMemoryCachePeer::ResetForTests(); } - virtual QuicTestClient* CreateQuicClient(QuicTestWriter* writer) { + virtual QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) { QuicTestClient* client = new QuicTestClient(server_address_, server_hostname_, false, // not secure @@ -204,8 +204,8 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> { } virtual void SetUp() { - // The ownership of these gets transferred to the QuicTestWriter and - // QuicDispatcher when Initialize() is executed. + // The ownership of these gets transferred to the QuicPacketWriterWrapper + // and QuicDispatcher when Initialize() is executed. client_writer_ = new PacketDroppingTestWriter(); server_writer_ = new PacketDroppingTestWriter(); } @@ -816,7 +816,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) { } } -class WrongAddressWriter : public QuicTestWriter { +class WrongAddressWriter : public QuicPacketWriterWrapper { public: WrongAddressWriter() { IPAddressNumber ip; @@ -825,12 +825,14 @@ class WrongAddressWriter : public QuicTestWriter { } virtual WriteResult WritePacket( - const char* buffer, size_t buf_len, + const char* buffer, + size_t buf_len, const IPAddressNumber& real_self_address, const IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) OVERRIDE { - return writer()->WritePacket(buffer, buf_len, self_address_.address(), - peer_address, blocked_writer); + // Use wrong address! + return QuicPacketWriterWrapper::WritePacket( + buffer, buf_len, self_address_.address(), peer_address, blocked_writer); } virtual bool IsWriteBlockedDataBuffered() const OVERRIDE { diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index df7a493..56648ad 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc @@ -247,12 +247,17 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) { } void QuicClient::OnClose(QuicDataStream* stream) { + QuicSpdyClientStream* client_stream = + static_cast<QuicSpdyClientStream*>(stream); + if (response_listener_.get() != NULL) { + response_listener_->OnCompleteResponse( + stream->id(), client_stream->headers(), client_stream->data()); + } + if (!print_response_) { return; } - QuicSpdyClientStream* client_stream = - static_cast<QuicSpdyClientStream*>(stream); const BalsaHeaders& headers = client_stream->headers(); printf("%s\n", headers.first_line().as_string().c_str()); for (BalsaHeaders::const_header_lines_iterator i = diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index 5e03882..0b8efe8 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h @@ -10,6 +10,7 @@ #include <string> +#include "base/basictypes.h" #include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "net/base/ip_endpoint.h" @@ -36,6 +37,15 @@ class QuicClientPeer; class QuicClient : public EpollCallbackInterface, public QuicDataStream::Visitor { public: + class ResponseListener { + public: + ResponseListener() {} + virtual ~ResponseListener() {} + virtual void OnCompleteResponse(QuicStreamId id, + const BalsaHeaders& response_headers, + const string& response_body) = 0; + }; + QuicClient(IPEndPoint server_address, const string& server_hostname, const QuicVersionVector& supported_versions, @@ -152,6 +162,11 @@ class QuicClient : public EpollCallbackInterface, supported_versions_ = versions; } + // Takes ownership of the listener. + void set_response_listener(ResponseListener* listener) { + response_listener_.reset(listener); + } + protected: virtual QuicGuid GenerateGuid(); virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper(); @@ -192,6 +207,9 @@ class QuicClient : public EpollCallbackInterface, // Helper to be used by created connections. scoped_ptr<QuicEpollConnectionHelper> helper_; + // Listens for full responses. + scoped_ptr<ResponseListener> response_listener_; + // Writer used to actually send packets to the wire. scoped_ptr<QuicPacketWriter> writer_; diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h index dcee15e..8330e2d 100644 --- a/net/tools/quic/quic_client_session.h +++ b/net/tools/quic/quic_client_session.h @@ -9,6 +9,7 @@ #include <string> +#include "base/basictypes.h" #include "net/quic/quic_crypto_client_stream.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_session.h" diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index dcb8d6a..e5fecc9 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc @@ -12,9 +12,11 @@ #include "net/quic/quic_utils.h" #include "net/tools/quic/quic_default_packet_writer.h" #include "net/tools/quic/quic_epoll_connection_helper.h" +#include "net/tools/quic/quic_packet_writer_wrapper.h" #include "net/tools/quic/quic_socket_utils.h" namespace net { + namespace tools { using base::StringPiece; @@ -39,8 +41,7 @@ class DeleteSessionsAlarm : public EpollAlarm { class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface { public: explicit QuicFramerVisitor(QuicDispatcher* dispatcher) - : dispatcher_(dispatcher) { - } + : dispatcher_(dispatcher) {} // QuicFramerVisitorInterface implementation virtual void OnPacket() OVERRIDE {} @@ -123,17 +124,12 @@ class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface { QuicDispatcher::QuicDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, const QuicVersionVector& supported_versions, - int fd, EpollServer* epoll_server) : config_(config), crypto_config_(crypto_config), - time_wait_list_manager_( - new QuicTimeWaitListManager(this, epoll_server, supported_versions)), delete_sessions_alarm_(new DeleteSessionsAlarm(this)), epoll_server_(epoll_server), - fd_(fd), helper_(new QuicEpollConnectionHelper(epoll_server_)), - writer_(new QuicDefaultPacketWriter(fd)), supported_versions_(supported_versions), current_packet_(NULL), framer_(supported_versions, /*unused*/ QuicTime::Zero(), true), @@ -146,9 +142,12 @@ QuicDispatcher::~QuicDispatcher() { STLDeleteElements(&closed_session_list_); } -void QuicDispatcher::set_fd(int fd) { - fd_ = fd; - writer_.reset(new QuicDefaultPacketWriter(fd)); +void QuicDispatcher::Initialize(int fd) { + DCHECK(writer_ == NULL); + writer_.reset(CreateWriterWrapper(CreateWriter(fd))); + time_wait_list_manager_.reset( + new QuicTimeWaitListManager(writer_.get(), this, + epoll_server(), supported_versions())); } // TODO(fnk): remove the Writer interface implementation in favor of @@ -332,6 +331,11 @@ void QuicDispatcher::OnConnectionClosed(QuicGuid guid, QuicErrorCode error) { CleanUpSession(it); } +void QuicDispatcher::OnWriteBlocked(QuicBlockedWriterInterface* writer) { + DCHECK(writer_->IsWriteBlocked()); + write_blocked_list_.insert(make_pair(writer, true)); +} + QuicSession* QuicDispatcher::CreateQuicSession( QuicGuid guid, const IPEndPoint& server_address, @@ -343,6 +347,19 @@ QuicSession* QuicDispatcher::CreateQuicSession( return session; } +QuicPacketWriter* QuicDispatcher::CreateWriter(int fd) { + return new QuicDefaultPacketWriter(fd); +} + +QuicPacketWriterWrapper* QuicDispatcher::CreateWriterWrapper( + QuicPacketWriter* writer) { + return new QuicPacketWriterWrapper(writer); +} + +void QuicDispatcher::set_writer(QuicPacketWriter* writer) { + writer_->set_writer(writer); +} + bool QuicDispatcher::HandlePacketForTimeWait( const QuicPacketPublicHeader& header) { if (header.reset_flag) { diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 1c010ab..47c31d2 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h @@ -10,6 +10,7 @@ #include <list> +#include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "net/base/ip_endpoint.h" @@ -37,11 +38,14 @@ namespace net { class EpollServer; class QuicConfig; +class QuicConnectionHelper; class QuicCryptoServerConfig; class QuicSession; namespace tools { +class QuicPacketWriterWrapper; + namespace test { class QuicDispatcherPeer; } // namespace test @@ -49,7 +53,8 @@ class QuicDispatcherPeer; class DeleteSessionsAlarm; class QuicEpollConnectionHelper; -class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { +class QuicDispatcher : public QuicPacketWriter, + public QuicServerSessionVisitor { public: // Ideally we'd have a linked_hash_set: the boolean is unused. typedef linked_hash_map<QuicBlockedWriterInterface*, bool> WriteBlockedList; @@ -60,10 +65,12 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { QuicDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, const QuicVersionVector& supported_versions, - int fd, EpollServer* epoll_server); + virtual ~QuicDispatcher(); + void Initialize(int fd); + // QuicPacketWriter virtual WriteResult WritePacket( const char* buffer, size_t buf_len, @@ -89,11 +96,12 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { // Sends ConnectionClose frames to all connected clients. void Shutdown(); + // QuicServerSessionVisitor interface implementation: // Ensure that the closed connection is cleaned up asynchronously. virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) OVERRIDE; - // Sets the fd and creates a default packet writer with that fd. - void set_fd(int fd); + // Queues the blocked writer for later resumption. + virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) OVERRIDE; typedef base::hash_map<QuicGuid, QuicSession*> SessionMap; @@ -110,8 +118,17 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { WriteBlockedList* write_blocked_list() { return &write_blocked_list_; } protected: - const QuicConfig& config_; - const QuicCryptoServerConfig& crypto_config_; + // Instantiates a new low-level packet writer. Caller takes ownership of the + // returned object. + QuicPacketWriter* CreateWriter(int fd); + + // Instantiates a new top-level writer wrapper. Takes ownership of |writer|. + // Caller takes ownership of the returned object. + virtual QuicPacketWriterWrapper* CreateWriterWrapper( + QuicPacketWriter* writer); + + // Replaces the packet writer with |writer|. Takes ownership of |writer|. + void set_writer(QuicPacketWriter* writer); QuicTimeWaitListManager* time_wait_list_manager() { return time_wait_list_manager_.get(); @@ -124,7 +141,6 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { return supported_versions_; } - protected: // Called by |framer_visitor_| when the public header has been parsed. virtual bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header); @@ -140,6 +156,10 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { return *current_packet_; } + const QuicConfig& config() const { return config_; } + + const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; } + private: class QuicFramerVisitor; friend class net::tools::test::QuicDispatcherPeer; @@ -154,6 +174,10 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header); + const QuicConfig& config_; + + const QuicCryptoServerConfig& crypto_config_; + // The list of connections waiting to write. WriteBlockedList write_blocked_list_; @@ -170,14 +194,13 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { EpollServer* epoll_server_; // Owned by the server. - // The connection for client-server communication - int fd_; - // The helper used for all connections. scoped_ptr<QuicEpollConnectionHelper> helper_; - // The writer to write to the socket with. - scoped_ptr<QuicPacketWriter> writer_; + // The writer to write to the socket with. We require a writer wrapper to + // allow replacing writer implementation without disturbing running + // connections. + scoped_ptr<QuicPacketWriterWrapper> writer_; // This vector contains QUIC versions which we currently support. // This should be ordered such that the highest supported version is the first diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 63400c1..5e4726f 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc @@ -12,8 +12,8 @@ #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_crypto_stream.h" #include "net/quic/test_tools/quic_test_utils.h" -#include "net/quic/test_tools/quic_test_writer.h" #include "net/tools/epoll_server/epoll_server.h" +#include "net/tools/quic/quic_packet_writer_wrapper.h" #include "net/tools/quic/quic_time_wait_list_manager.h" #include "net/tools/quic/test_tools/quic_dispatcher_peer.h" #include "net/tools/quic/test_tools/quic_test_utils.h" @@ -23,7 +23,6 @@ using base::StringPiece; using net::EpollServer; using net::test::MockSession; -using net::test::QuicTestWriter; using net::tools::test::MockConnection; using std::make_pair; using testing::_; @@ -43,7 +42,7 @@ class TestDispatcher : public QuicDispatcher { explicit TestDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, EpollServer* eps) - : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), 1, eps) { + : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), eps) { } MOCK_METHOD3(CreateQuicSession, QuicSession*( @@ -62,8 +61,8 @@ class MockServerConnection : public MockConnection { MockServerConnection(QuicGuid guid, QuicDispatcher* dispatcher) : MockConnection(guid, true), - dispatcher_(dispatcher) { - } + dispatcher_(dispatcher) {} + void UnregisterOnConnectionClosed() { LOG(ERROR) << "Unregistering " << guid(); dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR); @@ -95,6 +94,7 @@ class QuicDispatcherTest : public ::testing::Test { dispatcher_(config_, crypto_config_, &eps_), session1_(NULL), session2_(NULL) { + dispatcher_.Initialize(1); } virtual ~QuicDispatcherTest() {} @@ -202,8 +202,9 @@ TEST_F(QuicDispatcherTest, Shutdown) { class MockTimeWaitListManager : public QuicTimeWaitListManager { public: MockTimeWaitListManager(QuicPacketWriter* writer, + QuicServerSessionVisitor* visitor, EpollServer* eps) - : QuicTimeWaitListManager(writer, eps, QuicSupportedVersions()) { + : QuicTimeWaitListManager(writer, visitor, eps, QuicSupportedVersions()) { } MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address, @@ -215,7 +216,7 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { TEST_F(QuicDispatcherTest, TimeWaitListManager) { MockTimeWaitListManager* time_wait_list_manager = new MockTimeWaitListManager( - QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_); + QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_); // dispatcher takes the ownership of time_wait_list_manager. QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_, time_wait_list_manager); @@ -257,7 +258,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { MockTimeWaitListManager* time_wait_list_manager = new MockTimeWaitListManager( - QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_); + QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_); // dispatcher takes the ownership of time_wait_list_manager. QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_, time_wait_list_manager); @@ -272,30 +273,31 @@ TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { ProcessPacket(addr, guid, false, "foo"); } -class BlockingWriter : public QuicTestWriter { +class BlockingWriter : public QuicPacketWriterWrapper { public: BlockingWriter() : write_blocked_(false) {} virtual bool IsWriteBlocked() const OVERRIDE { return write_blocked_; } virtual void SetWritable() OVERRIDE { write_blocked_ = false; } - virtual bool IsWriteBlockedDataBuffered() const OVERRIDE { return false; } virtual WriteResult WritePacket( - const char* buffer, size_t buf_len, const IPAddressNumber& self_address, + const char* buffer, + size_t buf_len, + const IPAddressNumber& self_address, const IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) OVERRIDE { if (write_blocked_) { return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN); } else { - return writer()->WritePacket(buffer, buf_len, self_address, peer_address, - blocked_writer); + return QuicPacketWriterWrapper::WritePacket( + buffer, buf_len, self_address, peer_address, blocked_writer); } } bool write_blocked_; }; -class QuicWriteBlockedListTest : public QuicDispatcherTest { +class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest { public: virtual void SetUp() { writer_ = new BlockingWriter; @@ -323,7 +325,7 @@ class QuicWriteBlockedListTest : public QuicDispatcherTest { } bool SetBlocked() { - writer_->write_blocked_ = true;; + writer_->write_blocked_ = true; return true; } @@ -332,12 +334,13 @@ class QuicWriteBlockedListTest : public QuicDispatcherTest { QuicDispatcher::WriteBlockedList* blocked_list_; }; -TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) { +TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) { // No OnCanWrite calls because no connections are blocked. dispatcher_.OnCanWrite(); - // Register connection 1 for events, and make sure it's nofitied. - blocked_list_->insert(make_pair(connection1(), true)); + // Register connection 1 for events, and make sure it's notified. + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); EXPECT_CALL(*connection1(), OnCanWrite()); dispatcher_.OnCanWrite(); @@ -346,67 +349,75 @@ TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) { EXPECT_FALSE(dispatcher_.OnCanWrite()); } -TEST_F(QuicWriteBlockedListTest, OnCanWriteOrder) { +TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) { // Make sure we handle events in order. InSequence s; - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection2(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection2()); EXPECT_CALL(*connection1(), OnCanWrite()); EXPECT_CALL(*connection2(), OnCanWrite()); dispatcher_.OnCanWrite(); // Check the other ordering. - blocked_list_->insert(make_pair(connection2(), true)); - blocked_list_->insert(make_pair(connection1(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection2()); + dispatcher_.OnWriteBlocked(connection1()); EXPECT_CALL(*connection2(), OnCanWrite()); EXPECT_CALL(*connection1(), OnCanWrite()); dispatcher_.OnCanWrite(); } -TEST_F(QuicWriteBlockedListTest, OnCanWriteRemove) { +TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) { // Add and remove one connction. - blocked_list_->insert(make_pair(connection1(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); blocked_list_->erase(connection1()); EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); dispatcher_.OnCanWrite(); // Add and remove one connction and make sure it doesn't affect others. - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection2(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection2()); blocked_list_->erase(connection1()); EXPECT_CALL(*connection2(), OnCanWrite()); dispatcher_.OnCanWrite(); // Add it, remove it, and add it back and make sure things are OK. - blocked_list_->insert(make_pair(connection1(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); blocked_list_->erase(connection1()); - blocked_list_->insert(make_pair(connection1(), true)); + dispatcher_.OnWriteBlocked(connection1()); EXPECT_CALL(*connection1(), OnCanWrite()).Times(1); dispatcher_.OnCanWrite(); } -TEST_F(QuicWriteBlockedListTest, DoubleAdd) { +TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) { // Make sure a double add does not necessitate a double remove. - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection1(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection1()); blocked_list_->erase(connection1()); EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); dispatcher_.OnCanWrite(); // Make sure a double add does not result in two OnCanWrite calls. - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection1(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection1()); EXPECT_CALL(*connection1(), OnCanWrite()).Times(1); dispatcher_.OnCanWrite(); } -TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) { +TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) { // Finally make sure if we write block on a write call, we stop calling. InSequence s; - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection2(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection2()); EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce( - Invoke(this, &QuicWriteBlockedListTest::SetBlocked)); + Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked)); EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); dispatcher_.OnCanWrite(); @@ -415,12 +426,13 @@ TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) { dispatcher_.OnCanWrite(); } -TEST_F(QuicWriteBlockedListTest, LimitedWrites) { +TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) { // Make sure we call both writers. The first will register for more writing // but should not be immediately called due to limits. InSequence s; - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection2(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection2()); EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true)); EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false)); dispatcher_.OnCanWrite(); @@ -430,13 +442,14 @@ TEST_F(QuicWriteBlockedListTest, LimitedWrites) { dispatcher_.OnCanWrite(); } -TEST_F(QuicWriteBlockedListTest, TestWriteLimits) { +TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) { // Finally make sure if we write block on a write call, we stop calling. InSequence s; - blocked_list_->insert(make_pair(connection1(), true)); - blocked_list_->insert(make_pair(connection2(), true)); + SetBlocked(); + dispatcher_.OnWriteBlocked(connection1()); + dispatcher_.OnWriteBlocked(connection2()); EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce( - Invoke(this, &QuicWriteBlockedListTest::SetBlocked)); + Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked)); EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); dispatcher_.OnCanWrite(); diff --git a/net/tools/quic/quic_epoll_clock.h b/net/tools/quic/quic_epoll_clock.h index fb21354..76c0c50 100644 --- a/net/tools/quic/quic_epoll_clock.h +++ b/net/tools/quic/quic_epoll_clock.h @@ -5,6 +5,7 @@ #ifndef NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_ #define NET_TOOLS_QUIC_QUIC_EPOLL_CLOCK_H_ +#include "base/basictypes.h" #include "base/compiler_specific.h" #include "net/quic/quic_clock.h" #include "net/quic/quic_time.h" diff --git a/net/tools/quic/quic_packet_writer_wrapper.cc b/net/tools/quic/quic_packet_writer_wrapper.cc new file mode 100644 index 0000000..f45b90c --- /dev/null +++ b/net/tools/quic/quic_packet_writer_wrapper.cc @@ -0,0 +1,50 @@ +// Copyright 2014 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/tools/quic/quic_packet_writer_wrapper.h" + +#include "net/quic/quic_protocol.h" + +namespace net { +namespace tools { + +QuicPacketWriterWrapper::QuicPacketWriterWrapper() {} + +QuicPacketWriterWrapper::QuicPacketWriterWrapper(QuicPacketWriter* writer) + : writer_(writer) {} + +QuicPacketWriterWrapper::~QuicPacketWriterWrapper() {} + +WriteResult QuicPacketWriterWrapper::WritePacket( + const char* buffer, + size_t buf_len, + const net::IPAddressNumber& self_address, + const net::IPEndPoint& peer_address, + QuicBlockedWriterInterface* blocked_writer) { + return writer_->WritePacket( + buffer, buf_len, self_address, peer_address, blocked_writer); +} + +bool QuicPacketWriterWrapper::IsWriteBlockedDataBuffered() const { + return writer_->IsWriteBlockedDataBuffered(); +} + +bool QuicPacketWriterWrapper::IsWriteBlocked() const { + return writer_->IsWriteBlocked(); +} + +void QuicPacketWriterWrapper::SetWritable() { + writer_->SetWritable(); +} + +void QuicPacketWriterWrapper::set_writer(QuicPacketWriter* writer) { + writer_.reset(writer); +} + +QuicPacketWriter* QuicPacketWriterWrapper::release_writer() { + return writer_.release(); +} + +} // namespace tools +} // namespace net diff --git a/net/tools/quic/quic_packet_writer_wrapper.h b/net/tools/quic/quic_packet_writer_wrapper.h new file mode 100644 index 0000000..4a74ce8 --- /dev/null +++ b/net/tools/quic/quic_packet_writer_wrapper.h @@ -0,0 +1,51 @@ +// Copyright 2014 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_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_ +#define NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_ + +#include "base/memory/scoped_ptr.h" +#include "net/quic/quic_packet_writer.h" + +namespace net { + +namespace tools { + +// Wraps a writer object to allow dynamically extending functionality. Use +// cases: replace writer while dispatcher and connections hold on to the +// wrapper; mix in monitoring in internal server; mix in mocks in unit tests. +class QuicPacketWriterWrapper : public net::QuicPacketWriter { + public: + QuicPacketWriterWrapper(); + explicit QuicPacketWriterWrapper(QuicPacketWriter* writer); + virtual ~QuicPacketWriterWrapper(); + + // Default implementation of the QuicPacketWriter interface. Passes everything + // to |writer_|. + virtual WriteResult WritePacket( + const char* buffer, + size_t buf_len, + const IPAddressNumber& self_address, + const IPEndPoint& peer_address, + QuicBlockedWriterInterface* blocked_writer) OVERRIDE; + virtual bool IsWriteBlockedDataBuffered() const OVERRIDE; + virtual bool IsWriteBlocked() const OVERRIDE; + virtual void SetWritable() OVERRIDE; + + // Takes ownership of |writer|. + void set_writer(QuicPacketWriter* writer); + + // Releases ownership of |writer_|. + QuicPacketWriter* release_writer(); + + private: + scoped_ptr<QuicPacketWriter> writer_; + + DISALLOW_COPY_AND_ASSIGN(QuicPacketWriterWrapper); +}; + +} // namespace tools +} // namespace net + +#endif // NET_TOOLS_QUIC_QUIC_PACKET_WRITER_WRAPPER_H_ diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index 472f2b8..bef78e6 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc @@ -147,9 +147,9 @@ bool QuicServer::Listen(const IPEndPoint& address) { } epoll_server_.RegisterFD(fd_, this, kEpollFlags); - dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, - supported_versions_, - fd_, &epoll_server_)); + dispatcher_.reset(new QuicDispatcher( + config_, crypto_config_, supported_versions_, &epoll_server_)); + dispatcher_->Initialize(fd_); return true; } diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 1c22f11..fefac5d 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h @@ -8,6 +8,7 @@ #ifndef NET_TOOLS_QUIC_QUIC_SERVER_H_ #define NET_TOOLS_QUIC_QUIC_SERVER_H_ +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "net/base/ip_endpoint.h" #include "net/quic/crypto/quic_crypto_server_config.h" diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc index 29fd3165..1d0494c 100644 --- a/net/tools/quic/quic_server_session.cc +++ b/net/tools/quic/quic_server_session.cc @@ -15,13 +15,11 @@ namespace tools { QuicServerSession::QuicServerSession( const QuicConfig& config, QuicConnection* connection, - QuicSessionOwner* owner) + QuicServerSessionVisitor* visitor) : QuicSession(connection, config), - owner_(owner) { -} + visitor_(visitor) {} -QuicServerSession::~QuicServerSession() { -} +QuicServerSession::~QuicServerSession() {} void QuicServerSession::InitializeSession( const QuicCryptoServerConfig& crypto_config) { @@ -36,7 +34,12 @@ QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream( void QuicServerSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) { QuicSession::OnConnectionClosed(error, from_peer); - owner_->OnConnectionClosed(connection()->guid(), error); + visitor_->OnConnectionClosed(connection()->guid(), error); +} + +void QuicServerSession::OnWriteBlocked() { + QuicSession::OnWriteBlocked(); + visitor_->OnWriteBlocked(connection()); } bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) { diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h index ff921bb..288cc68 100644 --- a/net/tools/quic/quic_server_session.h +++ b/net/tools/quic/quic_server_session.h @@ -10,6 +10,7 @@ #include <set> #include <vector> +#include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "net/quic/quic_crypto_server_stream.h" @@ -18,6 +19,7 @@ namespace net { +class QuicBlockedWriterInterface; class QuicConfig; class QuicConnection; class QuicCryptoServerConfig; @@ -31,22 +33,24 @@ class QuicServerSessionPeer; // An interface from the session to the entity owning the session. // This lets the session notify its owner (the Dispatcher) when the connection -// is closed. -class QuicSessionOwner { +// is closed or blocked. +class QuicServerSessionVisitor { public: - virtual ~QuicSessionOwner() {} + virtual ~QuicServerSessionVisitor() {} virtual void OnConnectionClosed(QuicGuid guid, QuicErrorCode error) = 0; + virtual void OnWriteBlocked(QuicBlockedWriterInterface* writer) = 0; }; class QuicServerSession : public QuicSession { public: QuicServerSession(const QuicConfig& config, QuicConnection *connection, - QuicSessionOwner* owner); + QuicServerSessionVisitor* visitor); // Override the base class to notify the owner of the connection close. virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE; + virtual void OnWriteBlocked() OVERRIDE; virtual ~QuicServerSession(); @@ -74,7 +78,7 @@ class QuicServerSession : public QuicSession { friend class test::QuicServerSessionPeer; scoped_ptr<QuicCryptoServerStream> crypto_stream_; - QuicSessionOwner* owner_; + QuicServerSessionVisitor* visitor_; DISALLOW_COPY_AND_ASSIGN(QuicServerSession); }; diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index 2673148..1b2cb3f 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc @@ -60,10 +60,9 @@ class TestQuicQuicServerSession : public QuicServerSession { public: TestQuicQuicServerSession(const QuicConfig& config, QuicConnection* connection, - QuicSessionOwner* owner) + QuicServerSessionVisitor* owner) : QuicServerSession(config, connection, owner), - close_stream_on_data_(false) { - } + close_stream_on_data_(false) {} virtual QuicDataStream* CreateIncomingDataStream( QuicStreamId id) OVERRIDE { @@ -110,7 +109,7 @@ class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> { QuicDataStreamPeer::SetHeadersDecompressed(stream, true); } - StrictMock<MockQuicSessionOwner> owner_; + StrictMock<MockQuicServerSessionVisitor> owner_; StrictMock<MockConnection>* connection_; QuicConfig config_; QuicCryptoServerConfig crypto_config_; diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc index 23efeb6..833c25f 100644 --- a/net/tools/quic/quic_server_test.cc +++ b/net/tools/quic/quic_server_test.cc @@ -21,7 +21,9 @@ class QuicServerDispatchPacketTest : public ::testing::Test { public: QuicServerDispatchPacketTest() : crypto_config_("blah", QuicRandom::GetInstance()), - dispatcher_(config_, crypto_config_, 1234, &eps_) {} + dispatcher_(config_, crypto_config_, &eps_) { + dispatcher_.Initialize(1234); + } void DispatchPacket(const QuicEncryptedPacket& packet) { IPEndPoint client_addr, server_addr; diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc index 87071a6..c51c9ae 100644 --- a/net/tools/quic/quic_socket_utils.cc +++ b/net/tools/quic/quic_socket_utils.cc @@ -11,6 +11,7 @@ #include <sys/uio.h> #include <string> +#include "base/basictypes.h" #include "base/logging.h" #include "net/quic/quic_protocol.h" diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h index 1e60467..37b0812 100644 --- a/net/tools/quic/quic_spdy_client_stream.h +++ b/net/tools/quic/quic_spdy_client_stream.h @@ -8,6 +8,7 @@ #include <sys/types.h> #include <string> +#include "base/basictypes.h" #include "base/strings/string_piece.h" #include "net/base/io_buffer.h" #include "net/quic/quic_data_stream.h" diff --git a/net/tools/quic/quic_spdy_server_stream.h b/net/tools/quic/quic_spdy_server_stream.h index 574ef76..029e25f 100644 --- a/net/tools/quic/quic_spdy_server_stream.h +++ b/net/tools/quic/quic_spdy_server_stream.h @@ -7,6 +7,7 @@ #include <string> +#include "base/basictypes.h" #include "net/base/io_buffer.h" #include "net/quic/quic_data_stream.h" #include "net/quic/quic_protocol.h" diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index d17d721..4708d61 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc @@ -17,6 +17,7 @@ #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" +#include "net/tools/quic/quic_server_session.h" using base::StringPiece; using std::make_pair; @@ -93,13 +94,15 @@ class QuicTimeWaitListManager::QueuedPacket { QuicTimeWaitListManager::QuicTimeWaitListManager( QuicPacketWriter* writer, + QuicServerSessionVisitor* visitor, EpollServer* epoll_server, const QuicVersionVector& supported_versions) : epoll_server_(epoll_server), kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)), guid_clean_up_alarm_(new GuidCleanUpAlarm(this)), clock_(epoll_server_), - writer_(writer) { + writer_(writer), + visitor_(visitor) { SetGuidCleanUpAlarm(); } @@ -215,6 +218,7 @@ void QuicTimeWaitListManager::SendOrQueuePacket(QueuedPacket* packet) { bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { if (writer_->IsWriteBlocked()) { + visitor_->OnWriteBlocked(this); return false; } WriteResult result = writer_->WritePacket( @@ -226,6 +230,7 @@ bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) { if (result.status == WRITE_STATUS_BLOCKED) { // If blocked and unbuffered, return false to retry sending. DCHECK(writer_->IsWriteBlocked()); + visitor_->OnWriteBlocked(this); return writer_->IsWriteBlockedDataBuffered(); } else if (result.status == WRITE_STATUS_ERROR) { LOG(WARNING) << "Received unknown error while sending reset packet to " diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h index bb1caf2..70a6d0d 100644 --- a/net/tools/quic/quic_time_wait_list_manager.h +++ b/net/tools/quic/quic_time_wait_list_manager.h @@ -10,6 +10,7 @@ #include <deque> +#include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/strings/string_piece.h" #include "net/quic/quic_blocked_writer_interface.h" @@ -23,6 +24,7 @@ namespace net { namespace tools { class GuidCleanUpAlarm; +class QuicServerSessionVisitor; namespace test { class QuicTimeWaitListManagerPeer; @@ -39,8 +41,10 @@ class QuicTimeWaitListManagerPeer; class QuicTimeWaitListManager : public QuicBlockedWriterInterface { public: // writer - the entity that writes to the socket. (Owned by the dispatcher) + // visitor - the entity that manages blocked writers. (The dispatcher) // epoll_server - used to run clean up alarms. (Owned by the dispatcher) QuicTimeWaitListManager(QuicPacketWriter* writer, + QuicServerSessionVisitor* visitor, EpollServer* epoll_server, const QuicVersionVector& supported_versions); virtual ~QuicTimeWaitListManager(); @@ -137,7 +141,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { std::deque<QueuedPacket*> pending_packets_queue_; // Used to schedule alarms to delete old guids which have been in the list for - // too long. Owned by the dispatcher. + // too long. EpollServer* epoll_server_; // Time period for which guids should remain in time wait state. @@ -150,9 +154,12 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // Clock to efficiently measure approximate time from the epoll server. QuicEpollClock clock_; - // Interface that writes given buffer to the socket. Owned by the dispatcher. + // Interface that writes given buffer to the socket. QuicPacketWriter* writer_; + // Interface that manages blocked writers. + QuicServerSessionVisitor* visitor_; + DISALLOW_COPY_AND_ASSIGN(QuicTimeWaitListManager); }; diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index 31cbd41..6e76e96 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc @@ -41,7 +41,7 @@ namespace test { class QuicTimeWaitListManagerPeer { public: static bool ShouldSendResponse(QuicTimeWaitListManager* manager, - int received_packet_count) { + int received_packet_count) { return manager->ShouldSendResponse(received_packet_count); } @@ -57,14 +57,6 @@ class QuicTimeWaitListManagerPeer { namespace { -class TestTimeWaitListManager : public QuicTimeWaitListManager { - public: - TestTimeWaitListManager(QuicPacketWriter* writer, - EpollServer* epoll_server) - : QuicTimeWaitListManager(writer, epoll_server, QuicSupportedVersions()) { - } -}; - class MockFakeTimeEpollServer : public FakeTimeEpollServer { public: MOCK_METHOD2(RegisterAlarm, void(int64 timeout_in_us, @@ -74,8 +66,8 @@ class MockFakeTimeEpollServer : public FakeTimeEpollServer { class QuicTimeWaitListManagerTest : public testing::Test { protected: QuicTimeWaitListManagerTest() - : time_wait_list_manager_( - &writer_, &epoll_server_, QuicSupportedVersions()), + : time_wait_list_manager_(&writer_, &visitor_, + &epoll_server_, QuicSupportedVersions()), framer_(QuicSupportedVersions(), QuicTime::Zero(), true), guid_(45), writer_is_blocked_(false) {} @@ -142,6 +134,7 @@ class QuicTimeWaitListManagerTest : public testing::Test { NiceMock<MockFakeTimeEpollServer> epoll_server_; StrictMock<MockPacketWriter> writer_; + StrictMock<MockQuicServerSessionVisitor> visitor_; QuicTimeWaitListManager time_wait_list_manager_; QuicFramer framer_; QuicGuid guid_; @@ -307,6 +300,7 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) { .WillOnce(DoAll( Assign(&writer_is_blocked_, true), Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN)))); + EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_)); ProcessPacket(guid, sequence_number); // 3rd packet. No public reset should be sent; ProcessPacket(guid, sequence_number); @@ -321,6 +315,7 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) { ENCRYPTION_NONE, other_guid, other_sequence_number)); EXPECT_CALL(writer_, WritePacket(_, _, _, _, _)) .Times(0); + EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_)); ProcessPacket(other_guid, other_sequence_number); // Now expect all the write blocked public reset packets to be sent again. diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/net/tools/quic/test_tools/mock_quic_dispatcher.cc index 2d9c1ec..7248909 100644 --- a/net/tools/quic/test_tools/mock_quic_dispatcher.cc +++ b/net/tools/quic/test_tools/mock_quic_dispatcher.cc @@ -11,11 +11,9 @@ namespace test { MockQuicDispatcher::MockQuicDispatcher( const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, - QuicGuid guid, EpollServer* eps) - : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), guid, - eps) { -} + : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), eps) {} + MockQuicDispatcher::~MockQuicDispatcher() {} } // namespace test diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.h b/net/tools/quic/test_tools/mock_quic_dispatcher.h index 36813c9..a2fec0f 100644 --- a/net/tools/quic/test_tools/mock_quic_dispatcher.h +++ b/net/tools/quic/test_tools/mock_quic_dispatcher.h @@ -21,8 +21,8 @@ class MockQuicDispatcher : public QuicDispatcher { public: MockQuicDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, - QuicGuid guid, EpollServer* eps); + virtual ~MockQuicDispatcher(); MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address, diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc index fe26579..0331efd 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc @@ -10,8 +10,6 @@ #include "net/tools/quic/quic_epoll_connection_helper.h" #include "net/tools/quic/quic_socket_utils.h" -using net::test::QuicTestWriter; - namespace net { namespace tools { namespace test { @@ -64,7 +62,7 @@ PacketDroppingTestWriter::PacketDroppingTestWriter() simple_random_.set_seed(seed); } -PacketDroppingTestWriter::~PacketDroppingTestWriter() { } +PacketDroppingTestWriter::~PacketDroppingTestWriter() {} void PacketDroppingTestWriter::SetConnectionHelper( QuicEpollConnectionHelper* helper) { @@ -76,7 +74,8 @@ void PacketDroppingTestWriter::SetConnectionHelper( } WriteResult PacketDroppingTestWriter::WritePacket( - const char* buffer, size_t buf_len, + const char* buffer, + size_t buf_len, const net::IPAddressNumber& self_address, const net::IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) { @@ -133,12 +132,8 @@ WriteResult PacketDroppingTestWriter::WritePacket( return WriteResult(WRITE_STATUS_OK, buf_len); } - return writer()->WritePacket(buffer, buf_len, self_address, peer_address, - blocked_writer); -} - -bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const { - return false; + return QuicPacketWriterWrapper::WritePacket( + buffer, buf_len, self_address, peer_address, blocked_writer); } QuicTime PacketDroppingTestWriter::ReleaseNextPacket() { @@ -160,8 +155,9 @@ QuicTime PacketDroppingTestWriter::ReleaseNextPacket() { DVLOG(1) << "Releasing packet. " << (delayed_packets_.size() - 1) << " remaining."; // Grab the next one off the queue and send it. - writer()->WritePacket(iter->buffer.data(), iter->buffer.length(), - iter->self_address, iter->peer_address, NULL); + QuicPacketWriterWrapper::WritePacket( + iter->buffer.data(), iter->buffer.length(), + iter->self_address, iter->peer_address, NULL); DCHECK_GE(cur_buffer_size_, iter->buffer.length()); cur_buffer_size_ -= iter->buffer.length(); delayed_packets_.erase(iter); diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h index 2a736e0..8ecaf1f 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h @@ -7,14 +7,14 @@ #include <list> +#include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" #include "net/quic/quic_alarm.h" #include "net/quic/quic_blocked_writer_interface.h" -#include "net/quic/quic_packet_writer.h" -#include "net/quic/test_tools/quic_test_writer.h" #include "net/tools/quic/quic_epoll_clock.h" +#include "net/tools/quic/quic_packet_writer_wrapper.h" #include "net/tools/quic/test_tools/quic_test_client.h" #include "net/tools/quic/test_tools/quic_test_utils.h" @@ -25,7 +25,7 @@ namespace test { // Simulates a connection that drops packets a configured percentage of the time // and has a blocked socket a configured percentage of the time. Also provides // the options to delay packets and reorder packets if delay is enabled. -class PacketDroppingTestWriter : public net::test::QuicTestWriter { +class PacketDroppingTestWriter : public QuicPacketWriterWrapper { public: PacketDroppingTestWriter(); @@ -35,13 +35,12 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter { // QuicPacketWriter methods: virtual WriteResult WritePacket( - const char* buffer, size_t buf_len, + const char* buffer, + size_t buf_len, const IPAddressNumber& self_address, const IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) OVERRIDE; - virtual bool IsWriteBlockedDataBuffered() const OVERRIDE; - // Writes out any packet which should have been sent by now // to the contained writer and returns the time // for the next delayed packet to be written. diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc index 03324a0..7303175 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc @@ -6,8 +6,7 @@ #include "net/quic/quic_default_packet_writer.h" #include "net/tools/quic/quic_dispatcher.h" - -using net::test::QuicTestWriter; +#include "net/tools/quic/quic_packet_writer_wrapper.h" namespace net { namespace tools { @@ -22,13 +21,14 @@ void QuicDispatcherPeer::SetTimeWaitListManager( // static void QuicDispatcherPeer::UseWriter(QuicDispatcher* dispatcher, - QuicTestWriter* writer) { - writer->set_writer(dispatcher->writer_.release()); - dispatcher->writer_.reset(writer); + QuicPacketWriterWrapper* writer) { + writer->set_writer(dispatcher->writer_->release_writer()); + dispatcher->writer_->set_writer(writer); } // static -QuicPacketWriter* QuicDispatcherPeer::GetWriter(QuicDispatcher* dispatcher) { +QuicPacketWriterWrapper* QuicDispatcherPeer::GetWriter( + QuicDispatcher* dispatcher) { return dispatcher->writer_.get(); } diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h index 249dcb3..a6b72e0 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.h +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h @@ -5,11 +5,13 @@ #ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_ #define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_ -#include "net/quic/test_tools/quic_test_writer.h" #include "net/tools/quic/quic_dispatcher.h" namespace net { namespace tools { + +class QuicPacketWriterWrapper; + namespace test { class QuicDispatcherPeer { @@ -18,10 +20,12 @@ class QuicDispatcherPeer { QuicDispatcher* dispatcher, QuicTimeWaitListManager* time_wait_list_manager); + // Injects |writer| into |dispatcher| beneath the top-level wrapper (to avoid + // messing up existing connections). static void UseWriter(QuicDispatcher* dispatcher, - net::test::QuicTestWriter* writer); + QuicPacketWriterWrapper* writer); - static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher); + static QuicPacketWriterWrapper* GetWriter(QuicDispatcher* dispatcher); static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher); }; diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 428acc0..aac75ab 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -13,6 +13,7 @@ #include "net/quic/test_tools/quic_connection_peer.h" #include "net/tools/balsa/balsa_headers.h" #include "net/tools/quic/quic_epoll_connection_helper.h" +#include "net/tools/quic/quic_packet_writer_wrapper.h" #include "net/tools/quic/quic_spdy_client_stream.h" #include "net/tools/quic/test_tools/http_message_test_utils.h" #include "net/tools/quic/test_tools/quic_client_peer.h" @@ -20,7 +21,6 @@ using base::StringPiece; using net::test::QuicConnectionPeer; -using net::test::QuicTestWriter; using std::string; using std::vector; @@ -96,33 +96,31 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers, } // A quic client which allows mocking out writes. -class QuicEpollClient : public QuicClient { +class MockableQuicClient : public QuicClient { public: - typedef QuicClient Super; - - QuicEpollClient(IPEndPoint server_address, - const string& server_hostname, - const QuicVersionVector& supported_versions) - : Super(server_address, server_hostname, supported_versions, false), - override_guid_(0), test_writer_(NULL) { - } - - QuicEpollClient(IPEndPoint server_address, - const string& server_hostname, - const QuicConfig& config, - const QuicVersionVector& supported_versions) - : Super(server_address, server_hostname, config, supported_versions), - override_guid_(0), test_writer_(NULL) { - } - - virtual ~QuicEpollClient() { + MockableQuicClient(IPEndPoint server_address, + const string& server_hostname, + const QuicVersionVector& supported_versions) + : QuicClient(server_address, server_hostname, supported_versions, false), + override_guid_(0), + test_writer_(NULL) {} + + MockableQuicClient(IPEndPoint server_address, + const string& server_hostname, + const QuicConfig& config, + const QuicVersionVector& supported_versions) + : QuicClient(server_address, server_hostname, config, supported_versions), + override_guid_(0), + test_writer_(NULL) {} + + virtual ~MockableQuicClient() { if (connected()) { Disconnect(); } } virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE { - QuicPacketWriter* writer = Super::CreateQuicPacketWriter(); + QuicPacketWriter* writer = QuicClient::CreateQuicPacketWriter(); if (!test_writer_) { return writer; } @@ -131,24 +129,22 @@ class QuicEpollClient : public QuicClient { } virtual QuicGuid GenerateGuid() OVERRIDE { - return override_guid_ ? override_guid_ : Super::GenerateGuid(); + return override_guid_ ? override_guid_ : QuicClient::GenerateGuid(); } // Takes ownership of writer. - void UseWriter(QuicTestWriter* writer) { test_writer_ = writer; } + void UseWriter(QuicPacketWriterWrapper* writer) { test_writer_ = writer; } - void UseGuid(QuicGuid guid) { - override_guid_ = guid; - } + void UseGuid(QuicGuid guid) { override_guid_ = guid; } private: QuicGuid override_guid_; // GUID to use, if nonzero - QuicTestWriter* test_writer_; + QuicPacketWriterWrapper* test_writer_; }; QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname, const QuicVersionVector& supported_versions) - : client_(new QuicEpollClient(address, hostname, supported_versions)) { + : client_(new MockableQuicClient(address, hostname, supported_versions)) { Initialize(address, hostname, true); } @@ -156,7 +152,7 @@ QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname, bool secure, const QuicVersionVector& supported_versions) - : client_(new QuicEpollClient(address, hostname, supported_versions)) { + : client_(new MockableQuicClient(address, hostname, supported_versions)) { Initialize(address, hostname, secure); } @@ -165,8 +161,8 @@ QuicTestClient::QuicTestClient(IPEndPoint address, bool secure, const QuicConfig& config, const QuicVersionVector& supported_versions) - : client_(new QuicEpollClient(address, hostname, config, - supported_versions)) { + : client_(new MockableQuicClient( + address, hostname, config, supported_versions)) { Initialize(address, hostname, secure); } @@ -237,6 +233,10 @@ ssize_t QuicTestClient::SendData(string data, bool last_data) { return data.length(); } +QuicPacketCreator::Options* QuicTestClient::options() { + return client_->options(); +} + string QuicTestClient::SendCustomSynchronousRequest( const HTTPMessage& message) { SendMessage(message); @@ -274,6 +274,12 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() { return stream_; } +QuicErrorCode QuicTestClient::connection_error() { + return client()->session()->error(); +} + +QuicClient* QuicTestClient::client() { return client_.get(); } + const string& QuicTestClient::cert_common_name() const { return reinterpret_cast<RecordingProofVerifier*>(proof_verifier_) ->common_name(); @@ -435,17 +441,17 @@ void QuicTestClient::OnClose(QuicDataStream* stream) { stream_ = NULL; } -void QuicTestClient::UseWriter(QuicTestWriter* writer) { - reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer); +void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) { + client_->UseWriter(writer); } void QuicTestClient::UseGuid(QuicGuid guid) { DCHECK(!connected()); - reinterpret_cast<QuicEpollClient*>(client_.get())->UseGuid(guid); + client_->UseGuid(guid); } void QuicTestClient::WaitForWriteToFlush() { - while (connected() && client()->session()->HasQueuedData()) { + while (connected() && client()->session()->HasDataToWrite()) { client_->WaitForEvents(); } } diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 9792f66..b750cbff 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -12,7 +12,6 @@ #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" #include "net/quic/quic_protocol.h" -#include "net/quic/test_tools/quic_test_writer.h" #include "net/tools/quic/quic_client.h" namespace net { @@ -21,9 +20,12 @@ class ProofVerifier; namespace tools { +class QuicPacketWriterWrapper; + namespace test { class HTTPMessage; +class MockableQuicClient; // A toy QUIC client used for testing. class QuicTestClient : public QuicDataStream::Visitor { @@ -58,7 +60,7 @@ class QuicTestClient : public QuicDataStream::Visitor { // Wraps data in a quic packet and sends it. ssize_t SendData(string data, bool last_data); - QuicPacketCreator::Options* options() { return client_->options(); } + QuicPacketCreator::Options* options(); void WaitForResponse(); @@ -86,7 +88,7 @@ class QuicTestClient : public QuicDataStream::Visitor { // Configures client_ to take ownership of and use the writer. // Must be called before initial connect. - void UseWriter(net::test::QuicTestWriter* writer); + void UseWriter(QuicPacketWriterWrapper* writer); // If the given GUID is nonzero, configures client_ to use a specific GUID // instead of a random one. void UseGuid(QuicGuid guid); @@ -95,9 +97,9 @@ class QuicTestClient : public QuicDataStream::Visitor { QuicSpdyClientStream* GetOrCreateStream(); QuicRstStreamErrorCode stream_error() { return stream_error_; } - QuicErrorCode connection_error() { return client()->session()->error(); } + QuicErrorCode connection_error(); - QuicClient* client() { return client_.get(); } + QuicClient* client(); // cert_common_name returns the common name value of the server's certificate, // or the empty string if no certificate was presented. @@ -120,7 +122,7 @@ class QuicTestClient : public QuicDataStream::Visitor { IPEndPoint server_address_; IPEndPoint client_address_; - scoped_ptr<QuicClient> client_; // The actual client + scoped_ptr<MockableQuicClient> client_; // The actual client QuicSpdyClientStream* stream_; QuicRstStreamErrorCode stream_error_; diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc index 2d013c3..9b82b9d 100644 --- a/net/tools/quic/test_tools/quic_test_utils.cc +++ b/net/tools/quic/test_tools/quic_test_utils.cc @@ -96,10 +96,10 @@ MockPacketWriter::MockPacketWriter() { MockPacketWriter::~MockPacketWriter() { } -MockQuicSessionOwner::MockQuicSessionOwner() { +MockQuicServerSessionVisitor::MockQuicServerSessionVisitor() { } -MockQuicSessionOwner::~MockQuicSessionOwner() { +MockQuicServerSessionVisitor::~MockQuicServerSessionVisitor() { } bool TestDecompressorVisitor::OnDecompressedData(StringPiece data) { diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h index a263747..af46b77 100644 --- a/net/tools/quic/test_tools/quic_test_utils.h +++ b/net/tools/quic/test_tools/quic_test_utils.h @@ -128,11 +128,12 @@ class MockPacketWriter : public QuicPacketWriter { MOCK_METHOD0(SetWritable, void()); }; -class MockQuicSessionOwner : public QuicSessionOwner { +class MockQuicServerSessionVisitor : public QuicServerSessionVisitor { public: - MockQuicSessionOwner(); - virtual ~MockQuicSessionOwner(); + MockQuicServerSessionVisitor(); + virtual ~MockQuicServerSessionVisitor(); MOCK_METHOD2(OnConnectionClosed, void(QuicGuid guid, QuicErrorCode error)); + MOCK_METHOD1(OnWriteBlocked, void(QuicBlockedWriterInterface* writer)); }; class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor { |