Commit 14abd31d authored by rtenneti's avatar rtenneti Committed by Commit bot

QUIC - Race two connections. One connection which loads data from disk

cache sends a CHLO and another connection that doesn't wait to load
server config from disk cache and sends INCHOATE_HELLO.

This is not enabled. QuicStreamFactory tests with this flag enabled
and disabled. Tested chrome and all unit tests with this flag enabled.

R=rch@chromium.org

Review URL: https://codereview.chromium.org/881133004

Cr-Commit-Position: refs/heads/master@{#315117}
parent 1ef7ee1e
...@@ -196,7 +196,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( ...@@ -196,7 +196,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
break; break;
case STATE_SEND_CHLO: case STATE_SEND_CHLO:
DoSendCHLO(in, cached); DoSendCHLO(in, cached);
return; return; // return waiting to hear from server.
case STATE_RECV_REJ: case STATE_RECV_REJ:
DoReceiveREJ(in, cached); DoReceiveREJ(in, cached);
break; break;
...@@ -638,7 +638,7 @@ bool QuicCryptoClientStream::RequiresChannelID( ...@@ -638,7 +638,7 @@ bool QuicCryptoClientStream::RequiresChannelID(
return false; return false;
} }
const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
if (!scfg) { // scfg may be null when we send an inchoate CHLO. if (!scfg) { // scfg may be null then we send an inchoate CHLO.
return false; return false;
} }
const QuicTag* their_proof_demands; const QuicTag* their_proof_demands;
......
...@@ -513,6 +513,8 @@ enum QuicErrorCode { ...@@ -513,6 +513,8 @@ enum QuicErrorCode {
QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS = 68, QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS = 68,
// The connection has too many outstanding received packets. // The connection has too many outstanding received packets.
QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS = 69, QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS = 69,
// The quic connection job to load server config is cancelled.
QUIC_CONNECTION_CANCELLED = 70,
// Crypto errors. // Crypto errors.
...@@ -570,7 +572,7 @@ enum QuicErrorCode { ...@@ -570,7 +572,7 @@ enum QuicErrorCode {
QUIC_VERSION_NEGOTIATION_MISMATCH = 55, QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
// No error. Used as bound while iterating. // No error. Used as bound while iterating.
QUIC_LAST_ERROR = 70, QUIC_LAST_ERROR = 71,
}; };
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
......
This diff is collapsed.
...@@ -178,6 +178,11 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -178,6 +178,11 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
quic_server_info_factory_ = quic_server_info_factory; quic_server_info_factory_ = quic_server_info_factory;
} }
bool enable_connection_racing() const { return enable_connection_racing_; }
void set_enable_connection_racing(bool enable_connection_racing) {
enable_connection_racing_ = enable_connection_racing;
}
private: private:
class Job; class Job;
friend class test::QuicStreamFactoryPeer; friend class test::QuicStreamFactoryPeer;
...@@ -204,10 +209,17 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -204,10 +209,17 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
typedef std::set<QuicClientSession*> SessionSet; typedef std::set<QuicClientSession*> SessionSet;
typedef std::map<IpAliasKey, SessionSet> IPAliasMap; typedef std::map<IpAliasKey, SessionSet> IPAliasMap;
typedef std::map<QuicServerId, QuicCryptoClientConfig*> CryptoConfigMap; typedef std::map<QuicServerId, QuicCryptoClientConfig*> CryptoConfigMap;
typedef std::map<QuicServerId, Job*> JobMap; typedef std::set<Job*> JobSet;
typedef std::map<QuicStreamRequest*, Job*> RequestMap; typedef std::map<QuicServerId, JobSet> JobMap;
typedef std::map<QuicStreamRequest*, QuicServerId> RequestMap;
typedef std::set<QuicStreamRequest*> RequestSet; typedef std::set<QuicStreamRequest*> RequestSet;
typedef std::map<Job*, RequestSet> JobRequestsMap; typedef std::map<QuicServerId, RequestSet> ServerIDRequestsMap;
// Creates a job which doesn't wait for server config to be loaded from the
// disk cache. This job is started via a PostTask.
void CreateAuxilaryJob(const QuicServerId server_id,
bool is_post,
const BoundNetLog& net_log);
// Returns a newly created QuicHttpStream owned by the caller, if a // Returns a newly created QuicHttpStream owned by the caller, if a
// matching session already exists. Returns NULL otherwise. // matching session already exists. Returns NULL otherwise.
...@@ -233,6 +245,10 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -233,6 +245,10 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
int64 GetServerNetworkStatsSmoothedRttInMicroseconds( int64 GetServerNetworkStatsSmoothedRttInMicroseconds(
const QuicServerId& server_id) const; const QuicServerId& server_id) const;
// Helped methods.
bool WasAlternateProtocolRecentlyBroken(const QuicServerId& server_id) const;
bool CryptoConfigCacheIsEmpty(const QuicServerId& server_id);
// Initializes the cached state associated with |server_id| in // Initializes the cached state associated with |server_id| in
// |crypto_config_| with the information in |server_info|. // |crypto_config_| with the information in |server_info|.
void InitializeCachedStateInCryptoConfig( void InitializeCachedStateInCryptoConfig(
...@@ -274,7 +290,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -274,7 +290,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
QuicCryptoClientConfig crypto_config_; QuicCryptoClientConfig crypto_config_;
JobMap active_jobs_; JobMap active_jobs_;
JobRequestsMap job_requests_map_; ServerIDRequestsMap job_requests_map_;
RequestMap active_requests_; RequestMap active_requests_;
QuicVersionVector supported_versions_; QuicVersionVector supported_versions_;
...@@ -305,6 +321,11 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -305,6 +321,11 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
// Set this for setting config's BytesForConnectionIdToSend (TCID param) to 0. // Set this for setting config's BytesForConnectionIdToSend (TCID param) to 0.
bool enable_truncated_connection_ids_; bool enable_truncated_connection_ids_;
// Set if we want to race connections - one connection that sends
// INCHOATE_HELLO and another connection that sends CHLO after loading server
// config from the disk cache.
bool enable_connection_racing_;
// Each profile will (probably) have a unique port_seed_ value. This value is // Each profile will (probably) have a unique port_seed_ value. This value is
// used to help seed a pseudo-random number generator (PortSuggester) so that // used to help seed a pseudo-random number generator (PortSuggester) so that
// we consistently (within this profile) suggest the same ephemeral port when // we consistently (within this profile) suggest the same ephemeral port when
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece; using base::StringPiece;
using std::ostream;
using std::string; using std::string;
using std::vector; using std::vector;
...@@ -43,6 +44,34 @@ namespace test { ...@@ -43,6 +44,34 @@ namespace test {
namespace { namespace {
const char kDefaultServerHostName[] = "www.google.com"; const char kDefaultServerHostName[] = "www.google.com";
const int kDefaultServerPort = 443; const int kDefaultServerPort = 443;
// Run all tests with all the combinations of versions and
// enable_connection_racing.
struct TestParams {
TestParams(const QuicVersion version, bool enable_connection_racing)
: version(version), enable_connection_racing(enable_connection_racing) {}
friend ostream& operator<<(ostream& os, const TestParams& p) {
os << "{ version: " << QuicVersionToString(p.version);
os << " enable_connection_racing: " << p.enable_connection_racing << " }";
return os;
}
QuicVersion version;
bool enable_connection_racing;
};
// Constructs various test permutations.
vector<TestParams> GetTestParams() {
vector<TestParams> params;
QuicVersionVector all_supported_versions = QuicSupportedVersions();
for (const QuicVersion version : all_supported_versions) {
params.push_back(TestParams(version, false));
params.push_back(TestParams(version, true));
}
return params;
}
} // namespace anonymous } // namespace anonymous
class QuicStreamFactoryPeer { class QuicStreamFactoryPeer {
...@@ -100,6 +129,16 @@ class QuicStreamFactoryPeer { ...@@ -100,6 +129,16 @@ class QuicStreamFactoryPeer {
size_t load_server_info_timeout) { size_t load_server_info_timeout) {
factory->load_server_info_timeout_ms_ = load_server_info_timeout; factory->load_server_info_timeout_ms_ = load_server_info_timeout;
} }
static void SetEnableConnectionRacing(QuicStreamFactory* factory,
bool enable_connection_racing) {
factory->enable_connection_racing_ = enable_connection_racing;
}
static size_t GetNumberOfActiveJobs(QuicStreamFactory* factory,
const QuicServerId& server_id) {
return (factory->active_jobs_[server_id]).size();
}
}; };
class MockQuicServerInfo : public QuicServerInfo { class MockQuicServerInfo : public QuicServerInfo {
...@@ -135,14 +174,13 @@ class MockQuicServerInfoFactory : public QuicServerInfoFactory { ...@@ -135,14 +174,13 @@ class MockQuicServerInfoFactory : public QuicServerInfoFactory {
} }
}; };
class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
protected: protected:
QuicStreamFactoryTest() QuicStreamFactoryTest()
: random_generator_(0), : random_generator_(0),
clock_(new MockClock()), clock_(new MockClock()),
runner_(new TestTaskRunner(clock_)), runner_(new TestTaskRunner(clock_)),
maker_(GetParam(), 0, clock_), maker_(GetParam().version, 0, clock_),
cert_verifier_(CertVerifier::CreateDefault()), cert_verifier_(CertVerifier::CreateDefault()),
channel_id_service_( channel_id_service_(
new ChannelIDService(new DefaultChannelIDStore(nullptr), new ChannelIDService(new DefaultChannelIDStore(nullptr),
...@@ -158,7 +196,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { ...@@ -158,7 +196,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
clock_, clock_,
kDefaultMaxPacketSize, kDefaultMaxPacketSize,
std::string(), std::string(),
SupportedVersions(GetParam()), SupportedVersions(GetParam().version),
/*enable_port_selection=*/true, /*enable_port_selection=*/true,
/*always_require_handshake_confirmation=*/false, /*always_require_handshake_confirmation=*/false,
/*disable_connection_pooling=*/false, /*disable_connection_pooling=*/false,
...@@ -171,6 +209,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { ...@@ -171,6 +209,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
privacy_mode_(PRIVACY_MODE_DISABLED) { privacy_mode_(PRIVACY_MODE_DISABLED) {
factory_.set_require_confirmation(false); factory_.set_require_confirmation(false);
clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
QuicStreamFactoryPeer::SetEnableConnectionRacing(
&factory_, GetParam().enable_connection_racing);
} }
scoped_ptr<QuicHttpStream> CreateIfSessionExists( scoped_ptr<QuicHttpStream> CreateIfSessionExists(
...@@ -244,7 +284,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { ...@@ -244,7 +284,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
QuicStreamId stream_id = kClientDataStreamId1; QuicStreamId stream_id = kClientDataStreamId1;
return maker_.MakeRstPacket( return maker_.MakeRstPacket(
1, true, stream_id, 1, true, stream_id,
AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam())); AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam().version));
} }
MockQuicServerInfoFactory quic_server_info_factory_; MockQuicServerInfoFactory quic_server_info_factory_;
...@@ -266,8 +306,9 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { ...@@ -266,8 +306,9 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
TestCompletionCallback callback_; TestCompletionCallback callback_;
}; };
INSTANTIATE_TEST_CASE_P(Version, QuicStreamFactoryTest, INSTANTIATE_TEST_CASE_P(Version,
::testing::ValuesIn(QuicSupportedVersions())); QuicStreamFactoryTest,
::testing::ValuesIn(GetTestParams()));
TEST_P(QuicStreamFactoryTest, CreateIfSessionExists) { TEST_P(QuicStreamFactoryTest, CreateIfSessionExists) {
EXPECT_EQ(nullptr, CreateIfSessionExists(host_port_pair_, net_log_).get()); EXPECT_EQ(nullptr, CreateIfSessionExists(host_port_pair_, net_log_).get());
...@@ -1562,6 +1603,10 @@ TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) { ...@@ -1562,6 +1603,10 @@ TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
} }
TEST_P(QuicStreamFactoryTest, CancelWaitForDataReady) { TEST_P(QuicStreamFactoryTest, CancelWaitForDataReady) {
// Don't race quic connections when testing cancel reading of server config
// from disk cache.
if (GetParam().enable_connection_racing)
return;
factory_.set_quic_server_info_factory(&quic_server_info_factory_); factory_.set_quic_server_info_factory(&quic_server_info_factory_);
QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get()); QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
const size_t kLoadServerInfoTimeoutMs = 50; const size_t kLoadServerInfoTimeoutMs = 50;
...@@ -1604,5 +1649,52 @@ TEST_P(QuicStreamFactoryTest, CancelWaitForDataReady) { ...@@ -1604,5 +1649,52 @@ TEST_P(QuicStreamFactoryTest, CancelWaitForDataReady) {
EXPECT_TRUE(socket_data.at_write_eof()); EXPECT_TRUE(socket_data.at_write_eof());
} }
TEST_P(QuicStreamFactoryTest, RacingConnections) {
if (!GetParam().enable_connection_racing)
return;
factory_.set_quic_server_info_factory(&quic_server_info_factory_);
QuicStreamFactoryPeer::SetTaskRunner(&factory_, runner_.get());
const size_t kLoadServerInfoTimeoutMs = 50;
QuicStreamFactoryPeer::SetLoadServerInfoTimeout(&factory_,
kLoadServerInfoTimeoutMs);
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
socket_data.StopAfter(1);
MockRead reads2[] = {
MockRead(ASYNC, 0, 0) // EOF
};
DeterministicSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
socket_data2.StopAfter(1);
crypto_client_stream_factory_.set_handshake_mode(
MockCryptoClientStream::ZERO_RTT);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
QuicStreamRequest request(&factory_);
QuicServerId server_id(host_port_pair_, is_https_, privacy_mode_);
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, is_https_, privacy_mode_, "GET",
net_log_, callback_.callback()));
EXPECT_EQ(2u,
QuicStreamFactoryPeer::GetNumberOfActiveJobs(&factory_, server_id));
runner_->RunNextTask();
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
EXPECT_TRUE(stream.get());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
EXPECT_EQ(0u,
QuicStreamFactoryPeer::GetNumberOfActiveJobs(&factory_, server_id));
}
} // namespace test } // namespace test
} // namespace net } // namespace net
...@@ -221,6 +221,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { ...@@ -221,6 +221,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_VERSION_NEGOTIATION_MISMATCH); RETURN_STRING_LITERAL(QUIC_VERSION_NEGOTIATION_MISMATCH);
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS); RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS);
RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS); RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS);
RETURN_STRING_LITERAL(QUIC_CONNECTION_CANCELLED);
RETURN_STRING_LITERAL(QUIC_LAST_ERROR); RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
// Intentionally have no default case, so we'll break the build // Intentionally have no default case, so we'll break the build
// if we add errors and don't put them here. // if we add errors and don't put them here.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment