Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: net/quic/quic_stream_factory.cc

Issue 1327923002: Migrates QUIC sessions to a new network when old network is (about to be) disconnected. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@home
Patch Set: Addressed comments Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/quic_stream_factory.h" 5 #include "net/quic/quic_stream_factory.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 if (!IsEcdsaSupported()) 672 if (!IsEcdsaSupported())
673 crypto_config_.DisableEcdsa(); 673 crypto_config_.DisableEcdsa();
674 // When disk cache is used to store the server configs, HttpCache code calls 674 // When disk cache is used to store the server configs, HttpCache code calls
675 // |set_quic_server_info_factory| if |quic_server_info_factory_| wasn't 675 // |set_quic_server_info_factory| if |quic_server_info_factory_| wasn't
676 // created. 676 // created.
677 if (store_server_configs_in_properties_) { 677 if (store_server_configs_in_properties_) {
678 quic_server_info_factory_.reset( 678 quic_server_info_factory_.reset(
679 new PropertiesBasedQuicServerInfoFactory(http_server_properties_)); 679 new PropertiesBasedQuicServerInfoFactory(http_server_properties_));
680 } 680 }
681 681
682 if (close_sessions_on_ip_change_) { 682 if (migrate_sessions_on_net_change_) {
683 NetworkChangeNotifier::AddNetworkObserver(this);
684 } else if (close_sessions_on_ip_change_) {
683 NetworkChangeNotifier::AddIPAddressObserver(this); 685 NetworkChangeNotifier::AddIPAddressObserver(this);
684 } 686 }
685 } 687 }
686 688
687 QuicStreamFactory::~QuicStreamFactory() { 689 QuicStreamFactory::~QuicStreamFactory() {
688 CloseAllSessions(ERR_ABORTED); 690 CloseAllSessions(ERR_ABORTED);
689 while (!all_sessions_.empty()) { 691 while (!all_sessions_.empty()) {
690 delete all_sessions_.begin()->first; 692 delete all_sessions_.begin()->first;
691 all_sessions_.erase(all_sessions_.begin()); 693 all_sessions_.erase(all_sessions_.begin());
692 } 694 }
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
1149 list->Append(session->GetInfoAsValue(hosts)); 1151 list->Append(session->GetInfoAsValue(hosts));
1150 } 1152 }
1151 } 1153 }
1152 return list.Pass(); 1154 return list.Pass();
1153 } 1155 }
1154 1156
1155 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() { 1157 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
1156 crypto_config_.ClearCachedStates(); 1158 crypto_config_.ClearCachedStates();
1157 } 1159 }
1158 1160
1161 // We still need OnIPAddressChanged, but not for Android >= L.
1162 // pauljensen: How do we do this?
1159 void QuicStreamFactory::OnIPAddressChanged() { 1163 void QuicStreamFactory::OnIPAddressChanged() {
1160 CloseAllSessions(ERR_NETWORK_CHANGED); 1164 CloseAllSessions(ERR_NETWORK_CHANGED);
1161 set_require_confirmation(true); 1165 set_require_confirmation(true);
1162 } 1166 }
1163 1167
1168 void QuicStreamFactory::OnNetworkConnected(
1169 NetworkChangeNotifier::NetworkHandle network) {
1170 // Nothing to do.
1171 }
1172
1173 void QuicStreamFactory::OnNetworkMadeDefault(
1174 NetworkChangeNotifier::NetworkHandle network) {
1175 // Nothing to do.
1176 }
1177
1178 void QuicStreamFactory::OnNetworkDisconnected(
1179 NetworkChangeNotifier::NetworkHandle network) {
1180 MigrateOrCloseSessions(network);
1181 }
1182
1183 void QuicStreamFactory::OnNetworkSoonToDisconnect(
1184 NetworkChangeNotifier::NetworkHandle network) {
1185 MigrateOrCloseSessions(network);
1186 }
1187
1188 void QuicStreamFactory::MigrateOrCloseSessions(
1189 NetworkChangeNotifier::NetworkHandle network) {
1190 // pauljensen: do we need the following "== network" check?
1191 NetworkChangeNotifier::NetworkList network_list;
1192 NetworkChangeNotifier::GetConnectedNetworks(&network_list);
1193 if (network_list.empty() ||
1194 (network_list.size() == 1 && network_list[0] == network)) {
1195 CloseAllSessions(ERR_NETWORK_CHANGED);
1196 set_require_confirmation(true);
1197 return;
1198 }
1199
1200 // Find a new network that old sockets can be migrated to.
1201 // pauljensen: do we need the following "== network" check?
1202 NetworkChangeNotifier::NetworkHandle new_network =
1203 NetworkChangeNotifier::kInvalidNetworkHandle;
1204 for (NetworkChangeNotifier::NetworkHandle n : network_list) {
1205 if (n == network) {
1206 continue;
1207 }
1208 new_network = n;
1209 }
1210
1211 DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, new_network);
1212 DCHECK_NE(network, new_network);
1213
1214 for (QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
1215 it != all_sessions_.end(); ++it) {
1216 QuicChromiumClientSession* session = it->first;
1217 QuicServerId server_id = it->second;
1218
1219 if (session->GetNumOpenStreams() == 0) {
1220 // If idle session, close session
1221 active_sessions_.erase(server_id);
1222 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1223 // } else if (session->current_network() == new_network) {
1224 // @@@ TODO (jri): store network and record in session when
1225 // BindToNetwork() is called.
1226 // If session is already using |network|, move on.
1227 // continue;
1228 } else {
1229 // If session is active,
1230 // (i) make the session GO_AWAY,
1231 // (ii) create a new socket (which should be bound to the new interface),
1232 // (iii) add a new PacketReader to the session to read from new socket,
1233 // (iv) replace the connection's PacketWriter with a new PacketWriter
1234 // that uses the new socket.
1235 set_require_confirmation(true);
1236 OnSessionGoingAway(session);
1237 QuicConnection* connection = session->connection();
1238
1239 scoped_ptr<DatagramClientSocket> socket =
1240 CreateDatagramClientSocket(all_sessions_[session],
1241 session->net_log());
1242
1243 int rv = ConfigureDatagramClientSocket(socket.get(),
1244 connection->peer_address(),
1245 network);
1246
1247 if (rv != OK) {
1248 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1249 continue;
1250 }
1251
1252 if (!session->AddPacketReader(new QuicPacketReader(socket.get(),
1253 clock_.get(),
1254 session,
1255 yield_after_packets_,
1256 yield_after_duration_,
1257 session->net_log()))) {
1258 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1259 continue;
1260 }
1261
1262 session->StartReading();
1263 DefaultPacketWriterFactory packet_writer_factory(socket.get());
1264 connection->SetQuicPacketWriter(packet_writer_factory.Create(connection),
1265 /*owns_writer=*/true);
1266
1267 session->AddSocket(socket.Pass());
1268 }
1269 }
1270 }
1271
1164 void QuicStreamFactory::OnSSLConfigChanged() { 1272 void QuicStreamFactory::OnSSLConfigChanged() {
1165 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 1273 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
1166 } 1274 }
1167 1275
1168 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) { 1276 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
1169 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 1277 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
1170 } 1278 }
1171 1279
1172 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) { 1280 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
1173 // We should flush the sessions if we removed trust from a 1281 // We should flush the sessions if we removed trust from a
1174 // cert, because a previously trusted server may have become 1282 // cert, because a previously trusted server may have become
1175 // untrusted. 1283 // untrusted.
1176 // 1284 //
1177 // We should not flush the sessions if we added trust to a cert. 1285 // We should not flush the sessions if we added trust to a cert.
1178 // 1286 //
1179 // Since the OnCACertChanged method doesn't tell us what 1287 // Since the OnCACertChanged method doesn't tell us what
1180 // kind of change it is, we have to flush the socket 1288 // kind of change it is, we have to flush the socket
1181 // pools to be safe. 1289 // pools to be safe.
1182 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 1290 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
1183 } 1291 }
1184 1292
1185 bool QuicStreamFactory::HasActiveSession( 1293 bool QuicStreamFactory::HasActiveSession(const QuicServerId& server_id) const {
1186 const QuicServerId& server_id) const {
1187 return ContainsKey(active_sessions_, server_id); 1294 return ContainsKey(active_sessions_, server_id);
1188 } 1295 }
1189 1296
1190 bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const { 1297 bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const {
1191 return ContainsKey(active_jobs_, key); 1298 return ContainsKey(active_jobs_, key);
1192 } 1299 }
1193 1300
1194 int QuicStreamFactory::CreateSession(const QuicServerId& server_id, 1301 scoped_ptr<DatagramClientSocket> QuicStreamFactory::CreateDatagramClientSocket(
1195 int cert_verify_flags, 1302 const QuicServerId& server_id, const BoundNetLog& net_log) {
1196 scoped_ptr<QuicServerInfo> server_info,
1197 const AddressList& address_list,
1198 base::TimeTicks dns_resolution_end_time,
1199 const BoundNetLog& net_log,
1200 QuicChromiumClientSession** session) {
1201 bool enable_port_selection = enable_port_selection_; 1303 bool enable_port_selection = enable_port_selection_;
1202 if (enable_port_selection && 1304 if (enable_port_selection &&
1203 ContainsKey(gone_away_aliases_, server_id)) { 1305 ContainsKey(gone_away_aliases_, server_id)) {
1204 // Disable port selection when the server is going away. 1306 // Disable port selection when the server is going away.
1205 // There is no point in trying to return to the same server, if 1307 // There is no point in trying to return to the same server, if
1206 // that server is no longer handling requests. 1308 // that server is no longer handling requests.
1207 enable_port_selection = false; 1309 enable_port_selection = false;
1208 gone_away_aliases_.erase(server_id); 1310 gone_away_aliases_.erase(server_id);
1209 } 1311 }
1210
1211 QuicConnectionId connection_id = random_generator_->RandUint64();
1212 IPEndPoint addr = *address_list.begin();
1213 scoped_refptr<PortSuggester> port_suggester = 1312 scoped_refptr<PortSuggester> port_suggester =
1214 new PortSuggester(server_id.host_port_pair(), port_seed_); 1313 new PortSuggester(server_id.host_port_pair(), port_seed_);
1215 DatagramSocket::BindType bind_type = enable_port_selection ? 1314 DatagramSocket::BindType bind_type = enable_port_selection ?
1216 DatagramSocket::RANDOM_BIND : // Use our callback. 1315 DatagramSocket::RANDOM_BIND : // Use our callback.
1217 DatagramSocket::DEFAULT_BIND; // Use OS to randomize. 1316 DatagramSocket::DEFAULT_BIND; // Use OS to randomize.
1317
1218 scoped_ptr<DatagramClientSocket> socket( 1318 scoped_ptr<DatagramClientSocket> socket(
1219 client_socket_factory_->CreateDatagramClientSocket( 1319 client_socket_factory_->CreateDatagramClientSocket(
1220 bind_type, 1320 bind_type,
1221 base::Bind(&PortSuggester::SuggestPort, port_suggester), 1321 base::Bind(&PortSuggester::SuggestPort, port_suggester),
1222 net_log.net_log(), net_log.source())); 1322 net_log.net_log(), net_log.source()));
1223 1323
1324 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1325 port_suggester->call_count());
1326 if (enable_port_selection) {
1327 DCHECK_LE(1u, port_suggester->call_count());
1328 } else {
1329 DCHECK_EQ(0u, port_suggester->call_count());
1330 }
1331
1332 return socket;
1333 }
1334
1335 int QuicStreamFactory::ConfigureDatagramClientSocket(
1336 DatagramClientSocket* socket, IPEndPoint addr,
1337 NetworkChangeNotifier::NetworkHandle network) {
1224 if (enable_non_blocking_io_ && 1338 if (enable_non_blocking_io_ &&
1225 client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) { 1339 client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) {
1226 #if defined(OS_WIN) 1340 #if defined(OS_WIN)
1227 static_cast<UDPClientSocket*>(socket.get())->UseNonBlockingIO(); 1341 static_cast<UDPClientSocket*>(socket.get())->UseNonBlockingIO();
1228 #endif 1342 #endif
1229 } 1343 }
1230 1344
1231 int rv = socket->Connect(addr); 1345 // If caller leaves network unspecified, find current default.
1346 int rv;
1347 if (network == NetworkChangeNotifier::kInvalidNetworkHandle) {
1348 rv = socket->BindToDefaultNetwork();
1349 } else {
1350 rv = socket->BindToNetwork(network);
1351 }
1352 if (rv != OK) {
1353 return rv;
1354 }
1232 1355
1356 rv = socket->Connect(addr);
1233 if (rv != OK) { 1357 if (rv != OK) {
1234 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET); 1358 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
1235 return rv; 1359 return rv;
1236 } 1360 }
1237 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1238 port_suggester->call_count());
1239 if (enable_port_selection) {
1240 DCHECK_LE(1u, port_suggester->call_count());
1241 } else {
1242 DCHECK_EQ(0u, port_suggester->call_count());
1243 }
1244 1361
1245 rv = socket->SetReceiveBufferSize(socket_receive_buffer_size_); 1362 rv = socket->SetReceiveBufferSize(socket_receive_buffer_size_);
1246 if (rv != OK) { 1363 if (rv != OK) {
1247 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER); 1364 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
1248 return rv; 1365 return rv;
1249 } 1366 }
1367
1250 // Set a buffer large enough to contain the initial CWND's worth of packet 1368 // Set a buffer large enough to contain the initial CWND's worth of packet
1251 // to work around the problem with CHLO packets being sent out with the 1369 // to work around the problem with CHLO packets being sent out with the
1252 // wrong encryption level, when the send buffer is full. 1370 // wrong encryption level, when the send buffer is full.
1253 rv = socket->SetSendBufferSize(kMaxPacketSize * 20); 1371 rv = socket->SetSendBufferSize(kMaxPacketSize * 20);
1254 if (rv != OK) { 1372 if (rv != OK) {
1255 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER); 1373 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
1256 return rv; 1374 return rv;
1257 } 1375 }
1258 1376
1259 socket->GetLocalAddress(&local_address_); 1377 socket->GetLocalAddress(&local_address_);
1260 if (check_persisted_supports_quic_) { 1378 if (check_persisted_supports_quic_) {
1261 check_persisted_supports_quic_ = false; 1379 check_persisted_supports_quic_ = false;
1262 IPAddressNumber last_address; 1380 IPAddressNumber last_address;
1263 if (http_server_properties_->GetSupportsQuic(&last_address) && 1381 if (http_server_properties_->GetSupportsQuic(&last_address) &&
1264 last_address == local_address_.address()) { 1382 last_address == local_address_.address()) {
1265 require_confirmation_ = false; 1383 require_confirmation_ = false;
1266 } 1384 }
1267 } 1385 }
1268 1386
1387 return OK;
1388 }
1389
1390 int QuicStreamFactory::CreateSession(const QuicServerId& server_id,
1391 int cert_verify_flags,
1392 scoped_ptr<QuicServerInfo> server_info,
1393 const AddressList& address_list,
1394 base::TimeTicks dns_resolution_end_time,
1395 const BoundNetLog& net_log,
1396 QuicChromiumClientSession** session) {
1397 IPEndPoint addr = *address_list.begin();
1398
1399 scoped_ptr<DatagramClientSocket> socket =
1400 CreateDatagramClientSocket(server_id, net_log);
1401
1402 int rv = ConfigureDatagramClientSocket(socket.get(), addr,
1403 NetworkChangeNotifier::kInvalidNetworkHandle);
1404
1405 if (rv != OK) {
1406 return rv;
1407 }
1408
1269 DefaultPacketWriterFactory packet_writer_factory(socket.get()); 1409 DefaultPacketWriterFactory packet_writer_factory(socket.get());
1270
1271 if (!helper_.get()) { 1410 if (!helper_.get()) {
1272 helper_.reset( 1411 helper_.reset(
1273 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(), 1412 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
1274 clock_.get(), random_generator_)); 1413 clock_.get(), random_generator_));
1275 } 1414 }
1276 1415
1416 QuicConnectionId connection_id = random_generator_->RandUint64();
1277 QuicConnection* connection = new QuicConnection( 1417 QuicConnection* connection = new QuicConnection(
1278 connection_id, addr, helper_.get(), packet_writer_factory, 1418 connection_id, addr, helper_.get(), packet_writer_factory,
1279 true /* owns_writer */, Perspective::IS_CLIENT, server_id.is_https(), 1419 true /* owns_writer */, Perspective::IS_CLIENT, server_id.is_https(),
1280 supported_versions_); 1420 supported_versions_);
1281 connection->SetMaxPacketLength(max_packet_length_); 1421 connection->SetMaxPacketLength(max_packet_length_);
1282 1422
1283 InitializeCachedStateInCryptoConfig(server_id, server_info); 1423 InitializeCachedStateInCryptoConfig(server_id, server_info);
1284 1424
1285 QuicConfig config = config_; 1425 QuicConfig config = config_;
1286 config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_); 1426 config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_);
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
1478 // Since the session was active, there's no longer an 1618 // Since the session was active, there's no longer an
1479 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP 1619 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1480 // job also fails. So to avoid not using QUIC when we otherwise could, we mark 1620 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1481 // it as recently broken, which means that 0-RTT will be disabled but we'll 1621 // it as recently broken, which means that 0-RTT will be disabled but we'll
1482 // still race. 1622 // still race.
1483 http_server_properties_->MarkAlternativeServiceRecentlyBroken( 1623 http_server_properties_->MarkAlternativeServiceRecentlyBroken(
1484 alternative_service); 1624 alternative_service);
1485 } 1625 }
1486 1626
1487 } // namespace net 1627 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698