diff options
38 files changed, 312 insertions, 199 deletions
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc index 7af949a..33f6ba00 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.cc +++ b/net/quic/congestion_control/send_algorithm_simulator.cc @@ -195,7 +195,7 @@ QuicTime::Delta SendAlgorithmSimulator::FindNextAck( continue; } // Lost packets don't trigger an ack. - if (it->ack_time == QuicTime::Zero()) { + if (it->lost) { continue; } DCHECK_LT(*next_acked, it->sequence_number); @@ -228,7 +228,7 @@ bool SendAlgorithmSimulator::HasRecentLostPackets( continue; } // Lost packets don't trigger an ack. - if (it->ack_time == QuicTime::Zero()) { + if (it->lost) { return true; } // Buffer dropped packets are skipped automatically, but still end up @@ -252,7 +252,7 @@ void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) { << " Now():" << (clock_->Now().ToDebuggingValue() / 1000) << "ms"; // Some entries may be missing from the sent_packets_ array, if they were // dropped due to buffer overruns. - SentPacket largest_observed(0, QuicTime::Zero(), QuicTime::Zero(), NULL); + SentPacket largest_observed; list<SentPacket>::iterator it = sent_packets_.begin(); while (sender->last_acked < sender->next_acked) { ++sender->last_acked; @@ -271,10 +271,10 @@ void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) { lost_packets[sender->last_acked] = info; continue; } - if (it->ack_time.IsInitialized()) { - acked_packets[sender->last_acked] = info; - } else { + if (it->lost) { lost_packets[sender->last_acked] = info; + } else { + acked_packets[sender->last_acked] = info; } // This packet has been acked or lost, remove it from sent_packets_. largest_observed = *it; @@ -310,6 +310,8 @@ void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) { sender->last_transfer_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(transfer->num_bytes, transfer_time); + DCHECK_GE(bandwidth_.ToBitsPerSecond(), + sender->last_transfer_bandwidth.ToBitsPerSecond()); for (vector<Transfer>::iterator it = pending_transfers_.begin(); it != pending_transfers_.end(); ++it) { if (transfer == &(*it)) { @@ -336,8 +338,7 @@ void SendAlgorithmSimulator::SendDataNow(Transfer* transfer) { bool packet_lost = forward_loss_rate_ * kuint64max > simple_random_.RandUint64(); // Handle correlated loss. - if (!sent_packets_.empty() && - !sent_packets_.back().ack_time.IsInitialized() && + if (!sent_packets_.empty() && sent_packets_.back().lost && loss_correlation_ * kuint64max > simple_random_.RandUint64()) { packet_lost = true; } @@ -354,10 +355,8 @@ void SendAlgorithmSimulator::SendDataNow(Transfer* transfer) { QuicTime queue_ack_time = sent_packets_.empty() ? QuicTime::Zero() : sent_packets_.back().ack_time.Add(bandwidth_.TransferTime(kPacketSize)); ack_time = QuicTime::Max(ack_time, queue_ack_time); - // If the packet is lost, give it an ack time of Zero. sent_packets_.push_back(SentPacket( - sender->last_sent, clock_->Now(), - packet_lost ? QuicTime::Zero() : ack_time, transfer)); + sender->last_sent, clock_->Now(), ack_time, packet_lost, transfer)); } else { DVLOG(1) << "losing packet:" << sender->last_sent << " because the buffer was full."; diff --git a/net/quic/congestion_control/send_algorithm_simulator.h b/net/quic/congestion_control/send_algorithm_simulator.h index fb64049..934b275 100644 --- a/net/quic/congestion_control/send_algorithm_simulator.h +++ b/net/quic/congestion_control/send_algorithm_simulator.h @@ -89,18 +89,27 @@ class SendAlgorithmSimulator { }; struct SentPacket { + SentPacket() + : sequence_number(0), + send_time(QuicTime::Zero()), + ack_time(QuicTime::Zero()), + lost(false), + transfer(NULL) {} SentPacket(QuicPacketSequenceNumber sequence_number, QuicTime send_time, QuicTime ack_time, + bool lost, Transfer* transfer) : sequence_number(sequence_number), send_time(send_time), ack_time(ack_time), + lost(lost), transfer(transfer) {} QuicPacketSequenceNumber sequence_number; QuicTime send_time; QuicTime ack_time; + bool lost; Transfer* transfer; }; diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc index 408b76b..5a928b6 100644 --- a/net/quic/crypto/crypto_handshake.cc +++ b/net/quic/crypto/crypto_handshake.cc @@ -13,7 +13,8 @@ namespace net { QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() : key_exchange(0), - aead(0) { + aead(0), + x509_ecdsa_supported(false) { } QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {} diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h index cc25570..bfd2f34 100644 --- a/net/quic/crypto/crypto_handshake.h +++ b/net/quic/crypto/crypto_handshake.h @@ -124,6 +124,13 @@ struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters { // bytes of x coordinate, followed by 32 bytes of y coordinate. Both values // are big-endian and the pair is a P-256 public key. std::string channel_id; + + // Used when generating proof signature when sending server config updates. + bool x509_ecdsa_supported; + + // Used to generate cert chain when sending server config updates. + std::string client_common_set_hashes; + std::string client_cached_cert_hashes; }; // QuicCryptoConfig contains common configuration between clients and servers. diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc index 18c0d54..9b64e1c 100644 --- a/net/quic/crypto/quic_crypto_client_config.cc +++ b/net/quic/crypto/quic_crypto_client_config.cc @@ -612,7 +612,12 @@ QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig( cached->SetProof(certs, proof); } else { - cached->ClearProof(); + if (proof_verifier() != NULL) { + // Secure QUIC: clear existing proof as we have been sent a new SCFG + // without matching proof/certs. + cached->ClearProof(); + } + if (has_proof && !has_cert) { *error_details = "Certificate missing"; return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index ec88594c..bfd3ed3 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc @@ -603,7 +603,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( !info.client_nonce_well_formed || !info.unique || !requested_config.get()) { - BuildRejection(*primary_config, client_hello, info, rand, out); + BuildRejection(*primary_config, client_hello, info, rand, params, out); return QUIC_NO_ERROR; } @@ -1039,11 +1039,50 @@ void QuicCryptoServerConfig::EvaluateClientHello( helper.StartedAsyncCallback(); } +bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( + const IPEndPoint& client_ip, + const QuicClock* clock, + QuicRandom* rand, + const QuicCryptoNegotiatedParameters& params, + CryptoHandshakeMessage* out) const { + base::AutoLock locked(configs_lock_); + out->set_tag(kSCUP); + out->SetStringPiece(kSCFG, primary_config_->serialized); + out->SetStringPiece(kSourceAddressTokenTag, + NewSourceAddressToken(*primary_config_, + client_ip, + rand, + clock->WallNow())); + + if (proof_source_ == NULL) { + // Insecure QUIC, can send SCFG without proof. + return true; + } + + const vector<string>* certs; + string signature; + if (!proof_source_->GetProof(params.sni, primary_config_->serialized, + params.x509_ecdsa_supported, &certs, + &signature)) { + DVLOG(1) << "Server: failed to get proof."; + return false; + } + + const string compressed = CertCompressor::CompressChain( + *certs, params.client_common_set_hashes, params.client_cached_cert_hashes, + primary_config_->common_cert_sets); + + out->SetStringPiece(kCertificateTag, compressed); + out->SetStringPiece(kPROF, signature); + return true; +} + void QuicCryptoServerConfig::BuildRejection( const Config& config, const CryptoHandshakeMessage& client_hello, const ClientHelloInfo& info, QuicRandom* rand, + QuicCryptoNegotiatedParameters *params, CryptoHandshakeMessage* out) const { out->set_tag(kREJ); out->SetStringPiece(kSCFG, config.serialized); @@ -1074,12 +1113,12 @@ void QuicCryptoServerConfig::BuildRejection( return; } - bool x509_supported = false, x509_ecdsa_supported = false; + bool x509_supported = false; for (size_t i = 0; i < num_their_proof_demands; i++) { switch (their_proof_demands[i]) { case kX509: x509_supported = true; - x509_ecdsa_supported = true; + params->x509_ecdsa_supported = true; break; case kX59R: x509_supported = true; @@ -1094,18 +1133,24 @@ void QuicCryptoServerConfig::BuildRejection( const vector<string>* certs; string signature; if (!proof_source_->GetProof(info.sni.as_string(), config.serialized, - x509_ecdsa_supported, &certs, &signature)) { + params->x509_ecdsa_supported, &certs, + &signature)) { return; } - StringPiece their_common_set_hashes; - StringPiece their_cached_cert_hashes; - client_hello.GetStringPiece(kCCS, &their_common_set_hashes); - client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes); + StringPiece client_common_set_hashes; + if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) { + params->client_common_set_hashes = client_common_set_hashes.as_string(); + } + + StringPiece client_cached_cert_hashes; + if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { + params->client_cached_cert_hashes = client_cached_cert_hashes.as_string(); + } const string compressed = CertCompressor::CompressChain( - *certs, their_common_set_hashes, their_cached_cert_hashes, - config.common_cert_sets); + *certs, params->client_common_set_hashes, + params->client_cached_cert_hashes, config.common_cert_sets); // kREJOverheadBytes is a very rough estimate of how much of a REJ // message is taken up by things other than the certificates. diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h index 8760ace..9ec0612 100644 --- a/net/quic/crypto/quic_crypto_server_config.h +++ b/net/quic/crypto/quic_crypto_server_config.h @@ -16,6 +16,7 @@ #include "net/base/ip_endpoint.h" #include "net/base/net_export.h" #include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/crypto/crypto_handshake_message.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/crypto/crypto_secret_boxer.h" #include "net/quic/quic_time.h" @@ -210,6 +211,13 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { CryptoHandshakeMessage* out, std::string* error_details) const; + bool BuildServerConfigUpdateMessage( + const IPEndPoint& client_ip, + const QuicClock* clock, + QuicRandom* rand, + const QuicCryptoNegotiatedParameters& params, + CryptoHandshakeMessage* out) const; + // SetProofSource installs |proof_source| as the ProofSource for handshakes. // This object takes ownership of |proof_source|. void SetProofSource(ProofSource* proof_source); @@ -371,6 +379,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { const CryptoHandshakeMessage& client_hello, const ClientHelloInfo& info, QuicRandom* rand, + QuicCryptoNegotiatedParameters *params, CryptoHandshakeMessage* out) const; // ParseConfigProtobuf parses the given config protobuf and returns a diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 405ba42..f40b34d 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -1179,17 +1179,15 @@ void QuicConnection::WriteIfNotBlocked() { } bool QuicConnection::ProcessValidatedPacket() { - if ((!FLAGS_quic_allow_port_migration && peer_port_changed_) || - peer_ip_changed_ || self_ip_changed_ || self_port_changed_) { + if (peer_ip_changed_ || self_ip_changed_ || self_port_changed_) { SendConnectionCloseWithDetails( QUIC_ERROR_MIGRATING_ADDRESS, "Neither IP address migration, nor self port migration are supported."); return false; } - // Port migration is supported, do it now if port has changed. - if (FLAGS_quic_allow_port_migration && - peer_port_changed_) { + // Peer port migration is supported, do it now if port has changed. + if (peer_port_changed_) { DVLOG(1) << ENDPOINT << "Peer's port changed from " << peer_address_.port() << " to " << migrating_peer_port_ << ", migrating connection."; @@ -1542,6 +1540,10 @@ bool QuicConnection::OnSerializedPacket( NOT_RETRANSMISSION); } +void QuicConnection::OnHandshakeComplete() { + sent_packet_manager_.SetHandshakeConfirmed(); +} + bool QuicConnection::SendOrQueuePacket(EncryptionLevel level, const SerializedPacket& packet, TransmissionType transmission_type) { @@ -1796,6 +1798,9 @@ void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) { return; } connected_ = false; + if (debug_visitor_.get() != NULL) { + debug_visitor_->OnConnectionClosed(error, from_peer); + } visitor_->OnConnectionClosed(error, from_peer); // Cancel the alarms so they don't trigger any action now that the // connection is closed. diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index a98458b..ee5955f 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -198,6 +198,9 @@ class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor // in the revival of a packet via FEC. virtual void OnRevivedPacket(const QuicPacketHeader& revived_header, base::StringPiece payload) {} + + // Called when the connection is closed. + virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) {} }; class NET_EXPORT_PRIVATE QuicConnectionHelperInterface { @@ -363,6 +366,11 @@ class NET_EXPORT_PRIVATE QuicConnection virtual QuicStopWaitingFrame* CreateStopWaitingFrame() OVERRIDE; virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE; + // Called by the crypto stream when the handshake completes. In the server's + // case this is when the SHLO has been ACKed. Clients call this on receipt of + // the SHLO. + void OnHandshakeComplete(); + // Accessors void set_visitor(QuicConnectionVisitorInterface* visitor) { visitor_ = visitor; diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h index d020a61..bbb87e0 100644 --- a/net/quic/quic_connection_logger.h +++ b/net/quic/quic_connection_logger.h @@ -62,12 +62,12 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger const QuicVersionNegotiationPacket& packet) OVERRIDE; virtual void OnRevivedPacket(const QuicPacketHeader& revived_header, base::StringPiece payload) OVERRIDE; + virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE; void OnCryptoHandshakeMessageReceived( const CryptoHandshakeMessage& message); void OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& message); - void OnConnectionClosed(QuicErrorCode error, bool from_peer); void OnSuccessfulVersionNegotiation(const QuicVersion& version); void UpdateReceivedFrameCounts(QuicStreamId stream_id, int num_frames_received, diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index d28860a..40e4d45 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -464,6 +464,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( handshake_confirmed_ = true; session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + session()->connection()->OnHandshakeComplete(); return; } case STATE_IDLE: diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 7bd2c03..8e07f54 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc @@ -15,13 +15,23 @@ namespace net { +void ServerHelloNotifier::OnAckNotification( + int num_original_packets, + int num_original_bytes, + int num_retransmitted_packets, + int num_retransmitted_bytes, + QuicTime::Delta delta_largest_observed) { + server_stream_->OnServerHelloAcked(); +} + QuicCryptoServerStream::QuicCryptoServerStream( const QuicCryptoServerConfig& crypto_config, QuicSession* session) : QuicCryptoStream(session), crypto_config_(crypto_config), validate_client_hello_cb_(NULL), - num_handshake_messages_(0) { + num_handshake_messages_(0), + num_server_config_update_messages_sent_(0) { } QuicCryptoServerStream::~QuicCryptoServerStream() { @@ -116,7 +126,16 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage( session()->connection()->SetDecrypter( crypto_negotiated_params_.initial_crypters.decrypter.release(), ENCRYPTION_INITIAL); - SendHandshakeMessage(reply); + + // We want to be notified when the SHLO is ACKed so that we can disable + // HANDSHAKE_MODE in the sent packet manager. + if (session()->connection()->version() <= QUIC_VERSION_21) { + SendHandshakeMessage(reply); + } else { + scoped_refptr<ServerHelloNotifier> server_hello_notifier( + new ServerHelloNotifier(this)); + SendHandshakeMessage(reply, server_hello_notifier.get()); + } session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, @@ -130,6 +149,37 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage( encryption_established_ = true; handshake_confirmed_ = true; session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + + // Now that the handshake is complete, send an updated server config and + // source-address token to the client. + SendServerConfigUpdate(); +} + +void QuicCryptoServerStream::SendServerConfigUpdate() { + if (session()->connection()->version() <= QUIC_VERSION_21) { + return; + } + + CryptoHandshakeMessage server_config_update_message; + if (!crypto_config_.BuildServerConfigUpdateMessage( + session()->connection()->peer_address(), + session()->connection()->clock(), + session()->connection()->random_generator(), + crypto_negotiated_params_, &server_config_update_message)) { + DVLOG(1) << "Server: Failed to build server config update (SCUP)!"; + return; + } + + DVLOG(1) << "Server: Sending server config update (SCUP): " + << server_config_update_message.DebugString(); + const QuicData& data = server_config_update_message.GetSerialized(); + WriteOrBufferData(string(data.data(), data.length()), false, NULL); + + ++num_server_config_update_messages_sent_; +} + +void QuicCryptoServerStream::OnServerHelloAcked() { + session()->connection()->OnHandshakeComplete(); } bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID( diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h index ee40131..9cb242b 100644 --- a/net/quic/quic_crypto_server_stream.h +++ b/net/quic/quic_crypto_server_stream.h @@ -16,12 +16,37 @@ namespace net { class CryptoHandshakeMessage; class QuicCryptoServerConfig; +class QuicCryptoServerStream; class QuicSession; namespace test { class CryptoTestUtils; } // namespace test +// Receives a notification when the server hello (SHLO) has been ACKed by the +// peer. At this point we disable HANDSHAKE_MODE in the sent packet manager. +class NET_EXPORT_PRIVATE ServerHelloNotifier : public + QuicAckNotifier::DelegateInterface { + public: + explicit ServerHelloNotifier(QuicCryptoServerStream* stream) + : server_stream_(stream) {} + + // QuicAckNotifier::DelegateInterface implementation + virtual void OnAckNotification( + int num_original_packets, + int num_original_bytes, + int num_retransmitted_packets, + int num_retransmitted_bytes, + QuicTime::Delta delta_largest_observed) OVERRIDE; + + private: + virtual ~ServerHelloNotifier() {} + + QuicCryptoServerStream* server_stream_; + + DISALLOW_COPY_AND_ASSIGN(ServerHelloNotifier); +}; + class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { public: QuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config, @@ -44,6 +69,17 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { uint8 num_handshake_messages() const { return num_handshake_messages_; } + int num_server_config_update_messages_sent() const { + return num_server_config_update_messages_sent_; + } + + // Sends the latest server config and source-address token to the client. + void SendServerConfigUpdate(); + + // Called by the ServerHello AckNotifier once the SHLO has been ACKed by the + // client. + void OnServerHelloAcked(); + protected: virtual QuicErrorCode ProcessClientHello( const CryptoHandshakeMessage& message, @@ -90,8 +126,12 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream { // handshake message is being validated. ValidateCallback* validate_client_hello_cb_; + // Number of handshake messages received by this stream. uint8 num_handshake_messages_; + // Number of server config update (SCUP) messages sent by this stream. + int num_server_config_update_messages_sent_; + DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream); }; diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 8e8da00..c2e8bf8 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -131,6 +131,7 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { EXPECT_EQ(2, CompleteCryptoHandshake()); EXPECT_TRUE(stream_.encryption_established()); EXPECT_TRUE(stream_.handshake_confirmed()); + EXPECT_EQ(1, stream_.num_server_config_update_messages_sent()); } TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { @@ -223,6 +224,7 @@ TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { } EXPECT_EQ(1, client->num_sent_client_hellos()); + EXPECT_EQ(1, server->num_server_config_update_messages_sent()); } TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) { diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc index 25467cb..fe2d311 100644 --- a/net/quic/quic_crypto_stream.cc +++ b/net/quic/quic_crypto_stream.cc @@ -61,11 +61,17 @@ QuicPriority QuicCryptoStream::EffectivePriority() const { void QuicCryptoStream::SendHandshakeMessage( const CryptoHandshakeMessage& message) { + SendHandshakeMessage(message, NULL); +} + +void QuicCryptoStream::SendHandshakeMessage( + const CryptoHandshakeMessage& message, + QuicAckNotifier::DelegateInterface* delegate) { DVLOG(1) << ENDPOINT << "Sending " << message.DebugString(); session()->OnCryptoHandshakeMessageSent(message); const QuicData& data = message.GetSerialized(); // TODO(wtc): check the return value. - WriteOrBufferData(string(data.data(), data.length()), false, NULL); + WriteOrBufferData(string(data.data(), data.length()), false, delegate); } bool QuicCryptoStream::ExportKeyingMaterial( diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h index 131e096..4cce73c 100644 --- a/net/quic/quic_crypto_stream.h +++ b/net/quic/quic_crypto_stream.h @@ -45,6 +45,10 @@ class NET_EXPORT_PRIVATE QuicCryptoStream // Sends |message| to the peer. // TODO(wtc): return a success/failure status. void SendHandshakeMessage(const CryptoHandshakeMessage& message); + // As above, but registers |delegate| for notification when |message| has been + // ACKed by the peer. + void SendHandshakeMessage(const CryptoHandshakeMessage& message, + QuicAckNotifier::DelegateInterface* delegate); // Performs key extraction to derive a new secret of |result_len| bytes // dependent on |label|, |context|, and the stream's negotiated subkey secret. diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc index b21d5c0..7664912 100644 --- a/net/quic/quic_crypto_stream_test.cc +++ b/net/quic/quic_crypto_stream_test.cc @@ -10,7 +10,6 @@ #include "base/memory/scoped_ptr.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" -#include "net/quic/quic_flags.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/reliable_quic_stream_peer.h" @@ -104,8 +103,6 @@ TEST_F(QuicCryptoStreamTest, ProcessBadData) { } TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); if (connection_->version() <= QUIC_VERSION_20) { EXPECT_FALSE(stream_.flow_controller()->IsEnabled()); } else { diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc index b36053c..26dcd6c 100644 --- a/net/quic/quic_data_stream_test.cc +++ b/net/quic/quic_data_stream_test.cc @@ -6,7 +6,6 @@ #include "net/quic/quic_ack_notifier.h" #include "net/quic/quic_connection.h" -#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" @@ -418,9 +417,6 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) { if (GetParam() < QUIC_VERSION_19) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); - Initialize(kShouldProcessData); // Set a small flow control limit for streams and connection. @@ -505,8 +501,6 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) { if (GetParam() < QUIC_VERSION_19) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Stream should not process data, so that data gets buffered in the // sequencer, triggering flow control limits. diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc index 5c6836a..802f00b 100644 --- a/net/quic/quic_dispatcher.cc +++ b/net/quic/quic_dispatcher.cc @@ -164,7 +164,6 @@ QuicDispatcher::QuicDispatcher(const QuicConfig& config, delete_sessions_alarm_( helper_->CreateAlarm(new DeleteSessionsAlarm(this))), supported_versions_(supported_versions), - supported_versions_no_connection_flow_control_(supported_versions), current_packet_(NULL), framer_(supported_versions, /*unused*/ QuicTime::Zero(), true), framer_visitor_(new QuicFramerVisitor(this)) { @@ -180,19 +179,6 @@ void QuicDispatcher::Initialize(QuicServerPacketWriter* writer) { DCHECK(writer_ == NULL); writer_.reset(writer); time_wait_list_manager_.reset(CreateQuicTimeWaitListManager()); - - // Remove all versions > QUIC_VERSION_18 from the - // supported_versions_no_connection_flow_control_ vector. - QuicVersionVector::iterator connection_it = - find(supported_versions_no_connection_flow_control_.begin(), - supported_versions_no_connection_flow_control_.end(), - QUIC_VERSION_19); - if (connection_it != supported_versions_no_connection_flow_control_.end()) { - supported_versions_no_connection_flow_control_.erase( - supported_versions_no_connection_flow_control_.begin(), - connection_it + 1); - } - CHECK(!supported_versions_no_connection_flow_control_.empty()); } void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, @@ -375,27 +361,14 @@ QuicConnection* QuicDispatcher::CreateQuicConnection( const IPEndPoint& client_address, QuicPerConnectionPacketWriter* writer) { QuicConnection* connection; - if (FLAGS_enable_quic_connection_flow_control_2) { - DVLOG(1) << "Creating QuicDispatcher with all versions."; - connection = new QuicConnection(connection_id, - client_address, - helper_, - writer, - false /* owns_writer */, - true /* is_server */, - supported_versions_); - } else { - DVLOG(1) << "Connection flow control disabled, creating QuicDispatcher " - << "WITHOUT version 19 or higher."; - connection = new QuicConnection( - connection_id, - client_address, - helper_, - writer, - false /* owns_writer */, - true /* is_server */, - supported_versions_no_connection_flow_control_); - } + connection = new QuicConnection( + connection_id, + client_address, + helper_, + writer, + false /* owns_writer */, + true /* is_server */, + supported_versions_); writer->set_connection(connection); return connection; } diff --git a/net/quic/quic_dispatcher.h b/net/quic/quic_dispatcher.h index e7a5e95..684461d 100644 --- a/net/quic/quic_dispatcher.h +++ b/net/quic/quic_dispatcher.h @@ -137,11 +137,6 @@ class QuicDispatcher : public QuicBlockedWriterInterface, return supported_versions_; } - const QuicVersionVector& supported_versions_no_connection_flow_control() - const { - return supported_versions_no_connection_flow_control_; - } - const IPEndPoint& current_server_address() { return current_server_address_; } @@ -206,14 +201,6 @@ class QuicDispatcher : public QuicBlockedWriterInterface, // skipped as necessary). const QuicVersionVector supported_versions_; - // Versions which do not support *connection* flow control (introduced in - // QUIC_VERSION_19). - // This is used to construct new QuicConnections when connection flow control - // is disabled via flag. - // TODO(rjshade): Remove this when - // FLAGS_enable_quic_connection_flow_control_2 is removed. - QuicVersionVector supported_versions_no_connection_flow_control_; - // Information about the packet currently being handled. IPEndPoint current_client_address_; IPEndPoint current_server_address_; diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 58980b3..affa271 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc @@ -19,20 +19,11 @@ bool FLAGS_track_retransmission_history = false; // request pacing for the server to enable it. bool FLAGS_enable_quic_pacing = true; -// Do not remove this flag until b/11792453 is marked as Fixed. -// If true, turns on connection level flow control in QUIC. -// If this is disabled, all in flight QUIC connections talking QUIC_VERSION_19 -// or higher will timeout. New connections will be fine. -bool FLAGS_enable_quic_connection_flow_control_2 = true; - bool FLAGS_quic_allow_oversized_packets_for_test = false; // When true, the use time based loss detection instead of nack. bool FLAGS_quic_use_time_loss_detection = false; -// If true, allow peer port migration of established QUIC connections. -bool FLAGS_quic_allow_port_migration = true; - // If true, it will return as soon as an error is detected while validating // CHLO. bool FLAGS_use_early_return_when_verifying_chlo = true; @@ -44,3 +35,6 @@ bool FLAGS_send_quic_crypto_reject_reason = false; // packets, to reduce latency of data delivery to the application. The client // must also request FEC protection for the server to use FEC. bool FLAGS_enable_quic_fec = false; + +// If true, a QUIC connection with too many unfinished streams will be closed. +bool FLAGS_close_quic_connection_unfinished_streams = false; diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index f9654af..c68b822 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h @@ -9,12 +9,11 @@ NET_EXPORT_PRIVATE extern bool FLAGS_track_retransmission_history; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_pacing; -NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_connection_flow_control_2; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_port_migration; NET_EXPORT_PRIVATE extern bool FLAGS_use_early_return_when_verifying_chlo; NET_EXPORT_PRIVATE extern bool FLAGS_send_quic_crypto_reject_reason; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_fec; +NET_EXPORT_PRIVATE extern bool FLAGS_close_quic_connection_unfinished_streams; #endif // NET_QUIC_QUIC_FLAGS_H_ diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc index 9d09031..855d165 100644 --- a/net/quic/quic_flow_controller.cc +++ b/net/quic/quic_flow_controller.cc @@ -179,12 +179,7 @@ void QuicFlowController::Disable() { } bool QuicFlowController::IsEnabled() const { - bool connection_flow_control_enabled = - (id_ == kConnectionLevelId && - FLAGS_enable_quic_connection_flow_control_2); - bool stream_flow_control_enabled = (id_ != kConnectionLevelId); - return (connection_flow_control_enabled || stream_flow_control_enabled) && - is_enabled_; + return is_enabled_; } bool QuicFlowController::IsBlocked() const { diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 41ed0b8..dc94b86 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -526,7 +526,7 @@ class NET_EXPORT_PRIVATE QuicFramer { bool is_server_; // If false, skip validation that the public flags are set to legal values. bool validate_flags_; - // The time this frames was created. Time written to the wire will be + // The time this framer was created. Time written to the wire will be // written as a delta from this value. QuicTime creation_time_; diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 9b9401b..60aad46 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -46,7 +46,7 @@ const size_t kVersionOffset = kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID; // Size in bytes of the stream frame fields for an arbitrary StreamID and // offset and the last frame in a packet. -size_t GetMinStreamFrameSize(QuicVersion version) { +size_t GetMinStreamFrameSize() { return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize; } @@ -461,8 +461,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> { size_t stream_id_size, bool include_version) { // Now test framing boundaries - for (size_t i = kQuicFrameTypeSize; - i < GetMinStreamFrameSize(framer_.version()); ++i) { + for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) { string expected_error; if (i < kQuicFrameTypeSize + stream_id_size) { expected_error = "Unable to read stream_id."; diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc index 94f90c6..f2265ce 100644 --- a/net/quic/quic_headers_stream_test.cc +++ b/net/quic/quic_headers_stream_test.cc @@ -4,7 +4,6 @@ #include "net/quic/quic_headers_stream.h" -#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/quic_connection_peer.h" @@ -326,8 +325,6 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { } TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); if (connection_->version() <= QUIC_VERSION_20) { EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled()); } else { diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index c587c56..419820a 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -169,6 +169,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { return MakeQuicTag('Q', '0', '2', '0'); case QUIC_VERSION_21: return MakeQuicTag('Q', '0', '2', '1'); + case QUIC_VERSION_22: + return MakeQuicTag('Q', '0', '2', '2'); default: // This shold be an ERROR because we should never attempt to convert an // invalid QuicVersion to be written to the wire. @@ -200,6 +202,7 @@ string QuicVersionToString(const QuicVersion version) { RETURN_STRING_LITERAL(QUIC_VERSION_19); RETURN_STRING_LITERAL(QUIC_VERSION_20); RETURN_STRING_LITERAL(QUIC_VERSION_21); + RETURN_STRING_LITERAL(QUIC_VERSION_22); default: return "QUIC_VERSION_UNSUPPORTED"; } diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index d95df71..d91b55f 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -281,6 +281,7 @@ enum QuicVersion { QUIC_VERSION_19 = 19, // Connection level flow control. QUIC_VERSION_20 = 20, // Independent stream/connection flow control windows. QUIC_VERSION_21 = 21, // Headers/crypto streams are flow controlled. + QUIC_VERSION_22 = 22, // Send Server Config Update messages on crypto stream. }; // This vector contains QUIC versions which we currently support. @@ -290,7 +291,8 @@ enum QuicVersion { // // IMPORTANT: if you are adding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions -static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_21, +static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_22, + QUIC_VERSION_21, QUIC_VERSION_20, QUIC_VERSION_19, QUIC_VERSION_18, @@ -443,6 +445,8 @@ enum QuicErrorCode { QUIC_INVALID_PRIORITY = 49, // Too many streams already open. QUIC_TOO_MANY_OPEN_STREAMS = 18, + // The peer must send a FIN/RST for each stream, and has not been doing so. + QUIC_TOO_MANY_UNFINISHED_STREAMS = 66, // Received public reset for this connection. QUIC_PUBLIC_RESET = 19, // Invalid protocol version. @@ -533,7 +537,7 @@ enum QuicErrorCode { QUIC_VERSION_NEGOTIATION_MISMATCH = 55, // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 66, + QUIC_LAST_ERROR = 67, }; struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index f233d8b..a0ce684 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -87,7 +87,8 @@ QuicSentPacketManager::QuicSentPacketManager( consecutive_crypto_retransmission_count_(0), pending_tlp_transmission_(false), max_tail_loss_probes_(kDefaultMaxTailLossProbes), - using_pacing_(false) { + using_pacing_(false), + handshake_confirmed_(false) { } QuicSentPacketManager::~QuicSentPacketManager() { @@ -606,7 +607,9 @@ bool QuicSentPacketManager::MaybeRetransmitTailLossProbe() { if (!it->second.in_flight || frames == NULL) { continue; } - DCHECK_NE(IS_HANDSHAKE, frames->HasCryptoHandshake()); + if (!handshake_confirmed_) { + DCHECK_NE(IS_HANDSHAKE, frames->HasCryptoHandshake()); + } MarkForRetransmission(sequence_number, TLP_RETRANSMISSION); return true; } @@ -652,7 +655,7 @@ void QuicSentPacketManager::RetransmitAllPackets() { QuicSentPacketManager::RetransmissionTimeoutMode QuicSentPacketManager::GetRetransmissionMode() const { DCHECK(unacked_packets_.HasInFlightPackets()); - if (unacked_packets_.HasPendingCryptoPackets()) { + if (!handshake_confirmed_ && unacked_packets_.HasPendingCryptoPackets()) { return HANDSHAKE_MODE; } if (loss_algorithm_->GetLossTimeout() != QuicTime::Zero()) { diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 1bedf5a..3ace014 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -111,6 +111,8 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { virtual void SetFromConfig(const QuicConfig& config); + void SetHandshakeConfirmed() { handshake_confirmed_ = true; } + // Called when a new packet is serialized. If the packet contains // retransmittable data, it will be added to the unacked packet map. void OnSerializedPacket(const SerializedPacket& serialized_packet); @@ -362,6 +364,12 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { SendAlgorithmInterface::CongestionMap packets_acked_; SendAlgorithmInterface::CongestionMap packets_lost_; + // Set to true after the crypto handshake has successfully completed. After + // this is true we no longer use HANDSHAKE_MODE, and further frames sent on + // the crypto stream (i.e. SCUP messages) are treated like normal + // retransmittable frames. + bool handshake_confirmed_; + DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager); }; diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 4c8f50d..f227727 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -262,8 +262,7 @@ void QuicSession::OnWindowUpdateFrames( DVLOG(1) << ENDPOINT << "Received connection level flow control window update with " "byte offset: " << frames[i].byte_offset; - if (FLAGS_enable_quic_connection_flow_control_2 && - flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) { + if (flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) { connection_window_updated = true; } continue; @@ -428,10 +427,15 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, // of the how many bytes the stream's flow controller believes it has // received, for accurate connection level flow control accounting. if (!stream->HasFinalReceivedByteOffset() && - stream->flow_controller()->IsEnabled() && - FLAGS_enable_quic_connection_flow_control_2) { + stream->flow_controller()->IsEnabled()) { locally_closed_streams_highest_offset_[stream_id] = stream->flow_controller()->highest_received_byte_offset(); + if (FLAGS_close_quic_connection_unfinished_streams && + connection()->connected() && + locally_closed_streams_highest_offset_.size() > max_open_streams_) { + // A buggy client may fail to send FIN/RSTs. Don't tolerate this. + connection_->SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS); + } } stream_map_.erase(it); @@ -440,10 +444,6 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset( QuicStreamId stream_id, QuicStreamOffset final_byte_offset) { - if (!FLAGS_enable_quic_connection_flow_control_2) { - return; - } - map<QuicStreamId, QuicStreamOffset>::iterator it = locally_closed_streams_highest_offset_.find(stream_id); if (it == locally_closed_streams_highest_offset_.end()) { diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 83f2447..b604a7f 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -531,8 +531,6 @@ TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Ensure connection level flow control blockage. QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0); EXPECT_TRUE(session_.flow_controller()->IsBlocked()); @@ -711,8 +709,6 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Test that when we receive an out of order stream RST we correctly adjust // our connection level flow control receive window. // On close, the stream should mark as consumed all bytes between the highest @@ -741,8 +737,6 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Test the situation where we receive a FIN on a stream, and before we fully // consume all the data from the sequencer buffer we locally RST the stream. // The bytes between highest consumed byte, and the final byte offset that we @@ -789,8 +783,6 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAfterRst) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Connection starts with some non-zero highest received byte offset, // due to other active streams. const uint64 kInitialConnectionBytesConsumed = 567; @@ -833,8 +825,6 @@ TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstAfterRst) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Connection starts with some non-zero highest received byte offset, // due to other active streams. const uint64 kInitialConnectionBytesConsumed = 567; @@ -869,8 +859,6 @@ TEST_P(QuicSessionTest, FlowControlWithInvalidFinalOffset) { if (version() <= QUIC_VERSION_16) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); const uint64 kLargeOffset = kInitialSessionFlowControlWindowForTest + 1; EXPECT_CALL(*connection_, @@ -896,8 +884,6 @@ TEST_P(QuicSessionTest, VersionNegotiationDisablesFlowControl) { return; } - ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control_2, - true); // Test that after successful version negotiation, flow control is disabled // appropriately at both the connection and stream level. @@ -918,6 +904,35 @@ TEST_P(QuicSessionTest, VersionNegotiationDisablesFlowControl) { EXPECT_FALSE(stream->flow_controller()->IsEnabled()); } +TEST_P(QuicSessionTest, TooManyUnfinishedStreamsCauseConnectionClose) { + if (version() < QUIC_VERSION_18) { + return; + } + // If a buggy/malicious peer creates too many streams that are not ended with + // a FIN or RST then we send a connection close. + ValueRestore<bool> old_flag(&FLAGS_close_quic_connection_unfinished_streams, + true); + + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS)).Times(1); + + const int kMaxStreams = 5; + QuicSessionPeer::SetMaxOpenStreams(&session_, kMaxStreams); + + // Create kMaxStreams + 1 data streams, and close them all without receiving a + // FIN or a RST from the client. + const int kFirstStreamId = kClientDataStreamId1; + const int kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams + 1; + for (int i = kFirstStreamId; i < kFinalStreamId; i += 2) { + QuicStreamFrame data1(i, false, 0, MakeIOVector("HT")); + vector<QuicStreamFrame> frames; + frames.push_back(data1); + session_.OnStreamFrames(frames); + EXPECT_EQ(1u, session_.GetNumOpenStreams()); + session_.CloseStream(i); + } +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 87ec18c..8956fa2 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -191,6 +191,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID); RETURN_STRING_LITERAL(QUIC_INVALID_PRIORITY); RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS); + RETURN_STRING_LITERAL(QUIC_TOO_MANY_UNFINISHED_STREAMS); RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET); RETURN_STRING_LITERAL(QUIC_INVALID_VERSION); RETURN_STRING_LITERAL(QUIC_INVALID_HEADER_ID); diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index f25011d..f188783 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -6,7 +6,6 @@ #include "net/quic/quic_ack_notifier.h" #include "net/quic/quic_connection.h" -#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" @@ -471,9 +470,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) { // Set a large flow control send window so this doesn't interfere with test. stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); - if (FLAGS_enable_quic_connection_flow_control_2) { - session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); - } + session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate; @@ -526,9 +523,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) { // Set a large flow control send window so this doesn't interfere with test. stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); - if (FLAGS_enable_quic_connection_flow_control_2) { - session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); - } + session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1); scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate; @@ -634,9 +629,6 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) { // as we check for violation and close the connection early. TEST_F(ReliableQuicStreamTest, StreamSequencerNeverSeesPacketsViolatingFlowControl) { - ValueRestore<bool> old_connection_flag( - &FLAGS_enable_quic_connection_flow_control_2, true); - Initialize(kShouldProcessData); // Receive a stream frame that violates flow control: the byte offset is diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 0e3a815..86ff642 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc @@ -62,9 +62,9 @@ class CryptoFramerVisitor : public CryptoFramerVisitorInterface { }; // MovePackets parses crypto handshake messages from packet number -// |*inout_packet_index| through to the last packet and has |dest_stream| -// process them. |*inout_packet_index| is updated with an index one greater -// than the last packet processed. +// |*inout_packet_index| through to the last packet (or until a packet fails to +// decrypt) and has |dest_stream| process them. |*inout_packet_index| is updated +// with an index one greater than the last packet processed. void MovePackets(PacketSavingConnection* source_conn, size_t *inout_packet_index, QuicCryptoStream* dest_stream, @@ -84,7 +84,12 @@ void MovePackets(PacketSavingConnection* source_conn, size_t index = *inout_packet_index; for (; index < source_conn->encrypted_packets_.size(); index++) { - ASSERT_TRUE(framer.ProcessPacket(*source_conn->encrypted_packets_[index])); + if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) { + // The framer will be unable to decrypt forward-secure packets sent after + // the handshake is complete. Don't treat them as handshake packets. + break; + } + for (vector<QuicStreamFrame>::const_iterator i = framer.stream_frames().begin(); i != framer.stream_frames().end(); ++i) { diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 1243e34..fe1bbd1 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -197,9 +197,6 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> { FLAGS_enable_quic_pacing = GetParam().use_pacing; FLAGS_enable_quic_fec = GetParam().use_fec; - if (negotiated_version_ >= QUIC_VERSION_19) { - FLAGS_enable_quic_connection_flow_control_2 = true; - } VLOG(1) << "Using Configuration: " << GetParam(); client_config_.SetDefaults(); @@ -1165,8 +1162,6 @@ TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) { // Tests that the client's port can change during an established QUIC // connection, and that doing so does not result in the connection being // closed by the server. - FLAGS_quic_allow_port_migration = true; - ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 9980674..cf3a46b 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc @@ -169,7 +169,6 @@ QuicDispatcher::QuicDispatcher(const QuicConfig& config, epoll_server_(epoll_server), helper_(new QuicEpollConnectionHelper(epoll_server_)), supported_versions_(supported_versions), - supported_versions_no_connection_flow_control_(supported_versions), current_packet_(NULL), framer_(supported_versions, /*unused*/ QuicTime::Zero(), true), framer_visitor_(new QuicFramerVisitor(this)) { @@ -185,18 +184,6 @@ void QuicDispatcher::Initialize(int fd) { DCHECK(writer_ == NULL); writer_.reset(CreateWriter(fd)); time_wait_list_manager_.reset(CreateQuicTimeWaitListManager()); - - // Remove all versions > QUIC_VERSION_18 from the - // supported_versions_no_connection_flow_control_ vector. - QuicVersionVector::iterator connection_it = find( - supported_versions_no_connection_flow_control_.begin(), - supported_versions_no_connection_flow_control_.end(), QUIC_VERSION_19); - if (connection_it != supported_versions_no_connection_flow_control_.end()) { - supported_versions_no_connection_flow_control_.erase( - supported_versions_no_connection_flow_control_.begin(), - connection_it + 1); - } - CHECK(!supported_versions_no_connection_flow_control_.empty()); } void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, @@ -376,26 +363,13 @@ QuicConnection* QuicDispatcher::CreateQuicConnection( QuicConnectionId connection_id, const IPEndPoint& server_address, const IPEndPoint& client_address) { - if (FLAGS_enable_quic_connection_flow_control_2) { - DLOG(INFO) << "Creating QuicDispatcher with all versions."; - return new QuicConnection(connection_id, - client_address, - helper_.get(), - writer_.get(), - false /* owns_writer */, - true /* is_server */, - supported_versions_); - } - - DLOG(INFO) << "Connection flow control disabled, creating QuicDispatcher " - << "WITHOUT version 19 or higher."; return new QuicConnection(connection_id, client_address, helper_.get(), writer_.get(), false /* owns_writer */, true /* is_server */, - supported_versions_no_connection_flow_control_); + supported_versions_); } QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 088de31..8d7b03b 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h @@ -144,11 +144,6 @@ class QuicDispatcher : public QuicServerSessionVisitor, return supported_versions_; } - const QuicVersionVector& supported_versions_no_connection_flow_control() - const { - return supported_versions_no_connection_flow_control_; - } - const IPEndPoint& current_server_address() { return current_server_address_; } @@ -215,14 +210,6 @@ class QuicDispatcher : public QuicServerSessionVisitor, // skipped as necessary). const QuicVersionVector supported_versions_; - // Versions which do not support *connection* flow control (introduced in - // QUIC_VERSION_19). - // This is used to construct new QuicConnections when connection flow control - // is disabled via flag. - // TODO(rjshade): Remove this when - // FLAGS_enable_quic_connection_flow_control_2 is removed. - QuicVersionVector supported_versions_no_connection_flow_control_; - // Information about the packet currently being handled. IPEndPoint current_client_address_; IPEndPoint current_server_address_; |