| Index: net/quic/quic_stream_factory.cc
|
| diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
|
| index 75cc0d746f5280b9b7475c8d6560a580444fc3fa..95297b2253f96cde01371ecc9429e1721b56ba9f 100644
|
| --- a/net/quic/quic_stream_factory.cc
|
| +++ b/net/quic/quic_stream_factory.cc
|
| @@ -679,7 +679,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);
|
| }
|
| }
|
| @@ -1156,11 +1158,117 @@ 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) {
|
| + // 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);
|
| + set_require_confirmation(true);
|
| + 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 (QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
|
| + it != all_sessions_.end(); ++it) {
|
| + 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;
|
| + } else {
|
| + // If session is active,
|
| + // (i) make the session GO_AWAY,
|
| + // (ii) create a new socket (which should be bound to the new interface),
|
| + // (iii) add a new PacketReader to the session to read from new socket,
|
| + // (iv) replace the connection's PacketWriter with a new PacketWriter
|
| + // that uses the new socket.
|
| + set_require_confirmation(true);
|
| + 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;
|
| + }
|
| +
|
| + if (!session->AddPacketReader(new QuicPacketReader(socket.get(),
|
| + clock_.get(),
|
| + session,
|
| + yield_after_packets_,
|
| + yield_after_duration_,
|
| + session->net_log()))) {
|
| + session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
|
| + continue;
|
| + }
|
| +
|
| + session->StartReading();
|
| + DefaultPacketWriterFactory packet_writer_factory(socket.get());
|
| + connection->SetQuicPacketWriter(packet_writer_factory.Create(connection),
|
| + /*owns_writer=*/true);
|
| +
|
| + session->AddSocket(socket.Pass());
|
| + }
|
| + }
|
| +}
|
| +
|
| void QuicStreamFactory::OnSSLConfigChanged() {
|
| CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
|
| }
|
| @@ -1182,8 +1290,7 @@ void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
|
| CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
|
| }
|
|
|
| -bool QuicStreamFactory::HasActiveSession(
|
| - const QuicServerId& server_id) const {
|
| +bool QuicStreamFactory::HasActiveSession(const QuicServerId& server_id) const {
|
| return ContainsKey(active_sessions_, server_id);
|
| }
|
|
|
| @@ -1191,13 +1298,8 @@ 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)) {
|
| @@ -1207,20 +1309,32 @@ 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)
|
| @@ -1228,25 +1342,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.
|
| @@ -1266,14 +1384,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, server_id.is_https(),
|
|
|