Commit ca525331 authored by Matt Menke's avatar Matt Menke Committed by Commit Bot

Defrag QuicStreamFactory methods, and rename test-only method.

The QuicStreamFactory methods definition order was completely different
from the declaration order in the header. This CL fixes that. It also
renames the test-only method CryptoConfigCacheIsEmpty() to
CryptoConfigCacheIsEmptyForTesting().

This CL doesn't actually change any code, other than the rename and
moving stuff around.

Bug: 1003423
Change-Id: I751d656cf24b41e206414be04958ac52cf4a9faf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1819352Reviewed-by: default avatarZhongyi Shi <zhongyi@chromium.org>
Commit-Queue: Matt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#698980}
parent 877b01eb
...@@ -227,6 +227,14 @@ class ServerIdOriginFilter ...@@ -227,6 +227,14 @@ class ServerIdOriginFilter
const base::Callback<bool(const GURL&)> origin_filter_; const base::Callback<bool(const GURL&)> origin_filter_;
}; };
std::set<std::string> HostsFromOrigins(std::set<HostPortPair> origins) {
std::set<std::string> hosts;
for (const auto& origin : origins) {
hosts.insert(origin.host());
}
return hosts;
}
} // namespace } // namespace
QuicParams::QuicParams() QuicParams::QuicParams()
...@@ -1098,21 +1106,6 @@ bool QuicStreamRequest::WaitForHostResolution(CompletionOnceCallback callback) { ...@@ -1098,21 +1106,6 @@ bool QuicStreamRequest::WaitForHostResolution(CompletionOnceCallback callback) {
return expect_on_host_resolution_; return expect_on_host_resolution_;
} }
void QuicStreamRequest::SetSession(
std::unique_ptr<QuicChromiumClientSession::Handle> session) {
session_ = move(session);
}
void QuicStreamRequest::OnConnectionFailedOnDefaultNetwork() {
if (!failed_on_default_network_callback_.is_null())
std::move(failed_on_default_network_callback_).Run(OK);
}
void QuicStreamRequest::OnRequestComplete(int rv) {
factory_ = nullptr;
std::move(callback_).Run(rv);
}
void QuicStreamRequest::ExpectOnHostResolution() { void QuicStreamRequest::ExpectOnHostResolution() {
expect_on_host_resolution_ = true; expect_on_host_resolution_ = true;
} }
...@@ -1125,6 +1118,16 @@ void QuicStreamRequest::OnHostResolutionComplete(int rv) { ...@@ -1125,6 +1118,16 @@ void QuicStreamRequest::OnHostResolutionComplete(int rv) {
} }
} }
void QuicStreamRequest::OnRequestComplete(int rv) {
factory_ = nullptr;
std::move(callback_).Run(rv);
}
void QuicStreamRequest::OnConnectionFailedOnDefaultNetwork() {
if (!failed_on_default_network_callback_.is_null())
std::move(failed_on_default_network_callback_).Run(OK);
}
base::TimeDelta QuicStreamRequest::GetTimeDelayForWaitingJob() const { base::TimeDelta QuicStreamRequest::GetTimeDelayForWaitingJob() const {
if (!factory_) if (!factory_)
return base::TimeDelta(); return base::TimeDelta();
...@@ -1145,17 +1148,32 @@ QuicStreamRequest::ReleaseSessionHandle() { ...@@ -1145,17 +1148,32 @@ QuicStreamRequest::ReleaseSessionHandle() {
return std::move(session_); return std::move(session_);
} }
namespace { void QuicStreamRequest::SetSession(
std::unique_ptr<QuicChromiumClientSession::Handle> session) {
session_ = move(session);
}
std::set<std::string> HostsFromOrigins(std::set<HostPortPair> origins) { QuicStreamFactory::QuicSessionAliasKey::QuicSessionAliasKey(
std::set<std::string> hosts; const HostPortPair& destination,
for (const auto& origin : origins) { const QuicSessionKey& session_key)
hosts.insert(origin.host()); : destination_(destination), session_key_(session_key) {}
}
return hosts; bool QuicStreamFactory::QuicSessionAliasKey::operator<(
const QuicSessionAliasKey& other) const {
return std::tie(destination_, session_key_) <
std::tie(other.destination_, other.session_key_);
} }
} // namespace bool QuicStreamFactory::QuicSessionAliasKey::operator==(
const QuicSessionAliasKey& other) const {
return destination_.Equals(other.destination_) &&
session_key_ == other.session_key_;
}
size_t QuicStreamFactory::QuicSessionAliasKey::EstimateMemoryUsage() const {
return base::trace_event::EstimateMemoryUsage(destination_) +
base::trace_event::EstimateMemoryUsage(session_key_.server_id());
}
QuicStreamFactory::QuicStreamFactory( QuicStreamFactory::QuicStreamFactory(
NetLog* net_log, NetLog* net_log,
...@@ -1218,86 +1236,6 @@ QuicStreamFactory::QuicStreamFactory( ...@@ -1218,86 +1236,6 @@ QuicStreamFactory::QuicStreamFactory(
InitializeMigrationOptions(); InitializeMigrationOptions();
} }
void QuicStreamFactory::InitializeMigrationOptions() {
// The following list of options cannot be set immediately until
// prerequisites are met. Cache the initial setting in local variables and
// reset them in |params_|.
bool migrate_sessions_on_network_change =
params_.migrate_sessions_on_network_change_v2;
bool migrate_sessions_early = params_.migrate_sessions_early_v2;
bool retry_on_alternate_network_before_handshake =
params_.retry_on_alternate_network_before_handshake;
bool migrate_idle_sessions = params_.migrate_idle_sessions;
bool allow_port_migration = params_.allow_port_migration;
params_.migrate_sessions_on_network_change_v2 = false;
params_.migrate_sessions_early_v2 = false;
params_.allow_port_migration = false;
params_.retry_on_alternate_network_before_handshake = false;
params_.migrate_idle_sessions = false;
DCHECK(!(migrate_sessions_early && params_.go_away_on_path_degrading));
DCHECK(!(allow_port_migration && params_.go_away_on_path_degrading));
// TODO(zhongyi): deprecate |goaway_sessions_on_ip_change| if the experiment
// is no longer needed.
// goaway_sessions_on_ip_change and close_sessions_on_ip_change should never
// be simultaneously set to true.
DCHECK(!(params_.close_sessions_on_ip_change &&
params_.goaway_sessions_on_ip_change));
bool handle_ip_change = params_.close_sessions_on_ip_change ||
params_.goaway_sessions_on_ip_change;
// If IP address changes are handled explicitly, connection migration should
// not be set.
DCHECK(!(handle_ip_change && migrate_sessions_on_network_change));
if (handle_ip_change)
NetworkChangeNotifier::AddIPAddressObserver(this);
// Port migration and early migration both act on path degrading and thus can
// not be simultaneously set.
DCHECK(!allow_port_migration || !migrate_sessions_early);
if (allow_port_migration)
params_.allow_port_migration = true;
if (!NetworkChangeNotifier::AreNetworkHandlesSupported())
return;
NetworkChangeNotifier::AddNetworkObserver(this);
// Perform checks on the connection migration options.
if (!migrate_sessions_on_network_change) {
DCHECK(!migrate_sessions_early);
return;
}
// Enable migration on platform notifications.
params_.migrate_sessions_on_network_change_v2 = true;
if (!migrate_sessions_early) {
DCHECK(!migrate_idle_sessions &&
!retry_on_alternate_network_before_handshake);
return;
}
// Enable migration on path degrading.
params_.migrate_sessions_early_v2 = true;
// Set retransmittable on wire timeout for migration on path degrading if no
// value is specified.
if (retransmittable_on_wire_timeout_.IsZero()) {
retransmittable_on_wire_timeout_ = quic::QuicTime::Delta::FromMicroseconds(
kDefaultRetransmittableOnWireTimeout.InMicroseconds());
}
// Enable retry on alternate network before handshake.
if (retry_on_alternate_network_before_handshake)
params_.retry_on_alternate_network_before_handshake = true;
// Enable migration for idle sessions.
if (migrate_idle_sessions)
params_.migrate_idle_sessions = true;
}
QuicStreamFactory::~QuicStreamFactory() { QuicStreamFactory::~QuicStreamFactory() {
UMA_HISTOGRAM_COUNTS_1000("Net.NumQuicSessionsAtShutdown", UMA_HISTOGRAM_COUNTS_1000("Net.NumQuicSessionsAtShutdown",
all_sessions_.size()); all_sessions_.size());
...@@ -1323,81 +1261,6 @@ QuicStreamFactory::~QuicStreamFactory() { ...@@ -1323,81 +1261,6 @@ QuicStreamFactory::~QuicStreamFactory() {
} }
} }
void QuicStreamFactory::set_is_quic_known_to_work_on_current_network(
bool is_quic_known_to_work_on_current_network) {
is_quic_known_to_work_on_current_network_ =
is_quic_known_to_work_on_current_network;
if (!(local_address_ == IPEndPoint())) {
if (is_quic_known_to_work_on_current_network_) {
http_server_properties_->SetLastLocalAddressWhenQuicWorked(
local_address_.address());
} else {
http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
}
}
}
base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) {
// If |is_quic_known_to_work_on_current_network_| is false, then one of the
// following is true:
// 1) This is startup and QuicStreamFactory::CreateSession() and
// ConfigureSocket() have yet to be called, and it is not yet known
// if the current network is the last one where QUIC worked.
// 2) Startup has been completed, and QUIC has not been used
// successfully since startup, or on this network before.
if (!is_quic_known_to_work_on_current_network_) {
// If |need_to_check_persisted_supports_quic_| is false, this is case 1)
// above. If HasLastLocalAddressWhenQuicWorked() is also true, then there's
// a chance the current network is the last one on which QUIC worked. So
// only delay the request if there's no chance that is the case.
if (!need_to_check_persisted_supports_quic_ ||
!http_server_properties_->HasLastLocalAddressWhenQuicWorked()) {
return base::TimeDelta();
}
}
int64_t srtt = 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(
server_id, network_isolation_key);
// Picked 300ms based on mean time from
// Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
const int kDefaultRTT = 300 * quic::kNumMicrosPerMilli;
if (!srtt)
srtt = kDefaultRTT;
return base::TimeDelta::FromMicroseconds(srtt);
}
void QuicStreamFactory::DumpMemoryStats(
base::trace_event::ProcessMemoryDump* pmd,
const std::string& parent_absolute_name) const {
if (all_sessions_.empty() && active_jobs_.empty())
return;
base::trace_event::MemoryAllocatorDump* factory_dump =
pmd->CreateAllocatorDump(parent_absolute_name + "/quic_stream_factory");
size_t memory_estimate =
base::trace_event::EstimateMemoryUsage(all_sessions_) +
base::trace_event::EstimateMemoryUsage(active_sessions_) +
base::trace_event::EstimateMemoryUsage(session_aliases_) +
base::trace_event::EstimateMemoryUsage(ip_aliases_) +
base::trace_event::EstimateMemoryUsage(session_peer_ip_) +
base::trace_event::EstimateMemoryUsage(gone_away_aliases_) +
base::trace_event::EstimateMemoryUsage(active_jobs_) +
base::trace_event::EstimateMemoryUsage(active_cert_verifier_jobs_);
factory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
memory_estimate);
factory_dump->AddScalar("all_sessions",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
all_sessions_.size());
factory_dump->AddScalar("active_jobs",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
active_jobs_.size());
factory_dump->AddScalar("active_cert_jobs",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
active_cert_verifier_jobs_.size());
}
bool QuicStreamFactory::CanUseExistingSession(const QuicSessionKey& session_key, bool QuicStreamFactory::CanUseExistingSession(const QuicSessionKey& session_key,
const HostPortPair& destination) { const HostPortPair& destination) {
// TODO(zhongyi): delete active_sessions_.empty() checks once the // TODO(zhongyi): delete active_sessions_.empty() checks once the
...@@ -1421,13 +1284,6 @@ bool QuicStreamFactory::CanUseExistingSession(const QuicSessionKey& session_key, ...@@ -1421,13 +1284,6 @@ bool QuicStreamFactory::CanUseExistingSession(const QuicSessionKey& session_key,
return false; return false;
} }
void QuicStreamFactory::MarkAllActiveSessionsGoingAway() {
while (!active_sessions_.empty()) {
QuicChromiumClientSession* session = active_sessions_.begin()->second;
OnSessionGoingAway(session);
}
}
int QuicStreamFactory::Create(const QuicSessionKey& session_key, int QuicStreamFactory::Create(const QuicSessionKey& session_key,
const HostPortPair& destination, const HostPortPair& destination,
quic::ParsedQuicVersion quic_version, quic::ParsedQuicVersion quic_version,
...@@ -1547,92 +1403,16 @@ int QuicStreamFactory::Create(const QuicSessionKey& session_key, ...@@ -1547,92 +1403,16 @@ int QuicStreamFactory::Create(const QuicSessionKey& session_key,
return rv; return rv;
} }
QuicStreamFactory::QuicSessionAliasKey::QuicSessionAliasKey( void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) {
const HostPortPair& destination, const AliasSet& aliases = session_aliases_[session];
const QuicSessionKey& session_key) for (auto it = aliases.begin(); it != aliases.end(); ++it) {
: destination_(destination), session_key_(session_key) {} const QuicSessionKey& session_key = it->session_key();
DCHECK(active_sessions_.count(session_key));
bool QuicStreamFactory::QuicSessionAliasKey::operator<( DCHECK_EQ(session, active_sessions_[session_key]);
const QuicSessionAliasKey& other) const { // Track sessions which have recently gone away so that we can disable
return std::tie(destination_, session_key_) < // port suggestions.
std::tie(other.destination_, other.session_key_); if (session->goaway_received())
} gone_away_aliases_.insert(*it);
bool QuicStreamFactory::QuicSessionAliasKey::operator==(
const QuicSessionAliasKey& other) const {
return destination_.Equals(other.destination_) &&
session_key_ == other.session_key_;
}
size_t QuicStreamFactory::QuicSessionAliasKey::EstimateMemoryUsage() const {
return base::trace_event::EstimateMemoryUsage(destination_) +
base::trace_event::EstimateMemoryUsage(session_key_.server_id());
}
bool QuicStreamFactory::HasMatchingIpSession(const QuicSessionAliasKey& key,
const AddressList& address_list) {
const quic::QuicServerId& server_id(key.server_id());
DCHECK(!HasActiveSession(key.session_key()));
for (const IPEndPoint& address : address_list) {
if (!base::Contains(ip_aliases_, address))
continue;
const SessionSet& sessions = ip_aliases_[address];
for (QuicChromiumClientSession* session : sessions) {
if (!session->CanPool(server_id.host(), key.session_key().privacy_mode(),
key.session_key().socket_tag(),
key.session_key().network_isolation_key())) {
continue;
}
active_sessions_[key.session_key()] = session;
session_aliases_[session].insert(key);
return true;
}
}
return false;
}
void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
auto iter = active_jobs_.find(job->key().session_key());
DCHECK(iter != active_jobs_.end());
if (rv == OK) {
set_is_quic_known_to_work_on_current_network(true);
auto session_it = active_sessions_.find(job->key().session_key());
CHECK(session_it != active_sessions_.end());
QuicChromiumClientSession* session = session_it->second;
for (auto* request : iter->second->stream_requests()) {
// Do not notify |request| yet.
request->SetSession(session->CreateHandle(job->key().destination()));
}
}
for (auto* request : iter->second->stream_requests()) {
// Even though we're invoking callbacks here, we don't need to worry
// about |this| being deleted, because the factory is owned by the
// profile which can not be deleted via callbacks.
if (rv < 0) {
job->PopulateNetErrorDetails(request->net_error_details());
}
request->OnRequestComplete(rv);
}
active_jobs_.erase(iter);
}
void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) {
active_cert_verifier_jobs_.erase(job->server_id());
}
void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) {
const AliasSet& aliases = session_aliases_[session];
for (auto it = aliases.begin(); it != aliases.end(); ++it) {
const QuicSessionKey& session_key = it->session_key();
DCHECK(active_sessions_.count(session_key));
DCHECK_EQ(session, active_sessions_[session_key]);
// Track sessions which have recently gone away so that we can disable
// port suggestions.
if (session->goaway_received())
gone_away_aliases_.insert(*it);
active_sessions_.erase(session_key); active_sessions_.erase(session_key);
ProcessGoingAwaySession(session, session_key.server_id(), true); ProcessGoingAwaySession(session, session_key.server_id(), true);
...@@ -1737,6 +1517,90 @@ void QuicStreamFactory::ClearCachedStatesInCryptoConfig( ...@@ -1737,6 +1517,90 @@ void QuicStreamFactory::ClearCachedStatesInCryptoConfig(
} }
} }
int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket,
IPEndPoint addr,
NetworkHandle network,
const SocketTag& socket_tag) {
socket->UseNonBlockingIO();
int rv;
if (params_.migrate_sessions_on_network_change_v2) {
// If caller leaves network unspecified, use current default network.
if (network == NetworkChangeNotifier::kInvalidNetworkHandle) {
rv = socket->ConnectUsingDefaultNetwork(addr);
} else {
rv = socket->ConnectUsingNetwork(network, addr);
}
} else {
rv = socket->Connect(addr);
}
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
return rv;
}
socket->ApplySocketTag(socket_tag);
rv = socket->SetReceiveBufferSize(kQuicSocketReceiveBufferSize);
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
return rv;
}
rv = socket->SetDoNotFragment();
// SetDoNotFragment is not implemented on all platforms, so ignore errors.
if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
return rv;
}
// Set a buffer large enough to contain the initial CWND's worth of packet
// to work around the problem with CHLO packets being sent out with the
// wrong encryption level, when the send buffer is full.
rv = socket->SetSendBufferSize(quic::kMaxOutgoingPacketSize * 20);
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
return rv;
}
socket->GetLocalAddress(&local_address_);
if (need_to_check_persisted_supports_quic_) {
need_to_check_persisted_supports_quic_ = false;
if (http_server_properties_->WasLastLocalAddressWhenQuicWorked(
local_address_.address())) {
is_quic_known_to_work_on_current_network_ = true;
// Clear the persisted IP address, in case the network no longer supports
// QUIC so the next restart will require confirmation. It will be
// re-persisted when the first job completes successfully.
http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
}
}
return OK;
}
NetworkHandle QuicStreamFactory::FindAlternateNetwork(
NetworkHandle old_network) {
// Find a new network that sessions bound to |old_network| can be migrated to.
NetworkChangeNotifier::NetworkList network_list;
NetworkChangeNotifier::GetConnectedNetworks(&network_list);
for (NetworkHandle new_network : network_list) {
if (new_network != old_network)
return new_network;
}
return NetworkChangeNotifier::kInvalidNetworkHandle;
}
std::unique_ptr<DatagramClientSocket> QuicStreamFactory::CreateSocket(
NetLog* net_log,
const NetLogSource& source) {
auto socket = client_socket_factory_->CreateDatagramClientSocket(
DatagramSocket::DEFAULT_BIND, net_log, source);
if (params_.enable_socket_recv_optimization)
socket->EnableRecvOptimization();
return socket;
}
void QuicStreamFactory::OnIPAddressChanged() { void QuicStreamFactory::OnIPAddressChanged() {
LogPlatformNotificationInHistogram(NETWORK_IP_ADDRESS_CHANGED); LogPlatformNotificationInHistogram(NETWORK_IP_ADDRESS_CHANGED);
// Do nothing if connection migration is turned on. // Do nothing if connection migration is turned on.
...@@ -1768,6 +1632,29 @@ void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) { ...@@ -1768,6 +1632,29 @@ void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
} }
} }
void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) {
LogPlatformNotificationInHistogram(NETWORK_DISCONNECTED);
if (!params_.migrate_sessions_on_network_change_v2)
return;
ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
"OnNetworkDisconnected");
auto it = all_sessions_.begin();
// Sessions may be deleted while iterating through the map.
while (it != all_sessions_.end()) {
QuicChromiumClientSession* session = it->first;
++it;
session->OnNetworkDisconnectedV2(/*disconnected_network*/ network,
scoped_event_log.net_log());
}
}
// This method is expected to only be called when migrating from Cellular to
// WiFi on Android, and should always be preceded by OnNetworkMadeDefault().
void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) {
LogPlatformNotificationInHistogram(NETWORK_SOON_TO_DISCONNECT);
}
void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) { void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {
LogPlatformNotificationInHistogram(NETWORK_MADE_DEFAULT); LogPlatformNotificationInHistogram(NETWORK_MADE_DEFAULT);
if (!params_.migrate_sessions_on_network_change_v2) if (!params_.migrate_sessions_on_network_change_v2)
...@@ -1796,62 +1683,146 @@ void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) { ...@@ -1796,62 +1683,146 @@ void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {
set_is_quic_known_to_work_on_current_network(false); set_is_quic_known_to_work_on_current_network(false);
} }
void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) { void QuicStreamFactory::OnCertDBChanged() {
LogPlatformNotificationInHistogram(NETWORK_DISCONNECTED); // We should flush the sessions if we removed trust from a
if (!params_.migrate_sessions_on_network_change_v2) // cert, because a previously trusted server may have become
return; // untrusted.
//
// We should not flush the sessions if we added trust to a cert.
//
// Since the OnCertDBChanged method doesn't tell us what
// kind of change it is, we have to flush the socket
// pools to be safe.
MarkAllActiveSessionsGoingAway();
}
ScopedConnectionMigrationEventLog scoped_event_log(net_log_, void QuicStreamFactory::set_is_quic_known_to_work_on_current_network(
"OnNetworkDisconnected"); bool is_quic_known_to_work_on_current_network) {
auto it = all_sessions_.begin(); is_quic_known_to_work_on_current_network_ =
// Sessions may be deleted while iterating through the map. is_quic_known_to_work_on_current_network;
while (it != all_sessions_.end()) { if (!(local_address_ == IPEndPoint())) {
QuicChromiumClientSession* session = it->first; if (is_quic_known_to_work_on_current_network_) {
++it; http_server_properties_->SetLastLocalAddressWhenQuicWorked(
session->OnNetworkDisconnectedV2(/*disconnected_network*/ network, local_address_.address());
scoped_event_log.net_log()); } else {
http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
}
} }
} }
// This method is expected to only be called when migrating from Cellular to base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
// WiFi on Android, and should always be preceded by OnNetworkMadeDefault(). const quic::QuicServerId& server_id,
void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) { const NetworkIsolationKey& network_isolation_key) {
LogPlatformNotificationInHistogram(NETWORK_SOON_TO_DISCONNECT); // If |is_quic_known_to_work_on_current_network_| is false, then one of the
// following is true:
// 1) This is startup and QuicStreamFactory::CreateSession() and
// ConfigureSocket() have yet to be called, and it is not yet known
// if the current network is the last one where QUIC worked.
// 2) Startup has been completed, and QUIC has not been used
// successfully since startup, or on this network before.
if (!is_quic_known_to_work_on_current_network_) {
// If |need_to_check_persisted_supports_quic_| is false, this is case 1)
// above. If HasLastLocalAddressWhenQuicWorked() is also true, then there's
// a chance the current network is the last one on which QUIC worked. So
// only delay the request if there's no chance that is the case.
if (!need_to_check_persisted_supports_quic_ ||
!http_server_properties_->HasLastLocalAddressWhenQuicWorked()) {
return base::TimeDelta();
}
}
int64_t srtt = 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(
server_id, network_isolation_key);
// Picked 300ms based on mean time from
// Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
const int kDefaultRTT = 300 * quic::kNumMicrosPerMilli;
if (!srtt)
srtt = kDefaultRTT;
return base::TimeDelta::FromMicroseconds(srtt);
} }
NetworkHandle QuicStreamFactory::FindAlternateNetwork( void QuicStreamFactory::DumpMemoryStats(
NetworkHandle old_network) { base::trace_event::ProcessMemoryDump* pmd,
// Find a new network that sessions bound to |old_network| can be migrated to. const std::string& parent_absolute_name) const {
NetworkChangeNotifier::NetworkList network_list; if (all_sessions_.empty() && active_jobs_.empty())
NetworkChangeNotifier::GetConnectedNetworks(&network_list); return;
for (NetworkHandle new_network : network_list) { base::trace_event::MemoryAllocatorDump* factory_dump =
if (new_network != old_network) pmd->CreateAllocatorDump(parent_absolute_name + "/quic_stream_factory");
return new_network; size_t memory_estimate =
base::trace_event::EstimateMemoryUsage(all_sessions_) +
base::trace_event::EstimateMemoryUsage(active_sessions_) +
base::trace_event::EstimateMemoryUsage(session_aliases_) +
base::trace_event::EstimateMemoryUsage(ip_aliases_) +
base::trace_event::EstimateMemoryUsage(session_peer_ip_) +
base::trace_event::EstimateMemoryUsage(gone_away_aliases_) +
base::trace_event::EstimateMemoryUsage(active_jobs_) +
base::trace_event::EstimateMemoryUsage(active_cert_verifier_jobs_);
factory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
memory_estimate);
factory_dump->AddScalar("all_sessions",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
all_sessions_.size());
factory_dump->AddScalar("active_jobs",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
active_jobs_.size());
factory_dump->AddScalar("active_cert_jobs",
base::trace_event::MemoryAllocatorDump::kUnitsObjects,
active_cert_verifier_jobs_.size());
}
bool QuicStreamFactory::HasMatchingIpSession(const QuicSessionAliasKey& key,
const AddressList& address_list) {
const quic::QuicServerId& server_id(key.server_id());
DCHECK(!HasActiveSession(key.session_key()));
for (const IPEndPoint& address : address_list) {
if (!base::Contains(ip_aliases_, address))
continue;
const SessionSet& sessions = ip_aliases_[address];
for (QuicChromiumClientSession* session : sessions) {
if (!session->CanPool(server_id.host(), key.session_key().privacy_mode(),
key.session_key().socket_tag(),
key.session_key().network_isolation_key())) {
continue;
}
active_sessions_[key.session_key()] = session;
session_aliases_[session].insert(key);
return true;
}
} }
return NetworkChangeNotifier::kInvalidNetworkHandle; return false;
} }
std::unique_ptr<DatagramClientSocket> QuicStreamFactory::CreateSocket( void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
NetLog* net_log, auto iter = active_jobs_.find(job->key().session_key());
const NetLogSource& source) { DCHECK(iter != active_jobs_.end());
auto socket = client_socket_factory_->CreateDatagramClientSocket( if (rv == OK) {
DatagramSocket::DEFAULT_BIND, net_log, source); set_is_quic_known_to_work_on_current_network(true);
if (params_.enable_socket_recv_optimization)
socket->EnableRecvOptimization(); auto session_it = active_sessions_.find(job->key().session_key());
return socket; CHECK(session_it != active_sessions_.end());
QuicChromiumClientSession* session = session_it->second;
for (auto* request : iter->second->stream_requests()) {
// Do not notify |request| yet.
request->SetSession(session->CreateHandle(job->key().destination()));
}
}
for (auto* request : iter->second->stream_requests()) {
// Even though we're invoking callbacks here, we don't need to worry
// about |this| being deleted, because the factory is owned by the
// profile which can not be deleted via callbacks.
if (rv < 0) {
job->PopulateNetErrorDetails(request->net_error_details());
}
request->OnRequestComplete(rv);
}
active_jobs_.erase(iter);
} }
void QuicStreamFactory::OnCertDBChanged() { void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) {
// We should flush the sessions if we removed trust from a active_cert_verifier_jobs_.erase(job->server_id());
// cert, because a previously trusted server may have become
// untrusted.
//
// We should not flush the sessions if we added trust to a cert.
//
// Since the OnCertDBChanged method doesn't tell us what
// kind of change it is, we have to flush the socket
// pools to be safe.
MarkAllActiveSessionsGoingAway();
} }
bool QuicStreamFactory::HasActiveSession( bool QuicStreamFactory::HasActiveSession(
...@@ -1871,68 +1842,6 @@ bool QuicStreamFactory::HasActiveCertVerifierJob( ...@@ -1871,68 +1842,6 @@ bool QuicStreamFactory::HasActiveCertVerifierJob(
return base::Contains(active_cert_verifier_jobs_, server_id); return base::Contains(active_cert_verifier_jobs_, server_id);
} }
int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket,
IPEndPoint addr,
NetworkHandle network,
const SocketTag& socket_tag) {
socket->UseNonBlockingIO();
int rv;
if (params_.migrate_sessions_on_network_change_v2) {
// If caller leaves network unspecified, use current default network.
if (network == NetworkChangeNotifier::kInvalidNetworkHandle) {
rv = socket->ConnectUsingDefaultNetwork(addr);
} else {
rv = socket->ConnectUsingNetwork(network, addr);
}
} else {
rv = socket->Connect(addr);
}
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
return rv;
}
socket->ApplySocketTag(socket_tag);
rv = socket->SetReceiveBufferSize(kQuicSocketReceiveBufferSize);
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
return rv;
}
rv = socket->SetDoNotFragment();
// SetDoNotFragment is not implemented on all platforms, so ignore errors.
if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
return rv;
}
// Set a buffer large enough to contain the initial CWND's worth of packet
// to work around the problem with CHLO packets being sent out with the
// wrong encryption level, when the send buffer is full.
rv = socket->SetSendBufferSize(quic::kMaxOutgoingPacketSize * 20);
if (rv != OK) {
HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
return rv;
}
socket->GetLocalAddress(&local_address_);
if (need_to_check_persisted_supports_quic_) {
need_to_check_persisted_supports_quic_ = false;
if (http_server_properties_->WasLastLocalAddressWhenQuicWorked(
local_address_.address())) {
is_quic_known_to_work_on_current_network_ = true;
// Clear the persisted IP address, in case the network no longer supports
// QUIC so the next restart will require confirmation. It will be
// re-persisted when the first job completes successfully.
http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
}
}
return OK;
}
int QuicStreamFactory::CreateSession( int QuicStreamFactory::CreateSession(
const QuicSessionAliasKey& key, const QuicSessionAliasKey& key,
quic::ParsedQuicVersion quic_version, quic::ParsedQuicVersion quic_version,
...@@ -2087,6 +1996,13 @@ void QuicStreamFactory::ActivateSession(const QuicSessionAliasKey& key, ...@@ -2087,6 +1996,13 @@ void QuicStreamFactory::ActivateSession(const QuicSessionAliasKey& key,
session_peer_ip_[session] = peer_address; session_peer_ip_[session] = peer_address;
} }
void QuicStreamFactory::MarkAllActiveSessionsGoingAway() {
while (!active_sessions_.empty()) {
QuicChromiumClientSession* session = active_sessions_.begin()->second;
OnSessionGoingAway(session);
}
}
void QuicStreamFactory::ConfigureInitialRttEstimate( void QuicStreamFactory::ConfigureInitialRttEstimate(
const quic::QuicServerId& server_id, const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key, const NetworkIsolationKey& network_isolation_key,
...@@ -2123,6 +2039,14 @@ void QuicStreamFactory::ConfigureInitialRttEstimate( ...@@ -2123,6 +2039,14 @@ void QuicStreamFactory::ConfigureInitialRttEstimate(
SetInitialRttEstimate(base::TimeDelta(), INITIAL_RTT_DEFAULT, config); SetInitialRttEstimate(base::TimeDelta(), INITIAL_RTT_DEFAULT, config);
} }
int64_t QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) const {
const base::TimeDelta* srtt =
GetServerNetworkStatsSmoothedRtt(server_id, network_isolation_key);
return srtt == nullptr ? 0 : srtt->InMicroseconds();
}
const base::TimeDelta* QuicStreamFactory::GetServerNetworkStatsSmoothedRtt( const base::TimeDelta* QuicStreamFactory::GetServerNetworkStatsSmoothedRtt(
const quic::QuicServerId& server_id, const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) const { const NetworkIsolationKey& network_isolation_key) const {
...@@ -2135,14 +2059,6 @@ const base::TimeDelta* QuicStreamFactory::GetServerNetworkStatsSmoothedRtt( ...@@ -2135,14 +2059,6 @@ const base::TimeDelta* QuicStreamFactory::GetServerNetworkStatsSmoothedRtt(
return &(stats->srtt); return &(stats->srtt);
} }
int64_t QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) const {
const base::TimeDelta* srtt =
GetServerNetworkStatsSmoothedRtt(server_id, network_isolation_key);
return srtt == nullptr ? 0 : srtt->InMicroseconds();
}
bool QuicStreamFactory::WasQuicRecentlyBroken( bool QuicStreamFactory::WasQuicRecentlyBroken(
const QuicSessionKey& session_key) const { const QuicSessionKey& session_key) const {
const AlternativeService alternative_service( const AlternativeService alternative_service(
...@@ -2152,27 +2068,6 @@ bool QuicStreamFactory::WasQuicRecentlyBroken( ...@@ -2152,27 +2068,6 @@ bool QuicStreamFactory::WasQuicRecentlyBroken(
alternative_service, session_key.network_isolation_key()); alternative_service, session_key.network_isolation_key());
} }
bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) {
quic::QuicCryptoClientConfig::CachedState* cached = nullptr;
NetworkIsolationKey actual_network_isolation_key =
use_network_isolation_key_for_crypto_configs_ ? network_isolation_key
: NetworkIsolationKey();
auto map_iterator =
active_crypto_config_map_.find(actual_network_isolation_key);
if (map_iterator != active_crypto_config_map_.end()) {
cached = map_iterator->second->config()->LookupOrCreate(server_id);
} else {
auto mru_iterator =
recent_crypto_config_map_.Peek(actual_network_isolation_key);
if (mru_iterator != recent_crypto_config_map_.end()) {
cached = mru_iterator->second->config()->LookupOrCreate(server_id);
}
}
return !cached || cached->IsEmpty();
}
quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJob( quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJob(
const CryptoClientConfigHandle& crypto_config_handle, const CryptoClientConfigHandle& crypto_config_handle,
const quic::QuicServerId& server_id, const quic::QuicServerId& server_id,
...@@ -2197,6 +2092,86 @@ quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJob( ...@@ -2197,6 +2092,86 @@ quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJob(
return status; return status;
} }
void QuicStreamFactory::InitializeMigrationOptions() {
// The following list of options cannot be set immediately until
// prerequisites are met. Cache the initial setting in local variables and
// reset them in |params_|.
bool migrate_sessions_on_network_change =
params_.migrate_sessions_on_network_change_v2;
bool migrate_sessions_early = params_.migrate_sessions_early_v2;
bool retry_on_alternate_network_before_handshake =
params_.retry_on_alternate_network_before_handshake;
bool migrate_idle_sessions = params_.migrate_idle_sessions;
bool allow_port_migration = params_.allow_port_migration;
params_.migrate_sessions_on_network_change_v2 = false;
params_.migrate_sessions_early_v2 = false;
params_.allow_port_migration = false;
params_.retry_on_alternate_network_before_handshake = false;
params_.migrate_idle_sessions = false;
DCHECK(!(migrate_sessions_early && params_.go_away_on_path_degrading));
DCHECK(!(allow_port_migration && params_.go_away_on_path_degrading));
// TODO(zhongyi): deprecate |goaway_sessions_on_ip_change| if the experiment
// is no longer needed.
// goaway_sessions_on_ip_change and close_sessions_on_ip_change should never
// be simultaneously set to true.
DCHECK(!(params_.close_sessions_on_ip_change &&
params_.goaway_sessions_on_ip_change));
bool handle_ip_change = params_.close_sessions_on_ip_change ||
params_.goaway_sessions_on_ip_change;
// If IP address changes are handled explicitly, connection migration should
// not be set.
DCHECK(!(handle_ip_change && migrate_sessions_on_network_change));
if (handle_ip_change)
NetworkChangeNotifier::AddIPAddressObserver(this);
// Port migration and early migration both act on path degrading and thus can
// not be simultaneously set.
DCHECK(!allow_port_migration || !migrate_sessions_early);
if (allow_port_migration)
params_.allow_port_migration = true;
if (!NetworkChangeNotifier::AreNetworkHandlesSupported())
return;
NetworkChangeNotifier::AddNetworkObserver(this);
// Perform checks on the connection migration options.
if (!migrate_sessions_on_network_change) {
DCHECK(!migrate_sessions_early);
return;
}
// Enable migration on platform notifications.
params_.migrate_sessions_on_network_change_v2 = true;
if (!migrate_sessions_early) {
DCHECK(!migrate_idle_sessions &&
!retry_on_alternate_network_before_handshake);
return;
}
// Enable migration on path degrading.
params_.migrate_sessions_early_v2 = true;
// Set retransmittable on wire timeout for migration on path degrading if no
// value is specified.
if (retransmittable_on_wire_timeout_.IsZero()) {
retransmittable_on_wire_timeout_ = quic::QuicTime::Delta::FromMicroseconds(
kDefaultRetransmittableOnWireTimeout.InMicroseconds());
}
// Enable retry on alternate network before handshake.
if (retry_on_alternate_network_before_handshake)
params_.retry_on_alternate_network_before_handshake = true;
// Enable migration for idle sessions.
if (migrate_idle_sessions)
params_.migrate_idle_sessions = true;
}
void QuicStreamFactory::InitializeCachedStateInCryptoConfig( void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
const CryptoClientConfigHandle& crypto_config_handle, const CryptoClientConfigHandle& crypto_config_handle,
const quic::QuicServerId& server_id, const quic::QuicServerId& server_id,
...@@ -2372,4 +2347,25 @@ quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJobForTesting( ...@@ -2372,4 +2347,25 @@ quic::QuicAsyncStatus QuicStreamFactory::StartCertVerifyJobForTesting(
net_log); net_log);
} }
bool QuicStreamFactory::CryptoConfigCacheIsEmptyForTesting(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key) {
quic::QuicCryptoClientConfig::CachedState* cached = nullptr;
NetworkIsolationKey actual_network_isolation_key =
use_network_isolation_key_for_crypto_configs_ ? network_isolation_key
: NetworkIsolationKey();
auto map_iterator =
active_crypto_config_map_.find(actual_network_isolation_key);
if (map_iterator != active_crypto_config_map_.end()) {
cached = map_iterator->second->config()->LookupOrCreate(server_id);
} else {
auto mru_iterator =
recent_crypto_config_map_.Peek(actual_network_isolation_key);
if (mru_iterator != recent_crypto_config_map_.end()) {
cached = mru_iterator->second->config()->LookupOrCreate(server_id);
}
}
return !cached || cached->IsEmpty();
}
} // namespace net } // namespace net
...@@ -566,10 +566,6 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -566,10 +566,6 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
// Helper methods. // Helper methods.
bool WasQuicRecentlyBroken(const QuicSessionKey& session_key) const; bool WasQuicRecentlyBroken(const QuicSessionKey& session_key) const;
bool CryptoConfigCacheIsEmpty(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key);
// Starts an asynchronous job for cert verification if // Starts an asynchronous job for cert verification if
// |params_.race_cert_verification| is enabled and if there are cached certs // |params_.race_cert_verification| is enabled and if there are cached certs
// for the given |server_id|. // for the given |server_id|.
...@@ -630,6 +626,10 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -630,6 +626,10 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
int cert_verify_flags, int cert_verify_flags,
const NetLogWithSource& net_log); const NetLogWithSource& net_log);
bool CryptoConfigCacheIsEmptyForTesting(
const quic::QuicServerId& server_id,
const NetworkIsolationKey& network_isolation_key);
// Whether QUIC is known to work on current network. This is true when QUIC is // Whether QUIC is known to work on current network. This is true when QUIC is
// expected to work in general, rather than whether QUIC was broken / recently // expected to work in general, rather than whether QUIC was broken / recently
// broken when used with a particular server. That information is stored in // broken when used with a particular server. That information is stored in
......
...@@ -152,8 +152,8 @@ bool QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty( ...@@ -152,8 +152,8 @@ bool QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
QuicStreamFactory* factory, QuicStreamFactory* factory,
const quic::QuicServerId& quic_server_id, const quic::QuicServerId& quic_server_id,
const NetworkIsolationKey& network_isolation_key) { const NetworkIsolationKey& network_isolation_key) {
return factory->CryptoConfigCacheIsEmpty(quic_server_id, return factory->CryptoConfigCacheIsEmptyForTesting(quic_server_id,
network_isolation_key); network_isolation_key);
} }
void QuicStreamFactoryPeer::CacheDummyServerConfig( void QuicStreamFactoryPeer::CacheDummyServerConfig(
......
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