summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc8
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h2
-rw-r--r--net/quic/congestion_control/pacing_sender.cc22
-rw-r--r--net/quic/congestion_control/pacing_sender.h4
-rw-r--r--net/quic/congestion_control/pacing_sender_test.cc88
-rw-r--r--net/quic/congestion_control/rtt_stats.cc2
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h9
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc12
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h4
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc5
-rw-r--r--net/quic/crypto/crypto_protocol.h1
-rw-r--r--net/quic/crypto/quic_crypto_client_config.cc70
-rw-r--r--net/quic/crypto/quic_crypto_client_config.h23
-rw-r--r--net/quic/crypto/quic_crypto_server_config.cc10
-rw-r--r--net/quic/quic_client_session.cc37
-rw-r--r--net/quic/quic_client_session.h10
-rw-r--r--net/quic/quic_client_session_test.cc10
-rw-r--r--net/quic/quic_connection.cc1
-rw-r--r--net/quic/quic_connection_stats.cc4
-rw-r--r--net/quic/quic_connection_stats.h1
-rw-r--r--net/quic/quic_connection_test.cc12
-rw-r--r--net/quic/quic_crypto_client_stream.cc44
-rw-r--r--net/quic/quic_crypto_client_stream.h4
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc61
-rw-r--r--net/quic/quic_crypto_stream.cc5
-rw-r--r--net/quic/quic_http_stream_test.cc9
-rw-r--r--net/quic/quic_protocol.h4
-rw-r--r--net/quic/quic_sent_packet_manager.cc34
-rw-r--r--net/quic/quic_sent_packet_manager.h23
-rw-r--r--net/quic/quic_server_session.cc1
-rw-r--r--net/quic/quic_session.cc3
-rw-r--r--net/quic/quic_session.h1
-rw-r--r--net/quic/quic_session_test.cc4
-rw-r--r--net/quic/quic_stream_factory.cc8
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc3
-rw-r--r--net/quic/test_tools/quic_test_utils.cc11
-rw-r--r--net/quic/test_tools/quic_test_utils.h2
-rw-r--r--net/tools/quic/quic_client.cc5
-rw-r--r--net/tools/quic/quic_client_session.cc27
-rw-r--r--net/tools/quic/quic_client_session.h10
-rw-r--r--net/tools/quic/quic_client_session_test.cc7
-rw-r--r--net/tools/quic/quic_server_session.cc1
-rw-r--r--net/tools/quic/quic_spdy_client_stream_test.cc8
-rw-r--r--net/tools/quic/test_tools/quic_test_utils.cc5
45 files changed, 496 insertions, 120 deletions
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index ac5b46f5..73482cc 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -101,4 +101,12 @@ QuicByteCount FixRateSender::GetCongestionWindow() const {
return 0;
}
+bool FixRateSender::InSlowStart() const {
+ return false;
+}
+
+QuicByteCount FixRateSender::GetSlowStartThreshold() const {
+ return 0;
+}
+
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index dbf506b..c50d8a9 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -50,6 +50,8 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
virtual bool HasReliableBandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
+ virtual bool InSlowStart() const OVERRIDE;
+ virtual QuicByteCount GetSlowStartThreshold() const OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 405afdaa..f0f0e5d 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -41,10 +41,6 @@ void PacingSender::OnCongestionEvent(bool rtt_updated,
if (rtt_updated) {
has_valid_rtt_ = true;
}
- if (bytes_in_flight == 0) {
- // Add more burst tokens anytime the connection is entering quiescence.
- burst_tokens_ = initial_packet_burst_;
- }
sender_->OnCongestionEvent(
rtt_updated, bytes_in_flight, acked_packets, lost_packets);
}
@@ -71,9 +67,9 @@ bool PacingSender::OnPacketSent(
}
// The next packet should be sent as soon as the current packets has
// been transferred. We pace at twice the rate of the underlying
- // sender's bandwidth estimate to help ensure that pacing doesn't become
- // a bottleneck.
- const float kPacingAggression = 2;
+ // sender's bandwidth estimate during slow start and 1.25x during congestion
+ // avoidance to ensure pacing doesn't prevent us from filling the window.
+ const float kPacingAggression = sender_->InSlowStart() ? 2 : 1.25;
QuicTime::Delta delay =
BandwidthEstimate().Scale(kPacingAggression).TransferTime(bytes);
// If the last send was delayed, and the alarm took a long time to get
@@ -121,6 +117,10 @@ QuicTime::Delta PacingSender::TimeUntilSend(
// Don't pace if we don't have an updated RTT estimate.
return time_until_send;
}
+ if (bytes_in_flight == 0) {
+ // Add more burst tokens anytime the connection is entering quiescence.
+ burst_tokens_ = initial_packet_burst_;
+ }
if (burst_tokens_ > 0) {
// Don't pace if we have burst tokens available.
return time_until_send;
@@ -166,4 +166,12 @@ QuicByteCount PacingSender::GetCongestionWindow() const {
return sender_->GetCongestionWindow();
}
+bool PacingSender::InSlowStart() const {
+ return sender_->InSlowStart();
+}
+
+QuicByteCount PacingSender::GetSlowStartThreshold() const {
+ return sender_->GetSlowStartThreshold();
+}
+
} // namespace net
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index 9230635..b85946c 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -58,12 +58,14 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
virtual bool HasReliableBandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
+ virtual bool InSlowStart() const OVERRIDE;
+ virtual QuicByteCount GetSlowStartThreshold() const OVERRIDE;
private:
scoped_ptr<SendAlgorithmInterface> sender_; // Underlying sender.
QuicTime::Delta alarm_granularity_;
uint32 initial_packet_burst_;
- uint32 burst_tokens_;
+ mutable uint32 burst_tokens_;
// Send time of the last packet considered delayed.
QuicTime last_delayed_packet_sent_time_;
QuicTime next_packet_send_time_; // When can the next packet be sent.
diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc
index ba867b5..026905d 100644
--- a/net/quic/congestion_control/pacing_sender_test.cc
+++ b/net/quic/congestion_control/pacing_sender_test.cc
@@ -133,6 +133,9 @@ TEST_F(PacingSenderTest, SendNow) {
}
TEST_F(PacingSenderTest, VariousSending) {
+ // Start the test in slow start.
+ EXPECT_CALL(*mock_sender_, InSlowStart()).WillRepeatedly(Return(true));
+
// Configure bandwith of 1 packet per 2 ms, for which the pacing rate
// will be 1 packet per 1 ms.
EXPECT_CALL(*mock_sender_, BandwidthEstimate())
@@ -204,12 +207,82 @@ TEST_F(PacingSenderTest, VariousSending) {
CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
}
+TEST_F(PacingSenderTest, CongestionAvoidanceSending) {
+ // Start the test in congestion avoidance.
+ EXPECT_CALL(*mock_sender_, InSlowStart()).WillRepeatedly(Return(false));
+
+ // Configure bandwith of 1 packet per 2 ms, for which the pacing rate
+ // will be 1 packet per 1 ms.
+ EXPECT_CALL(*mock_sender_, BandwidthEstimate())
+ .WillRepeatedly(Return(QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(2))));
+
+ // Send a whole pile of packets, and verify that they are not paced.
+ for (int i = 0 ; i < 1000; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // Now update the RTT and verify that packets are actually paced.
+ EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytesInFlight, _, _));
+ SendAlgorithmInterface::CongestionMap empty_map;
+ pacing_sender_->OnCongestionEvent(true, kBytesInFlight, empty_map, empty_map);
+
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2200us.
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2200));
+
+ // Wake up on time.
+ clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(2200));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1600));
+ CheckAckIsSentImmediately();
+
+ // Wake up late.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(4));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2400));
+
+ // Wake up really late.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2400));
+
+ // Wake up really late again, but application pause partway through.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2200));
+
+ // Wake up too early.
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2200));
+
+ // Wake up early, but after enough time has passed to permit a send.
+ clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1200));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(2600));
+}
+
TEST_F(PacingSenderTest, InitialBurst) {
pacing_sender_.reset();
mock_sender_ = new StrictMock<MockSendAlgorithm>();
pacing_sender_.reset(new PacingSender(mock_sender_,
QuicTime::Delta::FromMilliseconds(1),
10));
+ // Start the test in slow start.
+ EXPECT_CALL(*mock_sender_, InSlowStart()).WillRepeatedly(Return(true));
// Configure bandwith of 1 packet per 2 ms, for which the pacing rate
// will be 1 packet per 1 ms.
@@ -237,10 +310,17 @@ TEST_F(PacingSenderTest, InitialBurst) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
CheckPacketIsSentImmediately();
- // Now reduce bytes in flight back to 0 by and ensure another burst of 10 can
- // be sent.
- EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, 0, _, _));
- pacing_sender_->OnCongestionEvent(true, 0, empty_map, empty_map);
+ // Next time TimeUntilSend is called with no bytes in flight, the tokens
+ // should be refilled and there should be no delay.
+ EXPECT_CALL(*mock_sender_,
+ TimeUntilSend(clock_.Now(),
+ 0,
+ HAS_RETRANSMITTABLE_DATA)).
+ WillOnce(Return(zero_time_));
+ EXPECT_EQ(zero_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(),
+ 0,
+ HAS_RETRANSMITTABLE_DATA));
for (int i = 0 ; i < 10; ++i) {
CheckPacketIsSentImmediately();
}
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc
index 3225d9f..e70d2d9 100644
--- a/net/quic/congestion_control/rtt_stats.cc
+++ b/net/quic/congestion_control/rtt_stats.cc
@@ -83,7 +83,7 @@ void RttStats::UpdateRtt(QuicTime::Delta send_delta,
kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds()));
smoothed_rtt_ = smoothed_rtt_.Multiply(kOneMinusAlpha).Add(
rtt_sample.Multiply(kAlpha));
- DVLOG(1) << "Cubic; smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
+ DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
<< " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
}
}
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 98437ff..9633ecd 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -92,6 +92,15 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// not the *available* window. Some send algorithms may not use a congestion
// window and will return 0.
virtual QuicByteCount GetCongestionWindow() const = 0;
+
+ // Whether the send algorithm is currently in slow start. When true, the
+ // BandwidthEstimate is expected to be too low.
+ virtual bool InSlowStart() const = 0;
+
+ // Returns the size of the slow start congestion window in bytes,
+ // aka ssthresh. Some send algorithms do not define a slow start
+ // threshold and will return 0.
+ virtual QuicByteCount GetSlowStartThreshold() const = 0;
};
} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 95fa6cc..80f07f5 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -57,10 +57,6 @@ TcpCubicSender::~TcpCubicSender() {
UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
}
-bool TcpCubicSender::InSlowStart() const {
- return congestion_window_ < slowstart_threshold_;
-}
-
void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) {
if (is_server && config.HasReceivedInitialCongestionWindow()) {
// Set the initial window size.
@@ -213,6 +209,14 @@ QuicByteCount TcpCubicSender::GetCongestionWindow() const {
return congestion_window_ * kMaxSegmentSize;
}
+bool TcpCubicSender::InSlowStart() const {
+ return congestion_window_ < slowstart_threshold_;
+}
+
+QuicByteCount TcpCubicSender::GetSlowStartThreshold() const {
+ return slowstart_threshold_ * kMaxSegmentSize;
+}
+
bool TcpCubicSender::IsCwndLimited(QuicByteCount bytes_in_flight) const {
const QuicByteCount congestion_window_bytes = congestion_window_ *
kMaxSegmentSize;
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 6f033e4..e682a62 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -37,8 +37,6 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
QuicConnectionStats* stats);
virtual ~TcpCubicSender();
- bool InSlowStart() const;
-
// Start implementation of SendAlgorithmInterface.
virtual void SetFromConfig(const QuicConfig& config, bool is_server) OVERRIDE;
virtual void OnIncomingQuicCongestionFeedbackFrame(
@@ -63,6 +61,8 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
virtual bool HasReliableBandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
+ virtual bool InSlowStart() const OVERRIDE;
+ virtual QuicByteCount GetSlowStartThreshold() const OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 8409f97..ef2e1c0 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -207,6 +207,9 @@ TEST_F(TcpCubicSenderTest, ExponentialSlowStart) {
}
TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
+ EXPECT_EQ(kDefaultMaxCongestionWindowTCP * kDefaultTCPMSS,
+ sender_->GetSlowStartThreshold());
+
// Make sure that we fall out of slow start when we send ACK train longer
// than half the RTT, in this test case 30ms, which is more than 30 calls to
// Ack2Packets in one round.
@@ -238,8 +241,10 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
}
SendAvailableSendWindow();
AckNPackets(2);
+ QuicByteCount expected_ss_tresh = expected_send_window;
expected_send_window += kDefaultTCPMSS;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ EXPECT_EQ(expected_ss_tresh, sender_->GetSlowStartThreshold());
EXPECT_EQ(140u, sender_->slowstart_threshold());
// Now RTO and ensure slow start gets reset.
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 07fe17c..9e38d4b 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -33,6 +33,7 @@ const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject
const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value
// pairs
const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset
+const QuicTag kSCUP = TAG('S', 'C', 'U', 'P'); // Server config update.
// Key exchange methods
const QuicTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index e045df5..33d5242 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -529,21 +529,16 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
return QUIC_NO_ERROR;
}
-QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
- const CryptoHandshakeMessage& rej,
+QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
+ const CryptoHandshakeMessage& message,
QuicWallTime now,
+ const vector<string>& cached_certs,
CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
string* error_details) {
DCHECK(error_details != NULL);
- if (rej.tag() != kREJ) {
- *error_details = "Message is not REJ";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
-
StringPiece scfg;
- if (!rej.GetStringPiece(kSCFG, &scfg)) {
+ if (!message.GetStringPiece(kSCFG, &scfg)) {
*error_details = "Missing SCFG";
return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
}
@@ -554,21 +549,16 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
}
StringPiece token;
- if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) {
+ if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
cached->set_source_address_token(token);
}
- StringPiece nonce;
- if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
- out_params->server_nonce = nonce.as_string();
- }
-
StringPiece proof, cert_bytes;
- bool has_proof = rej.GetStringPiece(kPROF, &proof);
- bool has_cert = rej.GetStringPiece(kCertificateTag, &cert_bytes);
+ bool has_proof = message.GetStringPiece(kPROF, &proof);
+ bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
if (has_proof && has_cert) {
vector<string> certs;
- if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs,
+ if (!CertCompressor::DecompressChain(cert_bytes, cached_certs,
common_cert_sets, &certs)) {
*error_details = "Certificate data invalid";
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
@@ -588,6 +578,33 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
}
}
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
+ const CryptoHandshakeMessage& rej,
+ QuicWallTime now,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ string* error_details) {
+ DCHECK(error_details != NULL);
+
+ if (rej.tag() != kREJ) {
+ *error_details = "Message is not REJ";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+
+ QuicErrorCode error = CacheNewServerConfig(rej, now, out_params->cached_certs,
+ cached, error_details);
+ if (error != QUIC_NO_ERROR) {
+ return error;
+ }
+
+ StringPiece nonce;
+ if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
+ out_params->server_nonce = nonce.as_string();
+ }
+
const uint32* reject_reasons;
size_t num_reject_reasons;
COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync);
@@ -686,6 +703,23 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
return QUIC_NO_ERROR;
}
+QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
+ const CryptoHandshakeMessage& server_config_update,
+ QuicWallTime now,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ string* error_details) {
+ DCHECK(error_details != NULL);
+
+ if (server_config_update.tag() != kSCUP) {
+ *error_details = "ServerConfigUpdate must have kSCUP tag.";
+ return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ }
+
+ return CacheNewServerConfig(server_config_update, now,
+ out_params->cached_certs, cached, error_details);
+}
+
ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
return proof_verifier_.get();
}
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 8aa4527..131e6da 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -208,6 +208,18 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
+ // Processes the message in |server_update|, updating the cached source
+ // address token, and server config.
+ // If |server_update| is invalid then |error_details| will contain an error
+ // message, and an error code will be returned. If all has gone well
+ // QUIC_NO_ERROR is returned.
+ QuicErrorCode ProcessServerConfigUpdate(
+ const CryptoHandshakeMessage& server_update,
+ QuicWallTime now,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ std::string* error_details);
+
ProofVerifier* proof_verifier() const;
// SetProofVerifier takes ownership of a |ProofVerifier| that clients are
@@ -255,6 +267,17 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
private:
typedef std::map<QuicServerId, CachedState*> CachedStateMap;
+ // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|,
+ // verifies them, and stores them in the cached state if they validate.
+ // This is used on receipt of a REJ from a server, or when a server sends
+ // updated server config during a connection.
+ QuicErrorCode CacheNewServerConfig(
+ const CryptoHandshakeMessage& message,
+ QuicWallTime now,
+ const std::vector<std::string>& cached_certs,
+ CachedState* cached,
+ std::string* error_details);
+
// If the suffix of the hostname in |server_id| is in |canoncial_suffixes_|,
// then populate |cached| with the canonical cached state from
// |canonical_server_map_| for that suffix.
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 6cd5b85..6bddf2b 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -174,10 +174,12 @@ class VerifyNonceIsValidAndUniqueCallback
case STRIKE_REGISTER_FAILURE:
client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE;
break;
- case NONCE_OK:
case NONCE_UNKNOWN_FAILURE:
+ client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
+ break;
+ case NONCE_OK:
default:
- LOG(WARNING) << "Unexpected nonce error: " << nonce_error;
+ LOG(DFATAL) << "Unexpected client nonce error: " << nonce_error;
client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
break;
}
@@ -1485,17 +1487,17 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
case NONCE_OK:
return HANDSHAKE_OK;
case NONCE_INVALID_FAILURE:
+ case NONCE_INVALID_ORBIT_FAILURE:
return SERVER_NONCE_INVALID_FAILURE;
case NONCE_NOT_UNIQUE_FAILURE:
return SERVER_NONCE_NOT_UNIQUE_FAILURE;
case NONCE_INVALID_TIME_FAILURE:
return SERVER_NONCE_INVALID_TIME_FAILURE;
case NONCE_UNKNOWN_FAILURE:
- case NONCE_INVALID_ORBIT_FAILURE:
case STRIKE_REGISTER_TIMEOUT:
case STRIKE_REGISTER_FAILURE:
default:
- LOG(WARNING) << "Unexpected nonce error: " << nonce_error;
+ LOG(DFATAL) << "Unexpected server nonce error: " << nonce_error;
return SERVER_NONCE_NOT_UNIQUE_FAILURE;
}
}
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index fce3bf7..fa6a211 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -132,21 +132,15 @@ void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
ResetAndReturn(&callback_).Run(rv);
}
-QuicClientSession::QuicClientSession(
- QuicConnection* connection,
- scoped_ptr<DatagramClientSocket> socket,
- scoped_ptr<QuicDefaultPacketWriter> writer,
- QuicStreamFactory* stream_factory,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory,
- scoped_ptr<QuicServerInfo> server_info,
- const QuicServerId& server_id,
- const QuicConfig& config,
- QuicCryptoClientConfig* crypto_config,
- base::TaskRunner* task_runner,
- NetLog* net_log)
- : QuicClientSessionBase(connection,
- config),
- server_host_port_(server_id.host_port_pair()),
+QuicClientSession::QuicClientSession(QuicConnection* connection,
+ scoped_ptr<DatagramClientSocket> socket,
+ scoped_ptr<QuicDefaultPacketWriter> writer,
+ QuicStreamFactory* stream_factory,
+ scoped_ptr<QuicServerInfo> server_info,
+ const QuicConfig& config,
+ base::TaskRunner* task_runner,
+ NetLog* net_log)
+ : QuicClientSessionBase(connection, config),
require_confirmation_(false),
stream_factory_(stream_factory),
socket_(socket.Pass()),
@@ -161,6 +155,15 @@ QuicClientSession::QuicClientSession(
num_packets_read_(0),
going_away_(false),
weak_factory_(this) {
+ connection->set_debug_visitor(&logger_);
+}
+
+void QuicClientSession::InitializeSession(
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
+ QuicClientSessionBase::InitializeSession();
+ server_host_port_.reset(new HostPortPair(server_id.host_port_pair()));
crypto_stream_.reset(
crypto_client_stream_factory ?
crypto_client_stream_factory->CreateQuicCryptoClientStream(
@@ -169,7 +172,6 @@ QuicClientSession::QuicClientSession(
new ProofVerifyContextChromium(net_log_),
crypto_config));
- connection->set_debug_visitor(&logger_);
// TODO(rch): pass in full host port proxy pair
net_log_.BeginEvent(
NetLog::TYPE_QUIC_SESSION,
@@ -437,6 +439,7 @@ int QuicClientSession::CryptoConnect(bool require_confirmation,
require_confirmation_ = require_confirmation;
handshake_start_ = base::TimeTicks::Now();
RecordHandshakeState(STATE_STARTED);
+ DCHECK(flow_controller());
if (!crypto_stream_->CryptoConnect()) {
// TODO(wtc): change crypto_stream_.CryptoConnect() to return a
// QuicErrorCode and map it to a net error code.
@@ -500,7 +503,7 @@ bool QuicClientSession::CanPool(const std::string& hostname) const {
if (ssl_info.channel_id_sent &&
ServerBoundCertService::GetDomainForHost(hostname) !=
- ServerBoundCertService::GetDomainForHost(server_host_port_.host())) {
+ ServerBoundCertService::GetDomainForHost(server_host_port_->host())) {
return false;
}
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index b46c0ab..eecebc6 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -94,15 +94,17 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase {
scoped_ptr<DatagramClientSocket> socket,
scoped_ptr<QuicDefaultPacketWriter> writer,
QuicStreamFactory* stream_factory,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory,
scoped_ptr<QuicServerInfo> server_info,
- const QuicServerId& server_id,
const QuicConfig& config,
- QuicCryptoClientConfig* crypto_config,
base::TaskRunner* task_runner,
NetLog* net_log);
virtual ~QuicClientSession();
+ void InitializeSession(
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* config,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory);
+
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -219,7 +221,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase {
void OnConnectTimeout();
- const HostPortPair server_host_port_;
+ scoped_ptr<HostPortPair> server_host_port_;
bool require_confirmation_;
scoped_ptr<QuicCryptoClientStream> crypto_stream_;
QuicStreamFactory* stream_factory_;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index f15e695..6b4e887 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -72,13 +72,13 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
: writer_(new TestPacketWriter(GetParam())),
connection_(
new PacketSavingConnection(false, SupportedVersions(GetParam()))),
- session_(connection_, GetSocket().Pass(), writer_.Pass(), NULL, NULL,
- make_scoped_ptr((QuicServerInfo*)NULL),
- QuicServerId(kServerHostname, kServerPort, false,
- PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(), &crypto_config_,
+ session_(connection_, GetSocket().Pass(), writer_.Pass(), NULL,
+ make_scoped_ptr((QuicServerInfo*)NULL), DefaultQuicConfig(),
base::MessageLoop::current()->message_loop_proxy().get(),
&net_log_) {
+ session_.InitializeSession(QuicServerId(kServerHostname, kServerPort, false,
+ PRIVACY_MODE_DISABLED),
+ &crypto_config_, NULL);
session_.config()->SetDefaults();
crypto_config_.SetDefaults();
}
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 9e1a7b3..199c407 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1069,6 +1069,7 @@ const QuicConnectionStats& QuicConnection::GetStats() {
stats_.estimated_bandwidth =
sent_packet_manager_.BandwidthEstimate().ToBytesPerSecond();
stats_.congestion_window = sent_packet_manager_.GetCongestionWindow();
+ stats_.slow_start_threshold = sent_packet_manager_.GetSlowStartThreshold();
stats_.max_packet_size = packet_generator_.max_packet_length();
return stats_;
}
diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc
index bf05386..7081d0d 100644
--- a/net/quic/quic_connection_stats.cc
+++ b/net/quic/quic_connection_stats.cc
@@ -32,7 +32,10 @@ QuicConnectionStats::QuicConnectionStats()
spurious_rto_count(0),
min_rtt_us(0),
srtt_us(0),
+ max_packet_size(0),
estimated_bandwidth(0),
+ congestion_window(0),
+ slow_start_threshold(0),
packets_reordered(0),
max_sequence_reordering(0),
max_time_reordering_us(0),
@@ -71,6 +74,7 @@ ostream& operator<<(ostream& os, const QuicConnectionStats& s) {
<< ", max packet size: " << s.max_packet_size
<< ", estimated bandwidth: " << s.estimated_bandwidth
<< ", congestion window: " << s.congestion_window
+ << ", slow start threshold: " << s.slow_start_threshold
<< ", tcp_loss_events: " << s.tcp_loss_events
<< ", packets reordered: " << s.packets_reordered
<< ", max sequence reordering: " << s.max_sequence_reordering
diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h
index b7f06f1..1cb8ca7 100644
--- a/net/quic/quic_connection_stats.h
+++ b/net/quic/quic_connection_stats.h
@@ -56,6 +56,7 @@ struct NET_EXPORT_PRIVATE QuicConnectionStats {
uint32 max_packet_size; // In bytes.
uint64 estimated_bandwidth; // In bytes per second.
uint32 congestion_window; // In bytes
+ uint32 slow_start_threshold; // In bytes
// Reordering stats for received packets.
// Number of packets received out of sequence number order.
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 563fa8d..746d6e1 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -3563,6 +3563,10 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(
Return(QuicBandwidth::Zero()));
+ const uint32 kSlowStartThreshold = 23u;
+ EXPECT_CALL(*send_algorithm_, GetSlowStartThreshold()).WillOnce(
+ Return(kSlowStartThreshold));
+
const QuicConnectionStats& stats = connection_.GetStats();
EXPECT_EQ(3 * first_packet_size + 2 * second_packet_size - kQuicVersionSize,
stats.bytes_sent);
@@ -3571,6 +3575,9 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
stats.bytes_retransmitted);
EXPECT_EQ(3u, stats.packets_retransmitted);
EXPECT_EQ(1u, stats.rto_count);
+ EXPECT_EQ(kMaxPacketSize, stats.congestion_window);
+ EXPECT_EQ(kSlowStartThreshold, stats.slow_start_threshold);
+ EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size);
}
TEST_P(QuicConnectionTest, CheckReceiveStats) {
@@ -3585,6 +3592,9 @@ TEST_P(QuicConnectionTest, CheckReceiveStats) {
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(
Return(QuicBandwidth::Zero()));
+ const uint32 kSlowStartThreshold = 23u;
+ EXPECT_CALL(*send_algorithm_, GetSlowStartThreshold()).WillOnce(
+ Return(kSlowStartThreshold));
const QuicConnectionStats& stats = connection_.GetStats();
EXPECT_EQ(received_bytes, stats.bytes_received);
@@ -3592,6 +3602,8 @@ TEST_P(QuicConnectionTest, CheckReceiveStats) {
EXPECT_EQ(1u, stats.packets_revived);
EXPECT_EQ(1u, stats.packets_dropped);
+
+ EXPECT_EQ(kSlowStartThreshold, stats.slow_start_threshold);
}
TEST_P(QuicConnectionTest, TestFecGroupLimits) {
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 19f3cec..64cb950 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -95,8 +95,28 @@ QuicCryptoClientStream::~QuicCryptoClientStream() {
void QuicCryptoClientStream::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
+ DVLOG(1) << "Client: Received " << message.DebugString();
+
QuicCryptoStream::OnHandshakeMessage(message);
+ if (message.tag() == kSCUP) {
+ if (!handshake_confirmed()) {
+ CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
+ return;
+ }
+
+ // |message| is an update from the server, so we treat it differently from a
+ // handshake message.
+ HandleServerConfigUpdateMessage(&message);
+ return;
+ }
+
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed()) {
+ CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
+ return;
+ }
+
DoHandshakeLoop(&message);
}
@@ -114,6 +134,26 @@ bool QuicCryptoClientStream::WasChannelIDSent() const {
return channel_id_sent_;
}
+void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
+ const CryptoHandshakeMessage* in) {
+ DCHECK(in->tag() == kSCUP);
+ string error_details;
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_->LookupOrCreate(server_id_);
+ QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
+ *in,
+ session()->connection()->clock()->WallNow(),
+ cached,
+ &crypto_negotiated_params_,
+ &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(
+ error, "Server config update invalid: " + error_details);
+ return;
+ }
+}
+
// kMaxClientHellos is the maximum number of times that we'll send a client
// hello. The value 3 accounts for:
// * One failure due to an incorrect or missing source-address token.
@@ -129,10 +169,6 @@ void QuicCryptoClientStream::DoHandshakeLoop(
QuicCryptoClientConfig::CachedState* cached =
crypto_config_->LookupOrCreate(server_id_);
- if (in != NULL) {
- DVLOG(1) << "Client: Received " << in->DebugString();
- }
-
for (;;) {
const State state = next_state_;
next_state_ = STATE_IDLE;
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index a0bfe06..eb8191a 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -104,6 +104,10 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
STATE_RECV_SHLO,
};
+ // Handles new server config and optional source-address token provided by the
+ // server during a connection.
+ void HandleServerConfigUpdateMessage(const CryptoHandshakeMessage* in);
+
// DoHandshakeLoop performs a step of the handshake state machine. Note that
// |in| may be NULL if the call did not result from a received message.
void DoHandshakeLoop(const CryptoHandshakeMessage* in);
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 3515d32..344dfe1 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -11,6 +11,7 @@
#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_server_id.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
@@ -140,6 +141,66 @@ TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
ASSERT_EQ(1u, connection_->packets_.size());
}
+TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
+ // Test that the crypto client stream can receive server config updates after
+ // the connection has been established.
+ CompleteCryptoHandshake();
+
+ QuicCryptoClientConfig::CachedState* state =
+ crypto_config_.LookupOrCreate(server_id_);
+
+ // Ensure cached STK is different to what we send in the handshake.
+ EXPECT_NE("xstk", state->source_address_token());
+
+ // Initialize using {...} syntax to avoid trailing \0 if converting from
+ // string.
+ unsigned char stk[] = { 'x', 's', 't', 'k' };
+
+ // Minimum SCFG that passes config validation checks.
+ unsigned char scfg[] = {
+ // SCFG
+ 0x53, 0x43, 0x46, 0x47,
+ // num entries
+ 0x01, 0x00,
+ // padding
+ 0x00, 0x00,
+ // EXPY
+ 0x45, 0x58, 0x50, 0x59,
+ // EXPY end offset
+ 0x08, 0x00, 0x00, 0x00,
+ // Value
+ '1', '2', '3', '4',
+ '5', '6', '7', '8'
+ };
+
+ CryptoHandshakeMessage server_config_update;
+ server_config_update.set_tag(kSCUP);
+ server_config_update.SetValue(kSourceAddressTokenTag, stk);
+ server_config_update.SetValue(kSCFG, scfg);
+
+ scoped_ptr<QuicData> data(
+ CryptoFramer::ConstructHandshakeMessage(server_config_update));
+ stream_->ProcessRawData(data->data(), data->length());
+
+ // Make sure that the STK and SCFG are cached correctly.
+ EXPECT_EQ("xstk", state->source_address_token());
+
+ string cached_scfg = state->server_config();
+ test::CompareCharArraysWithHexError(
+ "scfg", cached_scfg.data(), cached_scfg.length(),
+ QuicUtils::AsChars(scfg), arraysize(scfg));
+}
+
+TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
+ EXPECT_CALL(*connection_, SendConnectionClose(
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE));
+ CryptoHandshakeMessage server_config_update;
+ server_config_update.set_tag(kSCUP);
+ scoped_ptr<QuicData> data(
+ CryptoFramer::ConstructHandshakeMessage(server_config_update));
+ stream_->ProcessRawData(data->data(), data->length());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 870a3cf..36b7c45 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -43,11 +43,6 @@ void QuicCryptoStream::OnHandshakeMessage(
uint32 QuicCryptoStream::ProcessRawData(const char* data,
uint32 data_len) {
- // Do not process handshake messages after the handshake is confirmed.
- if (handshake_confirmed()) {
- CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
- return 0;
- }
if (!crypto_framer_.ProcessInput(StringPiece(data, data_len))) {
CloseConnection(crypto_framer_.error());
return 0;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index c0643d4..a4e3c98 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -208,14 +208,15 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
new QuicClientSession(connection_,
scoped_ptr<DatagramClientSocket>(socket),
writer_.Pass(), NULL,
- &crypto_client_stream_factory_,
make_scoped_ptr((QuicServerInfo*)NULL),
- QuicServerId(kServerHostname, kServerPort,
- false, PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(), &crypto_config_,
+ DefaultQuicConfig(),
base::MessageLoop::current()->
message_loop_proxy().get(),
NULL));
+ session_->InitializeSession(QuicServerId(kServerHostname, kServerPort,
+ false, PRIVACY_MODE_DISABLED),
+ &crypto_config_,
+ &crypto_client_stream_factory_);
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
stream_.reset(use_closing_stream_ ?
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 4c67efb..11ad238 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -528,12 +528,14 @@ enum QuicErrorCode {
// A handshake message arrived, but we are still validating the
// previous handshake message.
QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO = 54,
+ // A server config update arrived before the handshake is complete.
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE = 65,
// This connection involved a version negotiation which appears to have been
// tampered with.
QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 65,
+ QUIC_LAST_ERROR = 66,
};
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 5705c0b..b5ca9fe 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -20,6 +20,11 @@ using std::max;
using std::min;
namespace net {
+
+// The length of the recent min rtt window in seconds. Windowing is disabled for
+// values less than or equal to 0.
+int32 FLAGS_quic_recent_min_rtt_window_s = 60;
+
namespace {
static const int kDefaultRetransmissionTimeMs = 500;
// TCP RFC calls for 1 second RTO however Linux differs from this default and
@@ -44,6 +49,8 @@ static const size_t kNumMinRttSamplesAfterQuiescence = 2;
// Number of unpaced packets to send after quiescence.
static const size_t kInitialUnpacedBurst = 10;
+// Use a 1 minute window for Recent Min RTT with BBR.
+
bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
if (transmission_info.retransmittable_frames == NULL) {
return false;
@@ -91,6 +98,10 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
// TODO(ianswett): BBR is currently a server only feature.
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) {
+ if (FLAGS_quic_recent_min_rtt_window_s > 0) {
+ rtt_stats_.set_recent_min_rtt_window(
+ QuicTime::Delta::FromSeconds(FLAGS_quic_recent_min_rtt_window_s));
+ }
send_algorithm_.reset(
SendAlgorithmInterface::Create(clock_, &rtt_stats_, kTCPBBR, stats_));
}
@@ -144,6 +155,13 @@ void QuicSentPacketManager::OnRetransmittedPacket(
unacked_packets_.OnRetransmittedPacket(old_sequence_number,
new_sequence_number,
transmission_type);
+
+ if (debug_delegate_ != NULL) {
+ debug_delegate_->OnRetransmittedPacket(old_sequence_number,
+ new_sequence_number,
+ transmission_type,
+ clock_->ApproximateNow());
+ }
}
void QuicSentPacketManager::OnIncomingAck(
@@ -177,6 +195,14 @@ void QuicSentPacketManager::OnIncomingAck(
consecutive_tlp_count_ = 0;
consecutive_crypto_retransmission_count_ = 0;
}
+
+ if (debug_delegate_ != NULL) {
+ debug_delegate_->OnIncomingAck(received_info,
+ ack_receive_time,
+ largest_observed_,
+ largest_observed_acked,
+ GetLeastUnackedSentPacket());
+ }
}
void QuicSentPacketManager::MaybeInvokeCongestionEvent(
@@ -487,6 +513,10 @@ bool QuicSentPacketManager::OnPacketSent(
has_retransmittable_data);
unacked_packets_.SetSent(sequence_number, sent_time, bytes, in_flight);
+ if (debug_delegate_ != NULL) {
+ debug_delegate_->OnSentPacket(sequence_number, sent_time, bytes);
+ }
+
// Reset the retransmission timer anytime a pending packet is sent.
return in_flight;
}
@@ -798,6 +828,10 @@ QuicByteCount QuicSentPacketManager::GetCongestionWindow() const {
return send_algorithm_->GetCongestionWindow();
}
+QuicByteCount QuicSentPacketManager::GetSlowStartThreshold() const {
+ return send_algorithm_->GetSlowStartThreshold();
+}
+
void QuicSentPacketManager::MaybeEnablePacing() {
if (!FLAGS_enable_quic_pacing) {
return;
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 89a3b6d..af40072 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -52,6 +52,24 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
virtual void OnSpuriousPacketRetransmition(
TransmissionType transmission_type,
QuicByteCount byte_size) {}
+
+ virtual void OnSentPacket(
+ QuicPacketSequenceNumber sequence_number,
+ QuicTime sent_time,
+ QuicByteCount bytes) {}
+
+ virtual void OnRetransmittedPacket(
+ QuicPacketSequenceNumber old_sequence_number,
+ QuicPacketSequenceNumber new_sequence_number,
+ TransmissionType transmission_type,
+ QuicTime time) {}
+
+ virtual void OnIncomingAck(
+ const ReceivedPacketInfo& received_info,
+ QuicTime ack_receive_time,
+ QuicPacketSequenceNumber largest_observed,
+ bool largest_observed_acked,
+ QuicPacketSequenceNumber least_unacked_sent_packet) {}
};
// Struct to store the pending retransmission information.
@@ -173,6 +191,11 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
// window and will return 0.
QuicByteCount GetCongestionWindow() const;
+ // Returns the size of the slow start congestion window in bytes,
+ // aka ssthresh. Some send algorithms do not define a slow start
+ // threshold and will return 0.
+ QuicByteCount GetSlowStartThreshold() const;
+
// Enables pacing if it has not already been enabled, and if
// FLAGS_enable_quic_pacing is set.
void MaybeEnablePacing();
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 2b90f3b..399b772 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -25,6 +25,7 @@ QuicServerSession::~QuicServerSession() {}
void QuicServerSession::InitializeSession(
const QuicCryptoServerConfig& crypto_config) {
+ QuicSession::InitializeSession();
crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
}
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 281e02f..a6ffc05 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -106,6 +106,9 @@ QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
goaway_received_(false),
goaway_sent_(false),
has_pending_handshake_(false) {
+}
+
+void QuicSession::InitializeSession() {
if (connection_->version() <= QUIC_VERSION_19) {
flow_controller_.reset(new QuicFlowController(
connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 4880bff..5dfa7de 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -54,6 +54,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
};
QuicSession(QuicConnection* connection, const QuicConfig& config);
+ void InitializeSession();
virtual ~QuicSession();
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 9cb235d..83f2447 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,7 +125,9 @@ class TestSession : public QuicSession {
: QuicSession(connection,
DefaultQuicConfig()),
crypto_stream_(this),
- writev_consumes_all_data_(false) {}
+ writev_consumes_all_data_(false) {
+ InitializeSession();
+ }
virtual TestCryptoStream* GetCryptoStream() OVERRIDE {
return &crypto_stream_;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 19e3f3e..c458660 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -854,11 +854,11 @@ int QuicStreamFactory::CreateSession(
}
*session = new QuicClientSession(
- connection, socket.Pass(), writer.Pass(), this,
- quic_crypto_client_stream_factory_, server_info.Pass(), server_id,
- config, &crypto_config_,
- base::MessageLoop::current()->message_loop_proxy().get(),
+ connection, socket.Pass(), writer.Pass(), this, server_info.Pass(),
+ config, base::MessageLoop::current()->message_loop_proxy().get(),
net_log.net_log());
+ (*session)->InitializeSession(server_id, &crypto_config_,
+ quic_crypto_client_stream_factory_);
all_sessions_[*session] = server_id; // owning pointer
return OK;
}
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index ae4bb2e..87ec18c 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -213,6 +213,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_CHANNEL_ID_SIGNATURE);
RETURN_STRING_LITERAL(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED);
RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
RETURN_STRING_LITERAL(QUIC_VERSION_NEGOTIATION_MISMATCH);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index d1c19db..e067398 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -183,9 +183,10 @@ int CryptoTestUtils::HandshakeWithFakeServer(
PacketSavingConnection* server_conn =
new PacketSavingConnection(true, client_conn->supported_versions());
TestSession server_session(server_conn, DefaultQuicConfig());
-
+ server_session.InitializeSession();
QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance());
+
SetupCryptoServerConfigForTest(
server_session.connection()->clock(),
server_session.connection()->random_generator(),
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index b6a0744..36d0e78 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -302,6 +302,7 @@ bool PacketSavingConnection::SendOrQueuePacket(
MockSession::MockSession(QuicConnection* connection)
: QuicSession(connection, DefaultQuicConfig()) {
+ InitializeSession();
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
@@ -311,7 +312,9 @@ MockSession::~MockSession() {
TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
: QuicSession(connection, config),
- crypto_stream_(NULL) {}
+ crypto_stream_(NULL) {
+ InitializeSession();
+}
TestSession::~TestSession() {}
@@ -325,10 +328,10 @@ QuicCryptoStream* TestSession::GetCryptoStream() {
TestClientSession::TestClientSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicClientSessionBase(connection,
- config),
+ : QuicClientSessionBase(connection, config),
crypto_stream_(NULL) {
- EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
+ EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
+ InitializeSession();
}
TestClientSession::~TestClientSession() {}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 0a50861..bae8050 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -462,6 +462,8 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MOCK_METHOD1(OnRttUpdated, void(QuicPacketSequenceNumber));
MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void));
MOCK_CONST_METHOD0(GetCongestionWindow, QuicByteCount());
+ MOCK_CONST_METHOD0(InSlowStart, bool());
+ MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount());
private:
DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index c443434..52c4e2cf 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -183,11 +183,10 @@ bool QuicClient::StartConnect() {
}
session_.reset(new QuicClientSession(
- server_id_,
config_,
new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
- writer_.get(), false, supported_versions_),
- &crypto_config_));
+ writer_.get(), false, supported_versions_)));
+ session_->InitializeSession(server_id_, &crypto_config_);
return session_->CryptoConnect();
}
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index aca5418..0e7a7a2 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -14,18 +14,22 @@ using std::string;
namespace net {
namespace tools {
-QuicClientSession::QuicClientSession(
- const QuicServerId& server_id,
- const QuicConfig& config,
- QuicConnection* connection,
- QuicCryptoClientConfig* crypto_config)
- : QuicClientSessionBase(connection, config),
- crypto_stream_(server_id, this, NULL, crypto_config) {
+QuicClientSession::QuicClientSession(const QuicConfig& config,
+ QuicConnection* connection)
+ : QuicClientSessionBase(connection, config) {
}
QuicClientSession::~QuicClientSession() {
}
+void QuicClientSession::InitializeSession(
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config) {
+ QuicClientSessionBase::InitializeSession();
+ crypto_stream_.reset(
+ new QuicCryptoClientStream(server_id, this, NULL, crypto_config));
+}
+
void QuicClientSession::OnProofValid(
const QuicCryptoClientConfig::CachedState& /*cached*/) {
}
@@ -35,7 +39,7 @@ void QuicClientSession::OnProofVerifyDetailsAvailable(
}
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
- if (!crypto_stream_.encryption_established()) {
+ if (!crypto_stream_->encryption_established()) {
DVLOG(1) << "Encryption not active so no outgoing stream created.";
return NULL;
}
@@ -56,15 +60,16 @@ QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
}
QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
- return &crypto_stream_;
+ return crypto_stream_.get();
}
bool QuicClientSession::CryptoConnect() {
- return crypto_stream_.CryptoConnect();
+ DCHECK(flow_controller());
+ return crypto_stream_->CryptoConnect();
}
int QuicClientSession::GetNumSentClientHellos() const {
- return crypto_stream_.num_sent_client_hellos();
+ return crypto_stream_->num_sent_client_hellos();
}
QuicDataStream* QuicClientSession::CreateIncomingDataStream(
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index 3aad445..bb64145 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -25,10 +25,7 @@ namespace tools {
class QuicClientSession : public QuicClientSessionBase {
public:
- QuicClientSession(const QuicServerId& server_id,
- const QuicConfig& config,
- QuicConnection* connection,
- QuicCryptoClientConfig* crypto_config);
+ QuicClientSession(const QuicConfig& config, QuicConnection* connection);
virtual ~QuicClientSession();
// QuicClientSessionBase methods:
@@ -37,6 +34,9 @@ class QuicClientSession : public QuicClientSessionBase {
virtual void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) OVERRIDE;
+ void InitializeSession(const QuicServerId& server_id,
+ QuicCryptoClientConfig* config);
+
// QuicSession methods:
virtual QuicSpdyClientStream* CreateOutgoingDataStream() OVERRIDE;
virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE;
@@ -55,7 +55,7 @@ class QuicClientSession : public QuicClientSessionBase {
virtual QuicDataStream* CreateIncomingDataStream(QuicStreamId id) OVERRIDE;
private:
- QuicCryptoClientStream crypto_stream_;
+ scoped_ptr<QuicCryptoClientStream> crypto_stream_;
DISALLOW_COPY_AND_ASSIGN(QuicClientSession);
};
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index dc6b244..6f8136f 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -38,11 +38,10 @@ class ToolsQuicClientSessionTest
: connection_(new PacketSavingConnection(false,
SupportedVersions(GetParam()))) {
crypto_config_.SetDefaults();
- session_.reset(new QuicClientSession(
+ session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
+ session_->InitializeSession(
QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(),
- connection_,
- &crypto_config_));
+ &crypto_config_);
session_->config()->SetDefaults();
}
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 01371bf..c59559c 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -23,6 +23,7 @@ QuicServerSession::~QuicServerSession() {}
void QuicServerSession::InitializeSession(
const QuicCryptoServerConfig& crypto_config) {
+ QuicSession::InitializeSession();
crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
}
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index 475f832..ecaa497 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -29,11 +29,11 @@ class QuicSpdyClientStreamTest : public TestWithParam<QuicVersion> {
QuicSpdyClientStreamTest()
: connection_(new StrictMock<MockConnection>(
false, SupportedVersions(GetParam()))),
- session_(QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(),
- connection_,
- &crypto_config_),
+ session_(DefaultQuicConfig(), connection_),
body_("hello world") {
+ session_.InitializeSession(
+ QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
+ &crypto_config_);
crypto_config_.SetDefaults();
headers_.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "Ok");
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index d46eae5..02ab3e7 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -80,8 +80,9 @@ QuicAckFrame MakeAckFrameWithNackRanges(
TestSession::TestSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicSession(connection, config),
- crypto_stream_(NULL) {
+ : QuicSession(connection, config),
+ crypto_stream_(NULL) {
+ InitializeSession();
}
TestSession::~TestSession() {}