summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 11:13:49 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 11:15:20 +0000
commit9693157b613011ae67a34bd954f87b9afe24039e (patch)
tree9c3c2af865947fe2e2766c0cb7d102c4ec8d2446
parentf250fa5dd72b9f7368f7853a02382f0d6f971bc7 (diff)
downloadchromium_src-9693157b613011ae67a34bd954f87b9afe24039e.zip
chromium_src-9693157b613011ae67a34bd954f87b9afe24039e.tar.gz
chromium_src-9693157b613011ae67a34bd954f87b9afe24039e.tar.bz2
Land Recent QUIC Changes.
A fix to QUIC's test only SendAlgorithmSimulator to ensure it treats lost packets correctly. Merge internal change: 72754445 https://codereview.chromium.org/450043002/ Check return value of GetStringPiece for (optional) kCCRT/kCCS in QuicCryptoServerConfig. Merge internal change: 72727018 https://codereview.chromium.org/453693002/ Store client cert hashes as strings instead of StringPieces. Avoids use-after-free (detected by ASAN) when the CHLO callback deletes the CHLO request, and subsequently we try to access the stored StringPieces. Bug introduced in CL: https://codereview.chromium.org/449273002/ Merge internal change: 72724874 https://codereview.chromium.org/453663002/ Deprecate rolled out flag: FLAGS_quic_allow_port_migration. Merge internal change: 72668120 https://codereview.chromium.org/451903002/ Along with sending the SCUP message, this CL includes small fixes which allow messages to be sent on the crypto stream after handshake has completed. This includes disabling HANDSHAKE_MODE in the sent packet manager after the handshake is confirmed, and stopping processing of handshake packets once we switch to forward secure and can no longer decrypt them in crypto_test_utils. Without a version bump, out of date clients will tear down the connection if they get a SCUP message from the server. QUIC_VERSION_22. Send a new source-address token when crypto handshake completes. Merge internal change: 72652054 https://codereview.chromium.org/449273002/ Trigger internal QUIC "trace graph" trace dumping also in cases where connection termination is initiated by the server. Protected by existing debug flag. This CL adds a new OnConnectionClosed method to the ConnectionDebugVisitor interface, which is called when the connection is closed irrespective of how the connection is closed. Merge internal change: 72571464 https://codereview.chromium.org/454563002/ Close a QUIC connection if there are too many unfinished streams being tracked in the locally closed map. Protected behind FLAGS_close_quic_connection_unfinished_streams (defaults to false). Merge internal change: 72561976 https://codereview.chromium.org/448973002/ Remove unused version argument from QuicFramerTest's GetMinStreamFrameSize. Merge internal change: 72559549 https://codereview.chromium.org/447103002/ Fix typo in comment in QuicFramer. creation_time_ is the creation time of the framer, not the frames. Comment only change. Merge internal change: 72558804 https://codereview.chromium.org/444323002/ Deprecate rolled out FLAGS_enable_quic_connection_flow_control_2. Merge internal change: 72345333 https://codereview.chromium.org/444313002/ R=rch@chromium.org Review URL: https://codereview.chromium.org/448313003 Cr-Commit-Position: refs/heads/master@{#288331} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288331 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/quic/congestion_control/send_algorithm_simulator.cc21
-rw-r--r--net/quic/congestion_control/send_algorithm_simulator.h9
-rw-r--r--net/quic/crypto/crypto_handshake.cc3
-rw-r--r--net/quic/crypto/crypto_handshake.h7
-rw-r--r--net/quic/crypto/quic_crypto_client_config.cc7
-rw-r--r--net/quic/crypto/quic_crypto_server_config.cc65
-rw-r--r--net/quic/crypto/quic_crypto_server_config.h9
-rw-r--r--net/quic/quic_connection.cc15
-rw-r--r--net/quic/quic_connection.h8
-rw-r--r--net/quic/quic_connection_logger.h2
-rw-r--r--net/quic/quic_crypto_client_stream.cc1
-rw-r--r--net/quic/quic_crypto_server_stream.cc54
-rw-r--r--net/quic/quic_crypto_server_stream.h40
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc2
-rw-r--r--net/quic/quic_crypto_stream.cc8
-rw-r--r--net/quic/quic_crypto_stream.h4
-rw-r--r--net/quic/quic_crypto_stream_test.cc3
-rw-r--r--net/quic/quic_data_stream_test.cc6
-rw-r--r--net/quic/quic_dispatcher.cc43
-rw-r--r--net/quic/quic_dispatcher.h13
-rw-r--r--net/quic/quic_flags.cc12
-rw-r--r--net/quic/quic_flags.h3
-rw-r--r--net/quic/quic_flow_controller.cc7
-rw-r--r--net/quic/quic_framer.h2
-rw-r--r--net/quic/quic_framer_test.cc5
-rw-r--r--net/quic/quic_headers_stream_test.cc3
-rw-r--r--net/quic/quic_protocol.cc3
-rw-r--r--net/quic/quic_protocol.h8
-rw-r--r--net/quic/quic_sent_packet_manager.cc9
-rw-r--r--net/quic/quic_sent_packet_manager.h8
-rw-r--r--net/quic/quic_session.cc16
-rw-r--r--net/quic/quic_session_test.cc43
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/quic/reliable_quic_stream_test.cc12
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc13
-rw-r--r--net/tools/quic/end_to_end_test.cc5
-rw-r--r--net/tools/quic/quic_dispatcher.cc28
-rw-r--r--net/tools/quic/quic_dispatcher.h13
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_;