Chromium Code Reviews| Index: net/quic/quic_stream_factory.cc |
| diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc |
| index f44675595691c90063e47c5e72a166e20a05bbd2..942e057c9f57a8170a5428bab3aca4e79d147c13 100644 |
| --- a/net/quic/quic_stream_factory.cc |
| +++ b/net/quic/quic_stream_factory.cc |
| @@ -569,6 +569,7 @@ QuicStreamFactory::QuicStreamFactory( |
| bool delay_tcp_race, |
| bool store_server_configs_in_properties, |
| bool close_sessions_on_ip_change, |
| + bool migrate_sessions_on_net_change, |
| const QuicTagVector& connection_options) |
| : require_confirmation_(true), |
| host_resolver_(host_resolver), |
| @@ -613,6 +614,7 @@ QuicStreamFactory::QuicStreamFactory( |
| kQuicYieldAfterDurationMilliseconds)), |
| store_server_configs_in_properties_(store_server_configs_in_properties), |
| close_sessions_on_ip_change_(close_sessions_on_ip_change), |
| + migrate_sessions_on_net_change_(migrate_sessions_on_net_change), |
| port_seed_(random_generator_->RandUint64()), |
| check_persisted_supports_quic_(true), |
| has_initialized_data_(false), |
| @@ -651,7 +653,9 @@ QuicStreamFactory::QuicStreamFactory( |
| new PropertiesBasedQuicServerInfoFactory(http_server_properties_)); |
| } |
| - if (close_sessions_on_ip_change_) { |
| + if (migrate_sessions_on_net_change_) { |
| + NetworkChangeNotifier::AddNetworkObserver(this); |
| + } else if (close_sessions_on_ip_change_) { |
| NetworkChangeNotifier::AddIPAddressObserver(this); |
|
Ryan Hamilton
2015/11/17 04:57:28
So if migrate_ is true, then is close_ effectively
Jana
2015/11/18 04:31:41
Yes, since migrate_ and close_ are both experiment
|
| } |
| } |
| @@ -1131,11 +1135,103 @@ void QuicStreamFactory::ClearCachedStatesInCryptoConfig() { |
| crypto_config_.ClearCachedStates(); |
| } |
| +// We still need OnIPAddressChanged, but not for Android >= L. |
| +// pauljensen: How do we do this? |
| void QuicStreamFactory::OnIPAddressChanged() { |
| CloseAllSessions(ERR_NETWORK_CHANGED); |
| set_require_confirmation(true); |
| } |
| +void QuicStreamFactory::OnNetworkConnected( |
| + NetworkChangeNotifier::NetworkHandle network) { |
| + // Nothing to do. |
| +} |
| + |
| +void QuicStreamFactory::OnNetworkMadeDefault( |
| + NetworkChangeNotifier::NetworkHandle network) { |
| + // Nothing to do. |
| +} |
| + |
| +void QuicStreamFactory::OnNetworkDisconnected( |
| + NetworkChangeNotifier::NetworkHandle network) { |
| + MigrateOrCloseSessions(network); |
| +} |
| + |
| +void QuicStreamFactory::OnNetworkSoonToDisconnect( |
| + NetworkChangeNotifier::NetworkHandle network) { |
| + MigrateOrCloseSessions(network); |
| +} |
| + |
| +void QuicStreamFactory::MigrateOrCloseSessions( |
| + NetworkChangeNotifier::NetworkHandle network) { |
| + // TODO(jri): Need a "verified" flag on each network that gets set when |
| + // any data is received on the network. |
| + set_require_confirmation(true); |
| + |
| + // pauljensen: do we need the following "== network" check? |
| + NetworkChangeNotifier::NetworkList network_list; |
| + NetworkChangeNotifier::GetConnectedNetworks(&network_list); |
| + if (network_list.empty() || |
| + (network_list.size() == 1 && network_list[0] == network)) { |
| + CloseAllSessions(ERR_NETWORK_CHANGED); |
| + return; |
| + } |
| + |
| + // Find a new network that old sockets can be migrated to. |
| + // pauljensen: do we need the following "== network" check? |
| + NetworkChangeNotifier::NetworkHandle new_network = |
| + NetworkChangeNotifier::kInvalidNetworkHandle; |
| + for (NetworkChangeNotifier::NetworkHandle n : network_list) { |
| + if (n == network) { |
| + continue; |
| + } |
| + new_network = n; |
| + } |
| + |
| + DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, new_network); |
| + DCHECK_NE(network, new_network); |
| + |
| + for (auto& it : all_sessions_) { |
| + QuicChromiumClientSession* session = it.first; |
| + QuicServerId server_id = it.second; |
| + |
| + if (session->GetNumOpenStreams() == 0) { |
| + // If idle session, close session |
| + active_sessions_.erase(server_id); |
| + session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR); |
| + // } else if (session->current_network() == new_network) { |
| + // @@@ TODO (jri): store network and record in session when |
| + // BindToNetwork() is called. |
| + // If session is already using |network|, move on. |
| + // continue; |
| + continue; |
| + } |
| + // If session has active streams, |
| + // (i) make the session GO_AWAY, |
| + // (ii) create a new socket (which should be bound to the new interface), |
| + // (iii) migrate the session to using the new socket. |
| + OnSessionGoingAway(session); |
| + QuicConnection* connection = session->connection(); |
| + scoped_ptr<DatagramClientSocket> socket = |
| + CreateDatagramClientSocket(all_sessions_[session], session->net_log()); |
| + int rv = ConfigureDatagramClientSocket(socket.get(), |
| + connection->peer_address(), network); |
| + if (rv != OK) { |
| + session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR); |
| + continue; |
| + } |
| + QuicPacketReader* new_reader = new QuicPacketReader( |
| + socket.get(), clock_.get(), session, yield_after_packets_, |
| + yield_after_duration_, session->net_log()); |
| + DefaultPacketWriterFactory packet_writer_factory(socket.get()); |
| + QuicPacketWriter* new_writer = packet_writer_factory.Create(connection); |
| + |
| + if (!session->MigrateToSocket(socket.Pass(), new_reader, new_writer)) { |
|
Ryan Hamilton
2015/11/17 04:57:28
I think new_reader and new_writer are leaked here
Jana
2015/11/18 04:31:41
Doh! They're scoped_ptrs now, so the leak is fixed
|
| + session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR); |
| + } |
| + } |
| +} |
| + |
| void QuicStreamFactory::OnSSLConfigChanged() { |
| CloseAllSessions(ERR_CERT_DATABASE_CHANGED); |
| } |
| @@ -1169,13 +1265,9 @@ bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const { |
| return ContainsKey(active_jobs_, key); |
| } |
| -int QuicStreamFactory::CreateSession(const QuicServerId& server_id, |
| - int cert_verify_flags, |
| - scoped_ptr<QuicServerInfo> server_info, |
| - const AddressList& address_list, |
| - base::TimeTicks dns_resolution_end_time, |
| - const BoundNetLog& net_log, |
| - QuicChromiumClientSession** session) { |
| +scoped_ptr<DatagramClientSocket> QuicStreamFactory::CreateDatagramClientSocket( |
| + const QuicServerId& server_id, |
| + const BoundNetLog& net_log) { |
| bool enable_port_selection = enable_port_selection_; |
| if (enable_port_selection && |
| ContainsKey(gone_away_aliases_, server_id)) { |
| @@ -1185,20 +1277,33 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id, |
| enable_port_selection = false; |
| gone_away_aliases_.erase(server_id); |
| } |
| - |
| - QuicConnectionId connection_id = random_generator_->RandUint64(); |
| - IPEndPoint addr = *address_list.begin(); |
| scoped_refptr<PortSuggester> port_suggester = |
| new PortSuggester(server_id.host_port_pair(), port_seed_); |
| DatagramSocket::BindType bind_type = enable_port_selection ? |
| DatagramSocket::RANDOM_BIND : // Use our callback. |
| DatagramSocket::DEFAULT_BIND; // Use OS to randomize. |
| + |
| scoped_ptr<DatagramClientSocket> socket( |
| client_socket_factory_->CreateDatagramClientSocket( |
| bind_type, |
| base::Bind(&PortSuggester::SuggestPort, port_suggester), |
| net_log.net_log(), net_log.source())); |
| + UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested", |
| + port_suggester->call_count()); |
| + if (enable_port_selection) { |
| + DCHECK_LE(1u, port_suggester->call_count()); |
| + } else { |
| + DCHECK_EQ(0u, port_suggester->call_count()); |
| + } |
| + |
| + return socket; |
| +} |
| + |
| +int QuicStreamFactory::ConfigureDatagramClientSocket( |
| + DatagramClientSocket* socket, |
| + IPEndPoint addr, |
| + NetworkChangeNotifier::NetworkHandle network) { |
| if (enable_non_blocking_io_ && |
| client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) { |
| #if defined(OS_WIN) |
| @@ -1206,25 +1311,29 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id, |
| #endif |
| } |
| - int rv = socket->Connect(addr); |
| + // If caller leaves network unspecified, find current default. |
| + int rv; |
| + if (network == NetworkChangeNotifier::kInvalidNetworkHandle) { |
| + rv = socket->BindToDefaultNetwork(); |
| + } else { |
| + rv = socket->BindToNetwork(network); |
| + } |
| + if (rv != OK) { |
| + return rv; |
| + } |
| + rv = socket->Connect(addr); |
| if (rv != OK) { |
| HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET); |
| return rv; |
| } |
| - UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested", |
| - port_suggester->call_count()); |
| - if (enable_port_selection) { |
| - DCHECK_LE(1u, port_suggester->call_count()); |
| - } else { |
| - DCHECK_EQ(0u, port_suggester->call_count()); |
| - } |
| rv = socket->SetReceiveBufferSize(socket_receive_buffer_size_); |
| if (rv != OK) { |
| HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER); |
| 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. |
| @@ -1244,14 +1353,36 @@ int QuicStreamFactory::CreateSession(const QuicServerId& server_id, |
| } |
| } |
| - DefaultPacketWriterFactory packet_writer_factory(socket.get()); |
| + return OK; |
| +} |
| + |
| +int QuicStreamFactory::CreateSession(const QuicServerId& server_id, |
| + int cert_verify_flags, |
| + scoped_ptr<QuicServerInfo> server_info, |
| + const AddressList& address_list, |
| + base::TimeTicks dns_resolution_end_time, |
| + const BoundNetLog& net_log, |
| + QuicChromiumClientSession** session) { |
| + IPEndPoint addr = *address_list.begin(); |
| + |
| + scoped_ptr<DatagramClientSocket> socket = |
| + CreateDatagramClientSocket(server_id, net_log); |
| + |
| + int rv = ConfigureDatagramClientSocket( |
| + socket.get(), addr, NetworkChangeNotifier::kInvalidNetworkHandle); |
| + |
| + if (rv != OK) { |
| + return rv; |
| + } |
| + DefaultPacketWriterFactory packet_writer_factory(socket.get()); |
| if (!helper_.get()) { |
| helper_.reset( |
| new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(), |
| clock_.get(), random_generator_)); |
| } |
| + QuicConnectionId connection_id = random_generator_->RandUint64(); |
| QuicConnection* connection = new QuicConnection( |
| connection_id, addr, helper_.get(), packet_writer_factory, |
| true /* owns_writer */, Perspective::IS_CLIENT, supported_versions_); |