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

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: Iteration with new API 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
« no previous file with comments | « net/quic/quic_stream_factory.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 #endif 49 #endif
50 50
51 #if defined(USE_OPENSSL) 51 #if defined(USE_OPENSSL)
52 #include <openssl/aead.h> 52 #include <openssl/aead.h>
53 #include "crypto/openssl_util.h" 53 #include "crypto/openssl_util.h"
54 #else 54 #else
55 #include "base/cpu.h" 55 #include "base/cpu.h"
56 #endif 56 #endif
57 57
58 using std::min; 58 using std::min;
59 using NetworkChangeNotifier::NetworkHandle;
59 60
60 namespace net { 61 namespace net {
61 62
62 namespace { 63 namespace {
63 64
64 enum CreateSessionFailure { 65 enum CreateSessionFailure {
65 CREATION_ERROR_CONNECTING_SOCKET, 66 CREATION_ERROR_CONNECTING_SOCKET,
66 CREATION_ERROR_SETTING_RECEIVE_BUFFER, 67 CREATION_ERROR_SETTING_RECEIVE_BUFFER,
67 CREATION_ERROR_SETTING_SEND_BUFFER, 68 CREATION_ERROR_SETTING_SEND_BUFFER,
68 CREATION_ERROR_MAX 69 CREATION_ERROR_MAX
69 }; 70 };
70 71
71 // When a connection is idle for 30 seconds it will be closed. 72 // When a connection is idle for 30 seconds it will be closed.
72 const int kIdleConnectionTimeoutSeconds = 30; 73 const int kIdleConnectionTimeoutSeconds = 30;
73 74
74 // The maximum receive window sizes for QUIC sessions and streams. 75 // The maximum receive window sizes for QUIC sessions and streams.
75 const int32 kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB 76 const int32 kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
76 const int32 kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB 77 const int32 kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
77 78
78 // Set the maximum number of undecryptable packets the connection will store. 79 // Set the maximum number of undecryptable packets the connection will store.
79 const int32 kMaxUndecryptablePackets = 100; 80 const int32 kMaxUndecryptablePackets = 100;
80 81
82 // A default NetworkHandle.
83 const NetworkHandle kDefaultNetworkHandle = -2;
pauljensen 2015/10/14 11:51:34 This is a little sketchy for my liking. I'd sugge
Jana 2015/10/16 23:11:00 I think this is all sketchy :-) But, yeah, it seem
84
81 void HistogramCreateSessionFailure(enum CreateSessionFailure error) { 85 void HistogramCreateSessionFailure(enum CreateSessionFailure error) {
82 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error, 86 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error,
83 CREATION_ERROR_MAX); 87 CREATION_ERROR_MAX);
84 } 88 }
85 89
86 bool IsEcdsaSupported() { 90 bool IsEcdsaSupported() {
87 #if defined(OS_WIN) 91 #if defined(OS_WIN)
88 if (base::win::GetVersion() < base::win::VERSION_VISTA) 92 if (base::win::GetVersion() < base::win::VERSION_VISTA)
89 return false; 93 return false;
90 #endif 94 #endif
(...skipping 1039 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 list->Append(session->GetInfoAsValue(hosts)); 1134 list->Append(session->GetInfoAsValue(hosts));
1131 } 1135 }
1132 } 1136 }
1133 return list.Pass(); 1137 return list.Pass();
1134 } 1138 }
1135 1139
1136 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() { 1140 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
1137 crypto_config_.ClearCachedStates(); 1141 crypto_config_.ClearCachedStates();
1138 } 1142 }
1139 1143
1144 // We still need OnIPAddressChanged, but not for Android >= L.
1145 // pauljensen: How do we do this?
pauljensen 2015/10/14 11:51:34 Where do you register for events? (i.e. call Netwo
Jana 2015/10/16 23:11:00 *Facepalm*. So I discovered that we do not actuall
1140 void QuicStreamFactory::OnIPAddressChanged() { 1146 void QuicStreamFactory::OnIPAddressChanged() {
1141 CloseAllSessions(ERR_NETWORK_CHANGED); 1147 CloseAllSessions(ERR_NETWORK_CHANGED);
1142 set_require_confirmation(true); 1148 set_require_confirmation(true);
1143 } 1149 }
1144 1150
1151 void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
1152 // Nothing to do.
1153 }
1154
1155 void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {
1156 // Nothing to do.
1157 }
1158
1159 void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) {
1160 MigrateOrCloseSessions(network);
1161 }
1162
1163 void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) {
1164 MigrateOrCloseSessions(network);
1165 }
1166
1167 void QuicStreamFactory::MigrateOrCloseSessions(NetworkHandle network) {
1168 // pauljensen: do we need the following "== network" check?
pauljensen 2015/10/14 11:51:34 seems like a good idea
Jana 2015/10/16 23:11:00 Acknowledged.
1169 NetworkList network_list;
1170 GetConnectedNetworks(&network_list);
1171 if (network_list.isEmpty() ||
1172 (network_list.size() == 1 && network_list[0] == network)) {
1173 CloseAllSessions(ERR_NETWORK_CHANGED);
1174 set_require_confirmation(true);
1175 return;
1176 }
1177
1178 // Find a new network that old sockets can be migrated to.
1179 // pauljensen: do we need the following "== network" check?
pauljensen 2015/10/14 11:51:34 seems like a good idea
Jana 2015/10/16 23:11:00 Acknowledged.
1180 NetworkHandle new_network = kInvalidNetworkHandle;
1181 for (NetworkHandle n : network_list) {
1182 if (n == network) {
1183 continue;
1184 }
1185 new_network = n;
1186 }
1187
1188 DCHECK_NE(kInvalidNetworkHandle, new_network);
1189 DCHECK_NE(network, new_network);
1190
1191 for (QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
1192 it != all_sessions_.end(); ++it) {
1193 QuicChromiumClientSession* session = it->first;
1194 QuicServerId server_id = it->second;
1195
1196 if (session->GetNumOpenStreams() == 0) {
1197 // If idle session, close session
1198 active_sessions_.erase(server_id);
1199 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1200 } else if (session->current_network() == new_network) {
1201 // @@@ TODO (jri): store network and record in session when
1202 // BindToNetwork() is called.
1203 // If session is already using |network|, move on.
1204 continue;
1205 } else {
1206 // If session is active,
1207 // (i) make the session GO_AWAY,
1208 // (ii) create a new socket (which should be bound to the new interface),
1209 // (iii) add a new PacketReader to the session to read from new socket,
1210 // (iv) replace the connection's PacketWriter with a new PacketWriter
1211 // that uses the new socket.
1212 set_require_confirmation(true);
1213 OnSessionGoingAway(session);
1214 scoped_ptr<DatagramClientSocket> socket;
1215 int rv = CreateAndConfigureDatagramSocket(&socket,
1216 all_sessions[*session],
1217 connection->peer_address(),
1218 session->net_log(),
1219 new_network);
1220 if (rv != OK) {
1221 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1222 continue;
1223 }
1224
1225 if (!session->AddPacketReader(new QuicPacketReader(socket.get(),
1226 clock_.get(),
1227 session,
1228 yield_after_packets_,
1229 yield_after_duration_,
1230 session->net_log()))) {
1231 session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
1232 continue;
1233 }
1234
1235 session->StartReading();
1236 DefaultPacketWriterFactory packet_writer_factory(socket.get());
1237 QuicConnection* connection = session->connection();
1238 connection->SetQuicPacketWriter(packet_writer_factory.Create(connection),
1239 /*owns_writer=*/true);
1240
1241 session->AddSocket(socket.Pass());
1242 }
1243 }
1244 }
1245
1145 void QuicStreamFactory::OnSSLConfigChanged() { 1246 void QuicStreamFactory::OnSSLConfigChanged() {
1146 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 1247 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
1147 } 1248 }
1148 1249
1149 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) { 1250 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
1150 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 1251 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
1151 } 1252 }
1152 1253
1153 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) { 1254 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
1154 // We should flush the sessions if we removed trust from a 1255 // We should flush the sessions if we removed trust from a
(...skipping 10 matching lines...) Expand all
1165 1266
1166 bool QuicStreamFactory::HasActiveSession( 1267 bool QuicStreamFactory::HasActiveSession(
1167 const QuicServerId& server_id) const { 1268 const QuicServerId& server_id) const {
1168 return ContainsKey(active_sessions_, server_id); 1269 return ContainsKey(active_sessions_, server_id);
1169 } 1270 }
1170 1271
1171 bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const { 1272 bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const {
1172 return ContainsKey(active_jobs_, key); 1273 return ContainsKey(active_jobs_, key);
1173 } 1274 }
1174 1275
1175 int QuicStreamFactory::CreateSession(const QuicServerId& server_id, 1276 int QuicStreamFactory::CreateAndConfigureDatagramSocket(
1176 int cert_verify_flags, 1277 scoped_ptr<DatagramClientSocket>* new_socket,
pauljensen 2015/10/14 11:51:34 http://dev.chromium.org/developers/smart-pointer-g
Jana 2015/10/16 23:11:00 Done.
1177 scoped_ptr<QuicServerInfo> server_info, 1278 const QuicServerId& server_id,
1178 const AddressList& address_list, 1279 IPEndPoint addr,
1179 base::TimeTicks dns_resolution_end_time, 1280 const BoundNetLog& net_log,
1180 const BoundNetLog& net_log, 1281 NetworkHandle network) {
1181 QuicChromiumClientSession** session) {
1182 bool enable_port_selection = enable_port_selection_; 1282 bool enable_port_selection = enable_port_selection_;
1183 if (enable_port_selection && 1283 if (enable_port_selection &&
1184 ContainsKey(gone_away_aliases_, server_id)) { 1284 ContainsKey(gone_away_aliases_, server_id)) {
1185 // Disable port selection when the server is going away. 1285 // Disable port selection when the server is going away.
1186 // There is no point in trying to return to the same server, if 1286 // There is no point in trying to return to the same server, if
1187 // that server is no longer handling requests. 1287 // that server is no longer handling requests.
1188 enable_port_selection = false; 1288 enable_port_selection = false;
1189 gone_away_aliases_.erase(server_id); 1289 gone_away_aliases_.erase(server_id);
1190 } 1290 }
1191 1291
1192 QuicConnectionId connection_id = random_generator_->RandUint64();
1193 IPEndPoint addr = *address_list.begin();
1194 scoped_refptr<PortSuggester> port_suggester = 1292 scoped_refptr<PortSuggester> port_suggester =
1195 new PortSuggester(server_id.host_port_pair(), port_seed_); 1293 new PortSuggester(server_id.host_port_pair(), port_seed_);
1196 DatagramSocket::BindType bind_type = enable_port_selection ? 1294 DatagramSocket::BindType bind_type = enable_port_selection ?
1197 DatagramSocket::RANDOM_BIND : // Use our callback. 1295 DatagramSocket::RANDOM_BIND : // Use our callback.
1198 DatagramSocket::DEFAULT_BIND; // Use OS to randomize. 1296 DatagramSocket::DEFAULT_BIND; // Use OS to randomize.
1199 scoped_ptr<DatagramClientSocket> socket( 1297 scoped_ptr<DatagramClientSocket> socket(
1200 client_socket_factory_->CreateDatagramClientSocket( 1298 client_socket_factory_->CreateDatagramClientSocket(
1201 bind_type, 1299 bind_type,
1202 base::Bind(&PortSuggester::SuggestPort, port_suggester), 1300 base::Bind(&PortSuggester::SuggestPort, port_suggester),
1203 net_log.net_log(), net_log.source())); 1301 net_log.net_log(), net_log.source()));
1204 1302
1205 if (enable_non_blocking_io_ && 1303 if (enable_non_blocking_io_ &&
1206 client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) { 1304 client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) {
1207 #if defined(OS_WIN) 1305 #if defined(OS_WIN)
1208 static_cast<UDPClientSocket*>(socket.get())->UseNonBlockingIO(); 1306 static_cast<UDPClientSocket*>(socket.get())->UseNonBlockingIO();
1209 #endif 1307 #endif
1210 } 1308 }
1211 1309
1212 int rv = socket->Connect(addr); 1310 // If caller leaves network unspecified, find current default.
1311 if (network == kDefaultNetworkHandle) {
1312 network = NetworkChangeNotifier::GetDefaultNetwork();
pauljensen 2015/10/14 11:51:34 We may want to loop here in cases where the defaul
Jana 2015/10/16 23:11:00 I've added a BindToDefaultNetwork method to Datagr
1313 if (network == kDefaultNetworkHandle) {
1314 return ERR_INTERNET_DISCONNECTED;
1315 }
1316 }
1213 1317
1318 new_socket->Reset(socket.get());
1319
1320 int rv = socket->BindToNetwork(network);
1321 if (rv != OK) {
1322 return rv;
1323 }
1324
1325 rv = socket->Connect(addr);
1214 if (rv != OK) { 1326 if (rv != OK) {
1215 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET); 1327 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
1216 return rv; 1328 return rv;
1217 } 1329 }
1218 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested", 1330 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1219 port_suggester->call_count()); 1331 port_suggester->call_count());
1220 if (enable_port_selection) { 1332 if (enable_port_selection) {
1221 DCHECK_LE(1u, port_suggester->call_count()); 1333 DCHECK_LE(1u, port_suggester->call_count());
1222 } else { 1334 } else {
1223 DCHECK_EQ(0u, port_suggester->call_count()); 1335 DCHECK_EQ(0u, port_suggester->call_count());
(...skipping 15 matching lines...) Expand all
1239 1351
1240 socket->GetLocalAddress(&local_address_); 1352 socket->GetLocalAddress(&local_address_);
1241 if (check_persisted_supports_quic_ && http_server_properties_) { 1353 if (check_persisted_supports_quic_ && http_server_properties_) {
1242 check_persisted_supports_quic_ = false; 1354 check_persisted_supports_quic_ = false;
1243 IPAddressNumber last_address; 1355 IPAddressNumber last_address;
1244 if (http_server_properties_->GetSupportsQuic(&last_address) && 1356 if (http_server_properties_->GetSupportsQuic(&last_address) &&
1245 last_address == local_address_.address()) { 1357 last_address == local_address_.address()) {
1246 require_confirmation_ = false; 1358 require_confirmation_ = false;
1247 } 1359 }
1248 } 1360 }
1361 return OK;
1362 }
1363
1364 int QuicStreamFactory::CreateSession(const QuicServerId& server_id,
1365 int cert_verify_flags,
1366 scoped_ptr<QuicServerInfo> server_info,
1367 const AddressList& address_list,
1368 base::TimeTicks dns_resolution_end_time,
1369 const BoundNetLog& net_log,
1370 QuicChromiumClientSession** session) {
1371 scoped_ptr<DatagramClientSocket> socket;
1372 int rv = CreateAndConfigureDatagramSocket(&socket,
1373 server_id,
1374 *address_list.begin(),
1375 net_log,
1376 kDefaultNetworkHandle);
1377 if (rv != OK) {
1378 return rv;
1379 }
1249 1380
1250 DefaultPacketWriterFactory packet_writer_factory(socket.get()); 1381 DefaultPacketWriterFactory packet_writer_factory(socket.get());
1251
1252 if (!helper_.get()) { 1382 if (!helper_.get()) {
1253 helper_.reset( 1383 helper_.reset(
1254 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(), 1384 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
1255 clock_.get(), random_generator_)); 1385 clock_.get(), random_generator_));
1256 } 1386 }
1257 1387
1388 QuicConnectionId connection_id = random_generator_->RandUint64();
1258 QuicConnection* connection = new QuicConnection( 1389 QuicConnection* connection = new QuicConnection(
1259 connection_id, addr, helper_.get(), packet_writer_factory, 1390 connection_id, addr, helper_.get(), packet_writer_factory,
1260 true /* owns_writer */, Perspective::IS_CLIENT, server_id.is_https(), 1391 true /* owns_writer */, Perspective::IS_CLIENT, server_id.is_https(),
1261 supported_versions_); 1392 supported_versions_);
1262 connection->SetMaxPacketLength(max_packet_length_); 1393 connection->SetMaxPacketLength(max_packet_length_);
1263 1394
1264 InitializeCachedStateInCryptoConfig(server_id, server_info); 1395 InitializeCachedStateInCryptoConfig(server_id, server_info);
1265 1396
1266 QuicConfig config = config_; 1397 QuicConfig config = config_;
1267 config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_); 1398 config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_);
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
1446 // Since the session was active, there's no longer an 1577 // Since the session was active, there's no longer an
1447 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP 1578 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1448 // job also fails. So to avoid not using QUIC when we otherwise could, we mark 1579 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1449 // it as recently broken, which means that 0-RTT will be disabled but we'll 1580 // it as recently broken, which means that 0-RTT will be disabled but we'll
1450 // still race. 1581 // still race.
1451 http_server_properties_->MarkAlternativeServiceRecentlyBroken( 1582 http_server_properties_->MarkAlternativeServiceRecentlyBroken(
1452 alternative_service); 1583 alternative_service);
1453 } 1584 }
1454 1585
1455 } // namespace net 1586 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_stream_factory.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698