Commit e2661985 authored by jri's avatar jri Committed by Commit bot

Changes connection migration code to migrate on NetworkMadeDefault

instead of on SoonToDisconnect.

The NetworkMadeDefault notification is supposed to always be issued
before SoonToDisconnect, but there seems to be a bug in Android that
causes the order to sometimes be reversed. Current connection migration
looks for an alternate network on SoonToDisconnect, and this may not
work since there may be no alternate networks around. Since
NetworkMadeDefault guarantees that the new default network is around,
this CL changes connection migration code to migrate on
NetworkMadeDefault instead.

BUG=

Review-Url: https://codereview.chromium.org/2258893004
Cr-Commit-Position: refs/heads/master@{#413327}
parent 3a0ce10c
...@@ -1457,24 +1457,26 @@ void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) { ...@@ -1457,24 +1457,26 @@ void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
status_ = OPEN; status_ = OPEN;
} }
void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {} void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {
ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
"OnNetworkMadeDefault");
DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network);
MaybeMigrateOrCloseSessions(network, /*close_if_cannot_migrate=*/false,
scoped_event_log.net_log());
set_require_confirmation(true);
}
void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) { void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) {
ScopedConnectionMigrationEventLog scoped_event_log(net_log_, ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
"OnNetworkDisconnected"); "OnNetworkDisconnected");
MaybeMigrateOrCloseSessions(network, /*force_close=*/true, NetworkHandle new_network = FindAlternateNetwork(network);
MaybeMigrateOrCloseSessions(new_network, /*close_if_cannot_migrate=*/true,
scoped_event_log.net_log()); scoped_event_log.net_log());
set_require_confirmation(true);
} }
// This method is expected to only be called when migrating from Cellular to // This method is expected to only be called when migrating from Cellular to
// WiFi on Android. // WiFi on Android, and should always be preceded by OnNetworkMadeDefault().
void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) { void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) {}
ScopedConnectionMigrationEventLog scoped_event_log(
net_log_, "OnNetworkSoonToDisconnect");
MaybeMigrateOrCloseSessions(network, /*force_close=*/false,
scoped_event_log.net_log());
}
NetworkHandle QuicStreamFactory::FindAlternateNetwork( NetworkHandle QuicStreamFactory::FindAlternateNetwork(
NetworkHandle old_network) { NetworkHandle old_network) {
...@@ -1489,26 +1491,34 @@ NetworkHandle QuicStreamFactory::FindAlternateNetwork( ...@@ -1489,26 +1491,34 @@ NetworkHandle QuicStreamFactory::FindAlternateNetwork(
} }
void QuicStreamFactory::MaybeMigrateOrCloseSessions( void QuicStreamFactory::MaybeMigrateOrCloseSessions(
NetworkHandle network, NetworkHandle new_network,
bool force_close, bool close_if_cannot_migrate,
const BoundNetLog& bound_net_log) { const BoundNetLog& bound_net_log) {
DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network);
NetworkHandle new_network = FindAlternateNetwork(network);
QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin(); QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
while (it != all_sessions_.end()) { while (it != all_sessions_.end()) {
QuicChromiumClientSession* session = it->first; QuicChromiumClientSession* session = it->first;
++it; ++it;
if (session->GetDefaultSocket()->GetBoundNetwork() != network) { // Migration attempted, but no new network was found. Close session.
// If session is not bound to |network|, move on. if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) {
HistogramAndLogMigrationFailure(
bound_net_log, MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
session->connection_id(), "No alternate network found");
session->CloseSessionOnError(ERR_NETWORK_CHANGED,
QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
continue;
}
// If session is already bound to |new_network|, move on.
if (session->GetDefaultSocket()->GetBoundNetwork() == new_network) {
HistogramAndLogMigrationFailure( HistogramAndLogMigrationFailure(
bound_net_log, MIGRATION_STATUS_ALREADY_MIGRATED, bound_net_log, MIGRATION_STATUS_ALREADY_MIGRATED,
session->connection_id(), "Not bound to network"); session->connection_id(), "Already bound to new network");
continue; continue;
} }
// Close idle sessions.
if (session->GetNumActiveStreams() == 0) { if (session->GetNumActiveStreams() == 0) {
// Close idle sessions.
HistogramAndLogMigrationFailure( HistogramAndLogMigrationFailure(
bound_net_log, MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, bound_net_log, MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
session->connection_id(), "No active sessions"); session->connection_id(), "No active sessions");
...@@ -1516,42 +1526,28 @@ void QuicStreamFactory::MaybeMigrateOrCloseSessions( ...@@ -1516,42 +1526,28 @@ void QuicStreamFactory::MaybeMigrateOrCloseSessions(
ERR_NETWORK_CHANGED, QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS); ERR_NETWORK_CHANGED, QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS);
continue; continue;
} }
// If session has active streams, mark it as going away. // If session has active streams, mark it as going away.
OnSessionGoingAway(session); OnSessionGoingAway(session);
if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) { // Do not migrate sessions where connection migration is disabled.
// No new network was found.
// TODO (jri): Add histogram for this failure case.
bound_net_log.AddEvent(
NetLog::TYPE_QUIC_CONNECTION_MIGRATION_FAILURE,
base::Bind(&NetLogQuicConnectionMigrationFailureCallback,
session->connection_id(), "No new network"));
if (force_close) {
session->CloseSessionOnError(ERR_NETWORK_CHANGED,
QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
}
continue;
}
if (session->config()->DisableConnectionMigration()) { if (session->config()->DisableConnectionMigration()) {
// Do not migrate sessions where connection migration is disabled by
// config.
HistogramAndLogMigrationFailure(bound_net_log, MIGRATION_STATUS_DISABLED, HistogramAndLogMigrationFailure(bound_net_log, MIGRATION_STATUS_DISABLED,
session->connection_id(), session->connection_id(),
"Migration disabled"); "Migration disabled");
if (force_close) { if (close_if_cannot_migrate) {
// Close sessions where connection migration is disabled.
session->CloseSessionOnError(ERR_NETWORK_CHANGED, session->CloseSessionOnError(ERR_NETWORK_CHANGED,
QUIC_IP_ADDRESS_CHANGED); QUIC_IP_ADDRESS_CHANGED);
} }
continue; continue;
} }
// Do not migrate sessions with non-migratable streams.
if (session->HasNonMigratableStreams()) { if (session->HasNonMigratableStreams()) {
// Do not migrate sessions with non-migratable streams.
HistogramAndLogMigrationFailure( HistogramAndLogMigrationFailure(
bound_net_log, MIGRATION_STATUS_NON_MIGRATABLE_STREAM, bound_net_log, MIGRATION_STATUS_NON_MIGRATABLE_STREAM,
session->connection_id(), "Non-migratable stream"); session->connection_id(), "Non-migratable stream");
if (force_close) { if (close_if_cannot_migrate) {
// Close sessions with non-migratable streams.
session->CloseSessionOnError( session->CloseSessionOnError(
ERR_NETWORK_CHANGED, ERR_NETWORK_CHANGED,
QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM); QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM);
......
...@@ -283,15 +283,20 @@ class NET_EXPORT_PRIVATE QuicStreamFactory ...@@ -283,15 +283,20 @@ class NET_EXPORT_PRIVATE QuicStreamFactory
NetworkChangeNotifier::NetworkHandle FindAlternateNetwork( NetworkChangeNotifier::NetworkHandle FindAlternateNetwork(
NetworkChangeNotifier::NetworkHandle old_network); NetworkChangeNotifier::NetworkHandle old_network);
// Method that initiates migration of active sessions // Method that initiates migration of active sessions to |new_network|.
// currently bound to |network| to an alternate network, if one // If |new_network| is a valid network, sessions that can migrate are
// exists. Idle sessions bound to |network| are closed. If there is // migrated to |new_network|, and sessions not bound to |new_network|
// no alternate network to migrate active sessions onto, active // are left unchanged. Sessions with non-migratable streams are closed
// sessions are closed if |force_close| is true, and continue using // if |close_if_cannot_migrate| is true, and continue using their current
// |network| otherwise. Sessions not bound to |network| are left unchanged. // network otherwise.
void MaybeMigrateOrCloseSessions(NetworkChangeNotifier::NetworkHandle network, //
bool force_close, // If |new_network| is NetworkChangeNotifier::kInvalidNetworkHandle,
const BoundNetLog& bound_net_log); // there is no new network to migrate sessions onto, and all sessions are
// closed.
void MaybeMigrateOrCloseSessions(
NetworkChangeNotifier::NetworkHandle new_network,
bool close_if_cannot_migrate,
const BoundNetLog& bound_net_log);
// Method that initiates migration of |session| if |session| is // Method that initiates migration of |session| if |session| is
// active and if there is an alternate network than the one to which // active and if there is an alternate network than the one to which
......
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