diff options
31 files changed, 422 insertions, 533 deletions
diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter.h b/net/quic/crypto/aes_128_gcm_12_encrypter.h index abea8ac2..a2d1dc9 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_encrypter.h @@ -36,9 +36,6 @@ class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public QuicEncrypter { Aes128Gcm12Encrypter(); virtual ~Aes128Gcm12Encrypter(); - // Returns true if the underlying crypto library supports AES GCM. - static bool IsSupported(); - // QuicEncrypter implementation virtual bool SetKey(base::StringPiece key) OVERRIDE; virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc index ae6adab..e100edee 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_nss.cc @@ -256,14 +256,6 @@ Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() { Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {} -// static -bool Aes128Gcm12Encrypter::IsSupported() { - // NSS 3.15 supports CKM_AES_GCM directly. - // NSS 3.14 supports CKM_AES_CTR, which can be used to emulate CKM_AES_GCM. - // Versions earlier than NSS 3.14 are not supported. - return NSS_VersionCheck("3.14") != PR_FALSE; -} - bool Aes128Gcm12Encrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc index 166fd55..cc9bf35 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_openssl.cc @@ -25,9 +25,6 @@ Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() {} Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {} -// static -bool Aes128Gcm12Encrypter::IsSupported() { return true; } - bool Aes128Gcm12Encrypter::SetKey(StringPiece key) { DCHECK_EQ(key.size(), sizeof(key_)); if (key.size() != sizeof(key_)) { diff --git a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc index 0c9928b..bb641d6 100644 --- a/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc +++ b/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc @@ -261,11 +261,6 @@ QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter, } TEST(Aes128Gcm12EncrypterTest, Encrypt) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - char key[1024]; size_t key_len; char iv[1024]; diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc index 3ad50bb..dcde964 100644 --- a/net/quic/crypto/crypto_handshake_test.cc +++ b/net/quic/crypto/crypto_handshake_test.cc @@ -155,11 +155,6 @@ TEST(QuicCryptoServerConfigTest, ServerConfig) { } TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand); IPAddressNumber ip; diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 7874273..8298ff2 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -108,20 +108,10 @@ class QuicClientSessionTest : public ::testing::Test { }; TEST_F(QuicClientSessionTest, CryptoConnect) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); } TEST_F(QuicClientSessionTest, MaxNumStreams) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); std::vector<QuicReliableClientStream*> streams; @@ -138,11 +128,6 @@ TEST_F(QuicClientSessionTest, MaxNumStreams) { } TEST_F(QuicClientSessionTest, MaxNumStreamsViaRequest) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); std::vector<QuicReliableClientStream*> streams; @@ -167,11 +152,6 @@ TEST_F(QuicClientSessionTest, MaxNumStreamsViaRequest) { } TEST_F(QuicClientSessionTest, GoAwayReceived) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); // After receiving a GoAway, I should no longer be able to create outgoing diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 914f8ae..28a7b0d 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -55,8 +55,7 @@ const QuicPacketSequenceNumber kMaxPacketGap = 5000; // initial congestion window(RFC 6928). const size_t kMaxRetransmissionsPerAck = 10; -// TCP retransmits after 2 nacks. We allow for a third in case of out-of-order -// delivery. +// TCP retransmits after 3 nacks. // TODO(ianswett): Change to match TCP's rule of retransmitting once an ack // at least 3 sequence numbers larger arrives. const size_t kNumberOfNacksBeforeRetransmission = 3; @@ -189,14 +188,6 @@ net::IsHandshake HasCryptoHandshake( } // namespace -// TODO(rch): Remove this. -// Because of a bug in the interaction between the TcpCubicSender and -// QuicConnection, acks currently count against the congestion window. -// This means that if acks are not acked, and data is only flowing in -// one direction, then the connection will deadlock. -// static -bool QuicConnection::g_acks_do_not_instigate_acks = true; - #define ENDPOINT (is_server_ ? "Server: " : " Client: ") QuicConnection::QuicConnection(QuicGuid guid, @@ -241,7 +232,6 @@ QuicConnection::QuicConnection(QuicGuid guid, is_server_(is_server), connected_(true), received_truncated_ack_(false), - send_ack_in_response_to_packet_(false), address_migrating_(false) { timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_)); framer_.set_visitor(this); @@ -718,10 +708,15 @@ void QuicConnection::OnPacketComplete() { bool send_ack_immediately = received_packet_manager_.GetNumMissingPackets() != 0; + // Ensure the visitor can process the stream frames before recording and + // processing the rest of the packet. if (last_stream_frames_.empty() || visitor_->OnStreamFrames(last_stream_frames_)) { received_packet_manager_.RecordPacketReceived( last_header_, time_of_last_received_packet_); + for (size_t i = 0; i < last_stream_frames_.size(); ++i) { + stats_.stream_bytes_received += last_stream_frames_[i].data.length(); + } } // Process stream resets, then acks, then congestion feedback. @@ -794,26 +789,17 @@ void QuicConnection::MaybeSendInResponseToPacket( // |include_ack| is false since we decide about ack bundling below. ScopedPacketBundler bundler(this, false); - if (send_ack_immediately) { - send_ack_in_response_to_packet_ = true; - } - - // TODO(rch): remove last_packet_should_instigate_ack when we remove - // g_acks_do_not_instigate_acks. - if (last_packet_should_instigate_ack || - !g_acks_do_not_instigate_acks) { - if (send_ack_in_response_to_packet_) { + if (last_packet_should_instigate_ack) { + // In general, we ack every second packet. When we don't ack the first + // packet, we set the delayed ack alarm. Thus, if the ack alarm is set + // then we know this is the second packet, and we should send an ack. + if (send_ack_immediately || ack_alarm_->IsSet()) { SendAck(); - DCHECK(!send_ack_in_response_to_packet_); + DCHECK(!ack_alarm_->IsSet()); } else { - send_ack_in_response_to_packet_ = true; - DVLOG(1) << "Next received packet will trigger ACK."; - if (last_packet_should_instigate_ack && !ack_alarm_->IsSet()) { - // Set the ack alarm for when any retransmittable frame is received. - ack_alarm_->Set(clock_->ApproximateNow().Add( - congestion_manager_.DelayedAckTime())); - DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK."; - } + ack_alarm_->Set(clock_->ApproximateNow().Add( + congestion_manager_.DelayedAckTime())); + DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK."; } } @@ -907,6 +893,7 @@ QuicConsumedData QuicConnection::SendvStreamDataInner( fin_consumed = consumed_data.fin_consumed; } + stats_.stream_bytes_sent += bytes_written; return QuicConsumedData(bytes_written, fin_consumed); } @@ -1237,8 +1224,6 @@ void QuicConnection::SetupRetransmission( sent_packet_manager_.GetNumUnackedPackets(), consecutive_rto_count_); retransmission_alarm_->Set( clock_->ApproximateNow().Add(retransmission_delay)); - // TODO(satyamshekhar): restore packet reordering with Ian's TODO in - // SendStreamData(). } void QuicConnection::SetupAbandonFecTimer( @@ -1525,7 +1510,6 @@ void QuicConnection::UpdateSentPacketInfo(SentPacketInfo* sent_info) { void QuicConnection::SendAck() { ack_alarm_->Cancel(); - send_ack_in_response_to_packet_ = false; // TODO(rch): delay this until the CreateFeedbackFrame // method is invoked. This requires changes SetShouldSendAck // to be a no-arg method, and re-jiggering its implementation. @@ -1555,6 +1539,8 @@ void QuicConnection::OnRetransmissionTimeout() { // packets will be queued for future sending. SequenceNumberSet unacked_packets = sent_packet_manager_.GetUnackedPackets(); + DLOG(INFO) << "OnRetransmissionTimeout() fired with " + << unacked_packets.size() << " unacked packets."; // Abandon all unacked packets to ensure the congestion window // opens up before we attempt to retransmit the packet. @@ -1882,9 +1868,7 @@ QuicConnection::ScopedPacketBundler::ScopedPacketBundler( if (FLAGS_bundle_ack_with_outgoing_packet && include_ack && connection_->ack_alarm_->IsSet()) { DVLOG(1) << "Bundling ack with outgoing packet."; - DCHECK(connection_->send_ack_in_response_to_packet_); connection_->SendAck(); - DCHECK(!connection_->send_ack_in_response_to_packet_); } } diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 92f9f88..583962c 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -401,8 +401,6 @@ class NET_EXPORT_PRIVATE QuicConnection bool is_server() const { return is_server_; } - static bool g_acks_do_not_instigate_acks; - protected: // Send a packet to the peer using encryption |level|. If |sequence_number| // is present in the |retransmission_map_|, then contents of this packet will @@ -772,7 +770,6 @@ class NET_EXPORT_PRIVATE QuicConnection // True if the last ack received from the peer may have been truncated. False // otherwise. bool received_truncated_ack_; - bool send_ack_in_response_to_packet_; // Set to true if the udp packet headers have a new self or peer address. // This is checked later on validating a data or version negotiation packet. diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc index f66a5cb..500b5f3 100644 --- a/net/quic/quic_connection_stats.cc +++ b/net/quic/quic_connection_stats.cc @@ -4,13 +4,17 @@ #include "net/quic/quic_connection_stats.h" +using std::ostream; + namespace net { QuicConnectionStats::QuicConnectionStats() : bytes_sent(0), packets_sent(0), + stream_bytes_sent(0), bytes_received(0), packets_received(0), + stream_bytes_received(0), bytes_retransmitted(0), packets_retransmitted(0), packets_revived(0), @@ -22,4 +26,22 @@ QuicConnectionStats::QuicConnectionStats() QuicConnectionStats::~QuicConnectionStats() {} +ostream& operator<<(ostream& os, const QuicConnectionStats& s) { + os << "{ bytes sent: " << s.bytes_sent + << ", packets sent:" << s.packets_sent + << ", stream bytes sent: " << s.stream_bytes_sent + << ", bytes received: " << s.bytes_received + << ", packets received: " << s.packets_received + << ", stream bytes received: " << s.stream_bytes_received + << ", bytes retransmitted: " << s.bytes_retransmitted + << ", packets retransmitted: " << s.packets_retransmitted + << ", packets revived: " << s.packets_revived + << ", packets dropped:" << s.packets_dropped + << ", rto count: " << s.rto_count + << ", rtt(us): " << s.rtt + << ", estimated_bandwidth: " << s.estimated_bandwidth + << "}\n"; + return os; +} + } // namespace net diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h index f933662..b0761d9 100644 --- a/net/quic/quic_connection_stats.h +++ b/net/quic/quic_connection_stats.h @@ -5,6 +5,8 @@ #ifndef NET_QUIC_QUIC_CONNECTION_STATS_H_ #define NET_QUIC_QUIC_CONNECTION_STATS_H_ +#include <ostream> + #include "base/basictypes.h" #include "net/base/net_export.h" @@ -15,23 +17,26 @@ namespace net { // 3. CHLO sent to SHLO received time. // 4. Number of migrations. // 5. Number of out of order packets. -// 6. Avg packet size. -// 7. Number of connections that require more that 1-RTT. -// 8. Avg number of streams / session. -// 9. Number of duplicates received. -// 10. Fraction of traffic sent/received that was not data (protocol overhead). -// 11. Fraction of data transferred that was padding. +// 6. Number of connections that require more that 1-RTT. +// 7. Avg number of streams / session. +// 8. Number of duplicates received. +// 9. Fraction of data transferred that was padding. // Structure to hold stats for a QuicConnection. struct NET_EXPORT_PRIVATE QuicConnectionStats { QuicConnectionStats(); ~QuicConnectionStats(); + NET_EXPORT_PRIVATE friend std::ostream& operator<<( + std::ostream& os, const QuicConnectionStats& s); + uint64 bytes_sent; // includes retransmissions, fec. uint32 packets_sent; + uint64 stream_bytes_sent; // non-retransmitted bytes sent in a stream frame. uint64 bytes_received; // includes duplicate data for a stream, fec. uint32 packets_received; // includes dropped packets + uint64 stream_bytes_received; // bytes received in a stream frame. uint64 bytes_retransmitted; uint32 packets_retransmitted; @@ -40,7 +45,7 @@ struct NET_EXPORT_PRIVATE QuicConnectionStats { uint32 packets_dropped; // duplicate or less than least unacked. uint32 rto_count; - uint32 rtt; + uint32 rtt; // In microseconds uint64 estimated_bandwidth; // TODO(satyamshekhar): Add window_size, mss and mtu. }; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 37a8e9b..c5e33e2 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -526,7 +526,6 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> { frame2_(1, false, 3, data2), accept_packet_(true) { // TODO(rtenneti): remove g_* flags. - QuicConnection::g_acks_do_not_instigate_acks = true; FLAGS_track_retransmission_history = true; connection_.set_visitor(&visitor_); connection_.SetSendAlgorithm(send_algorithm_); @@ -552,11 +551,6 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> { Return(true)); } - ~QuicConnectionTest() { - // TODO(rch): remove this. - QuicConnection::g_acks_do_not_instigate_acks = false; - } - void SetUp() { FLAGS_bundle_ack_with_outgoing_packet = GetParam(); } @@ -701,8 +695,10 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> { return encrypted->length(); } - QuicByteCount SendStreamDataToPeer(QuicStreamId id, StringPiece data, - QuicStreamOffset offset, bool fin, + QuicByteCount SendStreamDataToPeer(QuicStreamId id, + StringPiece data, + QuicStreamOffset offset, + bool fin, QuicPacketSequenceNumber* last_packet) { QuicByteCount packet_size; EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) @@ -1488,6 +1484,45 @@ TEST_P(QuicConnectionTest, FramePackingFEC) { EXPECT_EQ(0u, writer_->frame_count()); } +TEST_P(QuicConnectionTest, FramePackingAckResponse) { + if (!GetParam()) { + // This test depends on BundleAckWithPacket being true. + return; + } + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + + // Process a data packet to queue up a pending ack. + EXPECT_CALL(visitor_, OnStreamFrames(_)).WillOnce(Return(true)); + ProcessDataPacket(1, 1, kEntropyFlag); + + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll( + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData3)), + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData5)), + Return(true))); + + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + .Times(1); + + // Process an ack to cause the visitor's OnCanWrite to be invoked. + creator_.set_sequence_number(2); + QuicAckFrame ack_one(0, QuicTime::Zero(), 0); + ProcessAckPacket(&ack_one); + + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + EXPECT_FALSE(connection_.HasQueuedData()); + + // Parse the last packet and ensure it's an ack and two stream frames from + // two different streams. + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_TRUE(writer_->ack()); + ASSERT_EQ(2u, writer_->stream_frames()->size()); + EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id); + EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id); +} + TEST_P(QuicConnectionTest, FramePackingSendv) { // Send two stream frames in 1 packet by using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); @@ -1724,18 +1759,6 @@ TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { connection_.OnCanWrite(); } -TEST_P(QuicConnectionTest, ResumptionAlarmThenWriteBlocked) { - // Set the send and resumption alarm, then block the connection. - 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_)); -} - TEST_P(QuicConnectionTest, WriteBlockedThenSent) { writer_->set_blocked(true); @@ -1748,6 +1771,18 @@ TEST_P(QuicConnectionTest, WriteBlockedThenSent) { EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } +TEST_P(QuicConnectionTest, ResumptionAlarmThenWriteBlocked) { + // Set the send and resumption alarm, then block the connection. + 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_)); +} + TEST_P(QuicConnectionTest, LimitPacketsPerNack) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1); diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 2ad9a3a2..e07ad46 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -53,32 +53,17 @@ class QuicCryptoClientStreamTest : public ::testing::Test { }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - EXPECT_FALSE(stream_->encryption_established()); EXPECT_FALSE(stream_->handshake_confirmed()); } TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); EXPECT_TRUE(stream_->encryption_established()); EXPECT_TRUE(stream_->handshake_confirmed()); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); EXPECT_CALL(*connection_, SendConnectionClose( @@ -89,11 +74,6 @@ TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoClientStreamTest, BadMessageType) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - EXPECT_TRUE(stream_->CryptoConnect()); message_.set_tag(kCHLO); @@ -105,11 +85,6 @@ TEST_F(QuicCryptoClientStreamTest, BadMessageType) { } TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); const QuicConfig* config = session_->config(); @@ -127,11 +102,6 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { } TEST_F(QuicCryptoClientStreamTest, InvalidHostname) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - stream_.reset(new QuicCryptoClientStream("invalid", session_.get(), &crypto_config_)); session_->SetCryptoStream(stream_.get()); diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 9e92b2b..bfea221 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -86,21 +86,11 @@ class QuicCryptoServerStreamTest : public ::testing::Test { }; TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - EXPECT_FALSE(stream_.encryption_established()); EXPECT_FALSE(stream_.handshake_confirmed()); } TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - // CompleteCryptoHandshake returns the number of client hellos sent. This // test should send: // * One to get a source-address token and certificates. @@ -111,11 +101,6 @@ TEST_F(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { } TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - QuicGuid guid(1); IPAddressNumber ip; ParseIPLiteralToNumber("127.0.0.1", &ip); @@ -184,11 +169,6 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { } TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); EXPECT_CALL(*connection_, SendConnectionClose( QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); @@ -198,11 +178,6 @@ TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { } TEST_F(QuicCryptoServerStreamTest, BadMessageType) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - message_.set_tag(kSHLO); ConstructHandshakeMessage(); EXPECT_CALL(*connection_, SendConnectionClose( @@ -211,11 +186,6 @@ TEST_F(QuicCryptoServerStreamTest, BadMessageType) { } TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - crypto_config_.SetProofSource(NULL); client_options_.dont_verify_certs = true; @@ -227,11 +197,6 @@ TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) { } TEST_F(QuicCryptoServerStreamTest, ChannelID) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - client_options_.channel_id_enabled = true; // TODO(rtenneti): Enable testing of ProofVerifier. // CompleteCryptoHandshake verifies diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 24bde81..02ca896 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -72,16 +72,6 @@ const uint8 kQuicFrameTypeStreamMask = 0x80; const uint8 kQuicFrameTypeAckMask = 0x40; const uint8 kQuicFrameTypeCongestionFeedbackMask = 0x20; -// Mask to determine if it's a special frame type(Stream, Ack, or -// Congestion Control) by checking if the first bit is 0, then shifting right. -// TODO(jri): Remove kQuicFrameType0BitMask constant from v. 10 onwards. -// Replaced by kQuicFrameTypeStream defined above. -const uint8 kQuicFrameType0BitMask = 0x01; - -// Default frame type shift and mask. -const uint8 kQuicDefaultFrameTypeShift = 3; -const uint8 kQuicDefaultFrameTypeMask = 0x07; - // Stream frame relative shifts and masks for interpreting the stream flags. // StreamID may be 1, 2, 3, or 4 bytes. const uint8 kQuicStreamIdShift = 2; @@ -936,11 +926,9 @@ bool QuicFramer::ProcessFrameData() { return RaiseError(QUIC_INVALID_FRAME_DATA); } - // TODO(jri): Remove this entire if block when support for - // QUIC version < 10 removed. - if (version() < QUIC_VERSION_10) { - // Special frame type processing for QUIC version < 10. - if ((frame_type & kQuicFrameType0BitMask) == 0) { + if (frame_type & kQuicFrameTypeSpecialMask) { + // Stream Frame + if (frame_type & kQuicFrameTypeStreamMask) { QuicStreamFrame frame; if (!ProcessStreamFrame(frame_type, &frame)) { return RaiseError(QUIC_INVALID_STREAM_DATA); @@ -953,8 +941,8 @@ bool QuicFramer::ProcessFrameData() { continue; } - frame_type >>= 1; - if ((frame_type & kQuicFrameType0BitMask) == 0) { + // Ack Frame + if (frame_type & kQuicFrameTypeAckMask) { QuicAckFrame frame; if (!ProcessAckFrame(&frame)) { return RaiseError(QUIC_INVALID_ACK_DATA); @@ -967,8 +955,8 @@ bool QuicFramer::ProcessFrameData() { continue; } - frame_type >>= 1; - if ((frame_type & kQuicFrameType0BitMask) == 0) { + // Congestion Feedback Frame + if (frame_type & kQuicFrameTypeCongestionFeedbackMask) { QuicCongestionFeedbackFrame frame; if (!ProcessQuicCongestionFeedbackFrame(&frame)) { return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA); @@ -981,178 +969,70 @@ bool QuicFramer::ProcessFrameData() { continue; } - frame_type >>= 1; - switch (frame_type) { - // STREAM_FRAME, ACK_FRAME, and CONGESTION_FEEDBACK_FRAME are handled - // above. - case PADDING_FRAME_OLD: - // We're done with the packet. - return true; - - case RST_STREAM_FRAME_OLD: { - QuicRstStreamFrame frame; - if (!ProcessRstStreamFrame(&frame)) { - return RaiseError(QUIC_INVALID_RST_STREAM_DATA); - } - if (!visitor_->OnRstStreamFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; - } - - case CONNECTION_CLOSE_FRAME_OLD: { - QuicConnectionCloseFrame frame; - if (!ProcessConnectionCloseFrame(&frame)) { - return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); - } + // This was a special frame type that did not match any + // of the known ones. Error. + set_detailed_error("Illegal frame type."); + DLOG(WARNING) << "Illegal frame type: " + << static_cast<int>(frame_type); + return RaiseError(QUIC_INVALID_FRAME_DATA); + } - if (!visitor_->OnAckFrame(frame.ack_frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } + switch (frame_type) { + case PADDING_FRAME: + // We're done with the packet. + return true; - if (!visitor_->OnConnectionCloseFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + case RST_STREAM_FRAME: { + QuicRstStreamFrame frame; + if (!ProcessRstStreamFrame(&frame)) { + return RaiseError(QUIC_INVALID_RST_STREAM_DATA); } - - case GOAWAY_FRAME_OLD: { - QuicGoAwayFrame goaway_frame; - if (!ProcessGoAwayFrame(&goaway_frame)) { - return RaiseError(QUIC_INVALID_GOAWAY_DATA); - } - if (!visitor_->OnGoAwayFrame(goaway_frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + if (!visitor_->OnRstStreamFrame(frame)) { + DLOG(INFO) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; } - - set_detailed_error("Illegal frame type."); - DLOG(WARNING) << "Illegal frame type: " - << static_cast<int>(frame_type); - return RaiseError(QUIC_INVALID_FRAME_DATA); + continue; } - } else { - // TODO(jri): Retain this else block when support for - // QUIC version < 10 removed. Remove above if block. - - // Special frame type processing for QUIC version >= 10. - if (frame_type & kQuicFrameTypeSpecialMask) { - // Stream Frame - if (frame_type & kQuicFrameTypeStreamMask) { - QuicStreamFrame frame; - if (!ProcessStreamFrame(frame_type, &frame)) { - return RaiseError(QUIC_INVALID_STREAM_DATA); - } - if (!visitor_->OnStreamFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; - } - // Ack Frame - if (frame_type & kQuicFrameTypeAckMask) { - QuicAckFrame frame; - if (!ProcessAckFrame(&frame)) { - return RaiseError(QUIC_INVALID_ACK_DATA); - } - if (!visitor_->OnAckFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + case CONNECTION_CLOSE_FRAME: { + QuicConnectionCloseFrame frame; + if (!ProcessConnectionCloseFrame(&frame)) { + return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); } - // Congestion Feedback Frame - if (frame_type & kQuicFrameTypeCongestionFeedbackMask) { - QuicCongestionFeedbackFrame frame; - if (!ProcessQuicCongestionFeedbackFrame(&frame)) { - return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA); - } - if (!visitor_->OnCongestionFeedbackFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + if (!visitor_->OnAckFrame(frame.ack_frame)) { + DLOG(INFO) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; } - // This was a special frame type that did not match any - // of the known ones. Error. - set_detailed_error("Illegal frame type."); - DLOG(WARNING) << "Illegal frame type: " - << static_cast<int>(frame_type); - return RaiseError(QUIC_INVALID_FRAME_DATA); - } - - switch (frame_type) { - case PADDING_FRAME: - // We're done with the packet. + if (!visitor_->OnConnectionCloseFrame(frame)) { + DLOG(INFO) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. return true; - - case RST_STREAM_FRAME: { - QuicRstStreamFrame frame; - if (!ProcessRstStreamFrame(&frame)) { - return RaiseError(QUIC_INVALID_RST_STREAM_DATA); - } - if (!visitor_->OnRstStreamFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; } + continue; + } - case CONNECTION_CLOSE_FRAME: { - QuicConnectionCloseFrame frame; - if (!ProcessConnectionCloseFrame(&frame)) { - return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); - } - - if (!visitor_->OnAckFrame(frame.ack_frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - - if (!visitor_->OnConnectionCloseFrame(frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + case GOAWAY_FRAME: { + QuicGoAwayFrame goaway_frame; + if (!ProcessGoAwayFrame(&goaway_frame)) { + return RaiseError(QUIC_INVALID_GOAWAY_DATA); } - - case GOAWAY_FRAME: { - QuicGoAwayFrame goaway_frame; - if (!ProcessGoAwayFrame(&goaway_frame)) { - return RaiseError(QUIC_INVALID_GOAWAY_DATA); - } - if (!visitor_->OnGoAwayFrame(goaway_frame)) { - DLOG(INFO) << "Visitor asked to stop further processing."; - // Returning true since there was no parsing error. - return true; - } - continue; + if (!visitor_->OnGoAwayFrame(goaway_frame)) { + DLOG(INFO) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; } - - default: - set_detailed_error("Illegal frame type."); - DLOG(WARNING) << "Illegal frame type: " - << static_cast<int>(frame_type); - return RaiseError(QUIC_INVALID_FRAME_DATA); + continue; } + + default: + set_detailed_error("Illegal frame type."); + DLOG(WARNING) << "Illegal frame type: " + << static_cast<int>(frame_type); + return RaiseError(QUIC_INVALID_FRAME_DATA); } } @@ -1163,12 +1043,7 @@ bool QuicFramer::ProcessStreamFrame(uint8 frame_type, QuicStreamFrame* frame) { uint8 stream_flags = frame_type; - // TODO(jri): Remove if block after support for ver. < 10 removed. - if (version() < QUIC_VERSION_10) { - stream_flags >>= 1; - } else { - stream_flags &= ~kQuicFrameTypeStreamMask; - } + stream_flags &= ~kQuicFrameTypeStreamMask; // Read from right to left: StreamID, Offset, Data Length, Fin. const uint8 stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1; @@ -1716,45 +1591,21 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, // stream id 2 bits. type_byte <<= kQuicStreamIdShift; type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1; - - // TODO(jri): Remove if block when support for QUIC ver. < 10 removed. - if (version() < QUIC_VERSION_10) { - type_byte <<= 1; // Leaves the last bit as a 0. - } else { - type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1. - } + type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1. break; } case ACK_FRAME: { // TODO(ianswett): Use extra 5 bits in the ack framing. - // TODO(jri): Remove if block when support for QUIC ver. < 10 removed. - if (version() < QUIC_VERSION_10) { - type_byte = 0x01; - } else { - type_byte = kQuicFrameTypeAckMask; - } + type_byte = kQuicFrameTypeAckMask; break; } case CONGESTION_FEEDBACK_FRAME: { // TODO(ianswett): Use extra 5 bits in the congestion feedback framing. - // TODO(jri): Remove if block when support for QUIC ver. < 10 removed. - if (version() < QUIC_VERSION_10) { - type_byte = 0x03; - } else { - type_byte = kQuicFrameTypeCongestionFeedbackMask; - } + type_byte = kQuicFrameTypeCongestionFeedbackMask; break; } default: type_byte = frame.type; - // TODO(jri): Remove if block when support for QUIC ver. < 10 removed. - if (version() < QUIC_VERSION_10) { - if (type_byte > 0) { - type_byte += 3; - } - type_byte = (type_byte << kQuicDefaultFrameTypeShift) | - kQuicDefaultFrameTypeMask; - } break; } diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index a0352de..f679b81 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -1038,8 +1038,7 @@ TEST_P(QuicFramerTest, InvalidPublicFlag) { 0x00, // frame type (padding) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; CheckProcessingFails(packet, @@ -1064,8 +1063,7 @@ TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) { 0x00, // frame type (padding) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; CheckProcessingFails(packet, @@ -1090,8 +1088,7 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); @@ -1116,8 +1113,7 @@ TEST_P(QuicFramerTest, InvalidPrivateFlag) { 0x10, // frame type (padding) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; CheckProcessingFails(packet, @@ -1162,12 +1158,10 @@ TEST_P(QuicFramerTest, PaddingFrame) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, // Ignored data (which in this case is a stream frame) // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1211,8 +1205,7 @@ TEST_P(QuicFramerTest, StreamFrame) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1260,8 +1253,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFC : 0xFE), + 0xFE, // stream id 0x04, 0x03, 0x02, // offset @@ -1310,8 +1302,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFA : 0xFD), + 0xFD, // stream id 0x04, 0x03, // offset @@ -1360,8 +1351,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xF8 : 0xFC), + 0xFC, // stream id 0x04, // offset @@ -1412,8 +1402,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1465,8 +1454,7 @@ TEST_P(QuicFramerTest, RejectPacket) { 0x00, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1494,8 +1482,7 @@ TEST_P(QuicFramerTest, RejectPacket) { TEST_P(QuicFramerTest, RevivedStreamFrame) { unsigned char payload[] = { // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1564,8 +1551,7 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) { 0x02, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -1617,8 +1603,7 @@ TEST_P(QuicFramerTest, AckFrame) { 0x00, // frame type (ack frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40), + 0x40, // entropy hash of sent packets till least awaiting - 1. 0xAB, // least packet sequence number awaiting an ack @@ -1711,8 +1696,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (tcp) 0x00, // ack_frame.feedback.tcp.accumulated_number_of_lost_packets @@ -1769,8 +1753,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameInterArrival) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (inter arrival) 0x01, // accumulated_number_of_lost_packets @@ -1866,8 +1849,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameFixRate) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (fix rate) 0x02, // bitrate_in_bytes_per_second; @@ -1919,8 +1901,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (invalid) 0x03, }; @@ -1945,8 +1926,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) { 0x00, // frame type (rst stream frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x27 : 0x01), + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // error code @@ -2005,8 +1985,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { 0x00, // frame type (connection close frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02), + 0x02, // error code 0x11, 0x00, 0x00, 0x00, @@ -2093,8 +2072,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) { 0x00, // frame type (go away frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x37 : 0x03), + 0x03, // error code 0x09, 0x00, 0x00, 0x00, // stream id @@ -2294,8 +2272,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -2341,8 +2318,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -2388,8 +2364,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -2435,8 +2410,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { 0x00, // frame type (padding frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x07 : 0x00), + 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -2486,8 +2460,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { 0x01, // frame type (stream frame with fin and no length) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF), + 0xDF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -2542,8 +2515,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { 0x01, // frame type (stream frame with fin and no length) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF), + 0xDF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -2626,8 +2598,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) { 0x01, // frame type (ack frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40), + 0x40, // entropy hash of sent packets till least awaiting - 1. 0x14, // least packet sequence number awaiting an ack @@ -2687,8 +2658,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCP) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (TCP) 0x00, // accumulated number of lost packets @@ -2747,8 +2717,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInterArrival) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (inter arrival) 0x01, // accumulated_number_of_lost_packets @@ -2811,8 +2780,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketFixRate) { 0x00, // frame type (congestion feedback frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x03 : 0x20), + 0x20, // congestion feedback type (fix rate) 0x02, // bitrate_in_bytes_per_second; @@ -2878,8 +2846,7 @@ TEST_P(QuicFramerTest, BuildRstFramePacket) { 0x00, // frame type (rst stream frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x27 : 0x01), + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // error code @@ -2942,8 +2909,7 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { 0x01, // frame type (connection close frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02), + 0x02, // error code 0x08, 0x07, 0x06, 0x05, // error details length @@ -3014,8 +2980,7 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { 0x01, // frame type (go away frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x37 : 0x03), + 0x03, // error code 0x08, 0x07, 0x06, 0x05, // stream id @@ -3356,8 +3321,7 @@ TEST_P(QuicFramerTest, EntropyFlagTest) { 0x01, // frame type (stream frame with fin and no length) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF), + 0xDF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -3394,8 +3358,7 @@ TEST_P(QuicFramerTest, FecEntropyTest) { 0xFF, // frame type (stream frame with fin and no length) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xBE : 0xDF), + 0xDF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -3430,8 +3393,7 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { 0x01, // frame type (stream frame with fin) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0xFE : 0xFF), + 0xFF, // stream id 0x04, 0x03, 0x02, 0x01, // offset @@ -3445,8 +3407,7 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { 'r', 'l', 'd', '!', // frame type (ack frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x01 : 0x40), + 0x40, // entropy hash of sent packets till least awaiting - 1. 0x14, // least packet sequence number awaiting an ack @@ -3491,8 +3452,7 @@ TEST_P(QuicFramerTest, ConnectionCloseWithInvalidAck) { 0x00, // frame type (connection close frame) - static_cast<unsigned char>( - GetParam() < QUIC_VERSION_10 ? 0x2F : 0x02), + 0x02, // error code 0x11, 0x00, 0x00, 0x00, // error details length diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index b7c0522..5995c44 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -140,8 +140,6 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); peer_addr_ = IPEndPoint(ip, 443); self_addr_ = IPEndPoint(ip, 8435); - // TODO(rch): remove this. - QuicConnection::g_acks_do_not_instigate_acks = true; } ~QuicHttpStreamTest() { @@ -149,8 +147,6 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { for (size_t i = 0; i < writes_.size(); i++) { delete writes_[i].packet; } - // TODO(rch): remove this. - QuicConnection::g_acks_do_not_instigate_acks = false; } // Adds a packet to the list of expected writes. diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 526cb68..efd0139 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -178,11 +178,8 @@ class QuicNetworkTransactionTest : public PlatformTest { std::string SerializeHeaderBlock(const SpdyHeaderBlock& headers) { QuicSpdyCompressor compressor; - if (QuicVersionMax() >= QUIC_VERSION_9) { - return compressor.CompressHeadersWithPriority( - ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers); - } - return compressor.CompressHeaders(headers); + return compressor.CompressHeadersWithPriority( + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), headers); } // Returns a newly created packet to send kData on stream 1. diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 72843ef..c586d29 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -121,8 +121,6 @@ QuicVersion QuicVersionMin() { QuicTag QuicVersionToQuicTag(const QuicVersion version) { switch (version) { - case QUIC_VERSION_9: - return MakeQuicTag('Q', '0', '0', '9'); case QUIC_VERSION_10: return MakeQuicTag('Q', '0', '1', '0'); case QUIC_VERSION_11: @@ -153,7 +151,6 @@ return #x string QuicVersionToString(const QuicVersion version) { switch (version) { - RETURN_STRING_LITERAL(QUIC_VERSION_9); RETURN_STRING_LITERAL(QUIC_VERSION_10); RETURN_STRING_LITERAL(QUIC_VERSION_11); default: diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 8b3c1e9..c2ccc07 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -190,7 +190,6 @@ enum QuicVersion { // Special case to indicate unknown/unsupported QUIC version. QUIC_VERSION_UNSUPPORTED = 0, - QUIC_VERSION_9 = 9, QUIC_VERSION_10 = 10, QUIC_VERSION_11 = 11, // Current version. }; @@ -200,7 +199,7 @@ enum QuicVersion { // element, with subsequent elements in descending order (versions can be // skipped as necessary). static const QuicVersion kSupportedQuicVersions[] = - {QUIC_VERSION_10, QUIC_VERSION_9}; + {QUIC_VERSION_10}; typedef std::vector<QuicVersion> QuicVersionVector; @@ -220,10 +219,6 @@ NET_EXPORT_PRIVATE QuicTag QuicVersionToQuicTag(const QuicVersion version); // Returns QUIC_VERSION_UNSUPPORTED if version_tag cannot be understood. NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag); -// Returns the appropriate QuicTag for a properly formed version string -// (e.g. Q010). -NET_EXPORT_PRIVATE QuicTag StringToQuicTag(std::string version); - // Helper function which translates from a QuicVersion to a string. // Returns strings corresponding to enum names (e.g. QUIC_VERSION_6). NET_EXPORT_PRIVATE std::string QuicVersionToString(const QuicVersion version); diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc index 0b96e4d..0dcfcc6 100644 --- a/net/quic/quic_protocol_test.cc +++ b/net/quic/quic_protocol_test.cc @@ -135,8 +135,8 @@ TEST(QuicProtocolTest, QuicVersionToString) { EXPECT_EQ("QUIC_VERSION_10,", QuicVersionArrayToString(single_version, arraysize(single_version))); - QuicVersion multiple_versions[] = {QUIC_VERSION_10, QUIC_VERSION_9}; - EXPECT_EQ("QUIC_VERSION_10,QUIC_VERSION_9,", + QuicVersion multiple_versions[] = {QUIC_VERSION_11, QUIC_VERSION_10}; + EXPECT_EQ("QUIC_VERSION_11,QUIC_VERSION_10,", QuicVersionArrayToString(multiple_versions, arraysize(multiple_versions))); diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index f29989a..96ea50b 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -74,7 +74,6 @@ class EndToEndTest : public ::testing::TestWithParam<QuicVersion> { net::IPAddressNumber ip; CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip)); server_address_ = IPEndPoint(ip, 0); - QuicConnection::g_acks_do_not_instigate_acks = true; FLAGS_track_retransmission_history = true; client_config_.SetDefaults(); server_config_.SetDefaults(); @@ -166,6 +165,23 @@ class EndToEndTest : public ::testing::TestWithParam<QuicVersion> { // server_writer_->set_fake_packet_loss_percentage(loss); } + void SetRTT(QuicTime::Delta rtt) { + // TODO(ianswett): For now, the RTT is entirely simulated on the client + // side, because the server's writer does not have a ConnectionHelper. + // TODO(rtenneti): enable when we can do random packet loss tests in + // chrome's tree. + // client_writer_->set_fake_packet_delay(rtt); + } + + void SetReorderPercentage(int32 reorder) { + // TODO(ianswett): For now, the reordering is entirely simulated on the + // client side, because the server's writer does not have a + // ConnectionHelper. + // TODO(rtenneti): enable when we can do random packet loss tests in + // chrome's tree. + // client_writer_->set_fake_reorder_percentage(reorder); + } + IPEndPoint server_address_; string server_hostname_; scoped_ptr<ServerThread> server_thread_; @@ -373,6 +389,24 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) { EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); } +TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) { + ASSERT_TRUE(Initialize()); + SetRTT(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + client_->client()->WaitForCryptoHandshakeConfirmed(); + + // 1 Mb body. + string body; + GenerateBody(&body, 1024 * 1024); + + HTTPMessage request(HttpConstants::HTTP_1_1, + HttpConstants::POST, "/foo"); + request.AddBody(body, true); + + EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); +} + TEST_P(EndToEndTest, LargePostWithPacketLossAndBlocketSocket) { // Connect with lower fake packet loss than we'd like to test. Until // b/10126687 is fixed, losing handshake packets is pretty brutal. diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index 6cef711..a01e3c7 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc @@ -153,14 +153,13 @@ bool QuicClient::Connect() { bool QuicClient::StartConnect() { DCHECK(!connected() && initialized_); - QuicGuid guid = QuicRandom::GetInstance()->RandUint64(); if (!writer_.get()) { writer_.reset(CreateQuicPacketWriter()); } session_.reset(new QuicClientSession( server_hostname_, config_, - new QuicConnection(guid, server_address_, + new QuicConnection(GenerateGuid(), server_address_, CreateQuicConnectionHelper(), writer_.get(), false, version_), &crypto_config_)); @@ -271,6 +270,10 @@ bool QuicClient::connected() const { session_->connection()->connected(); } +QuicGuid QuicClient::GenerateGuid() { + return QuicRandom::GetInstance()->RandUint64(); +} + QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() { return new QuicEpollConnectionHelper(&epoll_server_); } diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index b4b8ceb..5637736 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h @@ -144,6 +144,7 @@ class QuicClient : public EpollCallbackInterface, } protected: + virtual QuicGuid GenerateGuid(); virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper(); virtual QuicPacketWriter* CreateQuicPacketWriter(); diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index 1b1ece6..d5b63a8 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc @@ -48,19 +48,11 @@ class ToolsQuicClientSessionTest : public ::testing::Test { }; TEST_F(ToolsQuicClientSessionTest, CryptoConnect) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } CompleteCryptoHandshake(); } TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) { session_->config()->set_max_streams_per_connection(1, 1); - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } // FLAGS_max_streams_per_connection = 1; // Initialize crypto before the client session will create a stream. CompleteCryptoHandshake(); @@ -77,11 +69,6 @@ TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) { } TEST_F(ToolsQuicClientSessionTest, GoAwayReceived) { - if (!Aes128Gcm12Encrypter::IsSupported()) { - LOG(INFO) << "AES GCM not supported. Test skipped."; - return; - } - CompleteCryptoHandshake(); // After receiving a GoAway, I should no longer be able to create outgoing diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index b0930b0..72b14de 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc @@ -97,7 +97,7 @@ void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, packet); return; } - session = CreateQuicSession(guid, client_address, fd_, epoll_server_); + session = CreateQuicSession(guid, client_address); if (session == NULL) { DLOG(INFO) << "Failed to create session for " << guid; @@ -198,11 +198,9 @@ void QuicDispatcher::OnConnectionClose(QuicGuid guid, QuicErrorCode error) { QuicSession* QuicDispatcher::CreateQuicSession( QuicGuid guid, - const IPEndPoint& client_address, - int /* fd */, - EpollServer* epoll_server) { + const IPEndPoint& client_address) { QuicConnectionHelperInterface* helper = - new QuicEpollConnectionHelper(epoll_server); + new QuicEpollConnectionHelper(epoll_server_); QuicServerSession* session = new QuicServerSession( config_, new QuicConnection(guid, client_address, helper, this, true, QuicVersionMax()), this); diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index a5ce3e8..ddc98df 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h @@ -91,9 +91,7 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { virtual QuicSession* CreateQuicSession( QuicGuid guid, - const IPEndPoint& client_address, - int fd, - EpollServer* epoll_server); + const IPEndPoint& client_address); // Deletes all sessions on the closed session list and clears the list. void DeleteSessions(); @@ -114,6 +112,8 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner { return time_wait_list_manager_.get(); } + EpollServer* epoll_server() { return epoll_server_; } + private: friend class net::tools::test::QuicDispatcherPeer; diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 0d7407a..651f224 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc @@ -43,11 +43,9 @@ class TestDispatcher : public QuicDispatcher { EpollServer* eps) : QuicDispatcher(config, crypto_config, 1, eps) {} - MOCK_METHOD4(CreateQuicSession, QuicSession*( + MOCK_METHOD2(CreateQuicSession, QuicSession*( QuicGuid guid, - const IPEndPoint& client_address, - int fd, - EpollServer* eps)); + const IPEndPoint& client_address)); using QuicDispatcher::write_blocked_list; }; @@ -139,12 +137,12 @@ class QuicDispatcherTest : public ::testing::Test { TEST_F(QuicDispatcherTest, ProcessPackets) { IPEndPoint addr(Loopback4(), 1); - EXPECT_CALL(dispatcher_, CreateQuicSession(1, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(1, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, 1, addr, &session1_, &eps_))); ProcessPacket(addr, 1, "foo"); - EXPECT_CALL(dispatcher_, CreateQuicSession(2, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(2, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, 2, addr, &session2_, &eps_))); ProcessPacket(addr, 2, "bar"); @@ -160,7 +158,7 @@ TEST_F(QuicDispatcherTest, ProcessPackets) { TEST_F(QuicDispatcherTest, Shutdown) { IPEndPoint addr(Loopback4(), 1); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, 1, addr, &session1_, &eps_))); @@ -195,7 +193,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { // Create a new session. IPEndPoint addr(Loopback4(), 1); QuicGuid guid = 1; - EXPECT_CALL(dispatcher_, CreateQuicSession(guid, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(guid, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, guid, addr, &session1_, &eps_))); ProcessPacket(addr, guid, "foo"); @@ -232,12 +230,12 @@ class QuicWriteBlockedListTest : public QuicDispatcherTest { virtual void SetUp() { IPEndPoint addr(Loopback4(), 1); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, 1, addr, &session1_, &eps_))); ProcessPacket(addr, 1, "foo"); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr, _, &eps_)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, addr)) .WillOnce(testing::Return(CreateSession( &dispatcher_, 2, addr, &session2_, &eps_))); ProcessPacket(addr, 2, "bar"); 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 65f9fd7..8ea2992 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc @@ -31,11 +31,28 @@ class WriteUnblockedAlarm : public QuicAlarm::Delegate { PacketDroppingTestWriter* writer_; }; +// An alarm that is scheduled every time a new packet is to be written at a +// later point. +class DelayAlarm : public QuicAlarm::Delegate { + public: + explicit DelayAlarm(PacketDroppingTestWriter* writer) + : writer_(writer) { } + + virtual QuicTime OnAlarm() OVERRIDE { + return writer_->ReleaseNextPacket(); + } + + private: + PacketDroppingTestWriter* writer_; +}; + PacketDroppingTestWriter::PacketDroppingTestWriter() : clock_(NULL), blocked_writer_(NULL), fake_packet_loss_percentage_(0), - fake_blocked_socket_percentage_(0) { + fake_blocked_socket_percentage_(0), + fake_packet_reorder_percentage_(0), + fake_packet_delay_(QuicTime::Delta::Zero()) { int64 seed = base::RandUint64(); LOG(INFO) << "Seeding packet loss with " << seed; simple_random_.set_seed(seed); @@ -48,6 +65,8 @@ void PacketDroppingTestWriter::SetConnectionHelper( clock_ = helper->GetClock(); write_unblocked_alarm_.reset( helper->CreateAlarm(new WriteUnblockedAlarm(this))); + delay_alarm_.reset( + helper->CreateAlarm(new DelayAlarm(this))); } WriteResult PacketDroppingTestWriter::WritePacket( @@ -56,12 +75,14 @@ WriteResult PacketDroppingTestWriter::WritePacket( const net::IPEndPoint& peer_address, QuicBlockedWriterInterface* blocked_writer) { if (fake_packet_loss_percentage_ > 0 && - simple_random_.RandUint64() % 100 < fake_packet_loss_percentage_) { + simple_random_.RandUint64() % 100 < + static_cast<uint64>(fake_packet_loss_percentage_)) { DLOG(INFO) << "Dropping packet."; return WriteResult(WRITE_STATUS_OK, buf_len); } if (fake_blocked_socket_percentage_ > 0 && - simple_random_.RandUint64() % 100 < fake_blocked_socket_percentage_) { + simple_random_.RandUint64() % 100 < + static_cast<uint64>(fake_blocked_socket_percentage_)) { DLOG(INFO) << "Blocking socket."; if (!write_unblocked_alarm_->IsSet()) { blocked_writer_ = blocked_writer; @@ -73,6 +94,19 @@ WriteResult PacketDroppingTestWriter::WritePacket( return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN); } + if (!fake_packet_delay_.IsZero()) { + // Queue it to be sent. + QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_); + delayed_packets_.push_back(DelayedWrite(buffer, buf_len, self_address, + peer_address, send_time)); + // Set the alarm if it's not yet set. + if (!delay_alarm_->IsSet()) { + delay_alarm_->Set(send_time); + } + + return WriteResult(WRITE_STATUS_OK, buf_len); + } + return writer()->WritePacket(buffer, buf_len, self_address, peer_address, blocked_writer); } @@ -81,6 +115,49 @@ bool PacketDroppingTestWriter::IsWriteBlockedDataBuffered() const { return false; } +QuicTime PacketDroppingTestWriter::ReleaseNextPacket() { + if (delayed_packets_.empty()) { + return QuicTime::Zero(); + } + DelayedPacketList::iterator iter = delayed_packets_.begin(); + // Determine if we should re-order. + if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 && + simple_random_.RandUint64() % 100 < + static_cast<uint64>(fake_packet_reorder_percentage_)) { + DLOG(INFO) << "Reordering packets."; + ++iter; + // Swap the send times when re-ordering packets. + delayed_packets_.begin()->send_time = iter->send_time; + } + + DLOG(INFO) << "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); + delayed_packets_.erase(iter); + + // If there are others, find the time for the next to be sent. + if (delayed_packets_.empty()) { + return QuicTime::Zero(); + } + return delayed_packets_.begin()->send_time; +} + +PacketDroppingTestWriter::DelayedWrite::DelayedWrite( + const char* buffer, + size_t buf_len, + const net::IPAddressNumber& self_address, + const net::IPEndPoint& peer_address, + QuicTime send_time) + : buffer(buffer, buf_len), + self_address(self_address), + peer_address(peer_address), + send_time(send_time) { +} + +PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {} + } // namespace test } // namespace tools } // namespace net 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 6ee533b..4067ea9 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h @@ -5,6 +5,8 @@ #ifndef NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ #define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_ +#include <list> + #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "net/quic/quic_alarm.h" @@ -20,7 +22,8 @@ namespace tools { 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. +// 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 { public: PacketDroppingTestWriter(); @@ -38,6 +41,10 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter { virtual bool IsWriteBlockedDataBuffered() const OVERRIDE; + // Writes out the next packet to the contained writer and returns the time + // for the next delayed packet to be written. + QuicTime ReleaseNextPacket(); + QuicBlockedWriterInterface* blocked_writer() { return blocked_writer_; } // The percent of time a packet is simulated as being lost. @@ -53,13 +60,48 @@ class PacketDroppingTestWriter : public net::test::QuicTestWriter { fake_blocked_socket_percentage_ = fake_blocked_socket_percentage; } + // The percent of time a packet is simulated as being reordered. + void set_fake_reorder_percentage(int32 fake_packet_reorder_percentage) { + DCHECK(clock_); + fake_packet_reorder_percentage_ = fake_packet_reorder_percentage; + } + + // The percent of time WritePacket will block and set WriteResult's status + // to WRITE_BLOCKED. + void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) { + DCHECK(clock_); + fake_packet_delay_ = fake_packet_delay; + } + private: + // A single packet which will be sent at the supplied send_time. + class DelayedWrite { + public: + DelayedWrite(const char* buffer, + size_t buf_len, + const IPAddressNumber& self_address, + const IPEndPoint& peer_address, + QuicTime send_time); + ~DelayedWrite(); + + string buffer; + const IPAddressNumber self_address; + const IPEndPoint peer_address; + QuicTime send_time; + }; + + typedef std::list<DelayedWrite> DelayedPacketList; + const QuicClock* clock_; scoped_ptr<QuicAlarm> write_unblocked_alarm_; + scoped_ptr<QuicAlarm> delay_alarm_; QuicBlockedWriterInterface* blocked_writer_; - uint32 fake_packet_loss_percentage_; - uint32 fake_blocked_socket_percentage_; + int32 fake_packet_loss_percentage_; + int32 fake_blocked_socket_percentage_; + int32 fake_packet_reorder_percentage_; + QuicTime::Delta fake_packet_delay_; SimpleRandom simple_random_; + DelayedPacketList delayed_packets_; DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter); }; diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 701ca3d..c320b82 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -100,7 +100,7 @@ class QuicEpollClient : public QuicClient { const string& server_hostname, const QuicVersion version) : Super(server_address, server_hostname, version, false), - test_writer_(NULL) { + override_guid_(0), test_writer_(NULL) { } QuicEpollClient(IPEndPoint server_address, @@ -108,7 +108,7 @@ class QuicEpollClient : public QuicClient { const QuicConfig& config, const QuicVersion version) : Super(server_address, server_hostname, config, version), - test_writer_(NULL) { + override_guid_(0), test_writer_(NULL) { } virtual ~QuicEpollClient() { @@ -126,10 +126,19 @@ class QuicEpollClient : public QuicClient { return test_writer_; } + virtual QuicGuid GenerateGuid() OVERRIDE { + return override_guid_ ? override_guid_ : Super::GenerateGuid(); + } + // Takes ownership of writer. void UseWriter(QuicTestWriter* writer) { test_writer_ = writer; } + void UseGuid(QuicGuid guid) { + override_guid_ = guid; + } + private: + QuicGuid override_guid_; // GUID to use, if nonzero QuicTestWriter* test_writer_; }; @@ -165,7 +174,7 @@ void QuicTestClient::Initialize(IPEndPoint address, priority_ = 3; bytes_read_ = 0; bytes_written_= 0; - never_connected_ = true; + connect_attempted_ = false; secure_ = secure; auto_reconnect_ = false; proof_verifier_ = NULL; @@ -239,7 +248,7 @@ string QuicTestClient::SendSynchronousRequest(const string& uri) { } QuicReliableClientStream* QuicTestClient::GetOrCreateStream() { - if (never_connected_ == true || auto_reconnect_) { + if (!connect_attempted_ || auto_reconnect_) { if (!connected()) { Connect(); } @@ -278,9 +287,11 @@ void QuicTestClient::WaitForResponse() { void QuicTestClient::Connect() { DCHECK(!connected()); - client_->Initialize(); + if (!connect_attempted_) { + client_->Initialize(); + } client_->Connect(); - never_connected_ = false; + connect_attempted_ = true; } void QuicTestClient::ResetConnection() { @@ -290,6 +301,7 @@ void QuicTestClient::ResetConnection() { void QuicTestClient::Disconnect() { client_->Disconnect(); + connect_attempted_ = false; } IPEndPoint QuicTestClient::LocalSocketAddress() const { @@ -344,6 +356,11 @@ void QuicTestClient::UseWriter(QuicTestWriter* writer) { reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer); } +void QuicTestClient::UseGuid(QuicGuid guid) { + DCHECK(!connected()); + reinterpret_cast<QuicEpollClient*>(client_.get())->UseGuid(guid); +} + } // namespace test } // namespace tools } // namespace net diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 9640505..4f52cfb 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -81,6 +81,9 @@ class QuicTestClient : public ReliableQuicStream::Visitor { // Configures client_ to take ownership of and use the writer. // Must be called before initial connect. void UseWriter(net::test::QuicTestWriter* writer); + // If the given GUID is nonzero, configures client_ to use a specific GUID + // instead of a random one. + void UseGuid(QuicGuid guid); // Returns NULL if the maximum number of streams have already been created. QuicReliableClientStream* GetOrCreateStream(); @@ -117,13 +120,12 @@ class QuicTestClient : public ReliableQuicStream::Visitor { string response_; uint64 bytes_read_; uint64 bytes_written_; - // True if the client has never connected before. The client will - // auto-connect exactly once before sending data. If something causes a - // connection reset, it will not automatically reconnect. - bool never_connected_; + // True if we tried to connect already since the last call to Disconnect(). + bool connect_attempted_; bool secure_; - // If true, the client will always reconnect if necessary before creating a - // stream. + // The client will auto-connect exactly once before sending data. If + // something causes a connection reset, it will not automatically reconnect + // unless auto_reconnect_ is true. bool auto_reconnect_; // proof_verifier_ points to a RecordingProofVerifier that is owned by |