Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "google_apis/gcm/engine/connection_factory_impl.h" | 5 #include "google_apis/gcm/engine/connection_factory_impl.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 38 | 38 |
| 39 // Decides whether the last login was within kConnectionResetWindowSecs of now | 39 // Decides whether the last login was within kConnectionResetWindowSecs of now |
| 40 // or not. | 40 // or not. |
| 41 bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time, | 41 bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time, |
| 42 const base::TimeTicks& now_ticks) { | 42 const base::TimeTicks& now_ticks) { |
| 43 return !login_time.is_null() && | 43 return !login_time.is_null() && |
| 44 now_ticks - login_time <= | 44 now_ticks - login_time <= |
| 45 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs); | 45 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs); |
| 46 } | 46 } |
| 47 | 47 |
| 48 const int kMaxClientEvents = 30; | |
|
Peter Beverloo
2016/11/28 15:05:15
++docs. Explain what it is and how this number was
harkness
2016/12/01 10:34:34
Done.
| |
| 49 | |
| 48 } // namespace | 50 } // namespace |
| 49 | 51 |
| 50 ConnectionFactoryImpl::ConnectionFactoryImpl( | 52 ConnectionFactoryImpl::ConnectionFactoryImpl( |
| 51 const std::vector<GURL>& mcs_endpoints, | 53 const std::vector<GURL>& mcs_endpoints, |
| 52 const net::BackoffEntry::Policy& backoff_policy, | 54 const net::BackoffEntry::Policy& backoff_policy, |
| 53 net::HttpNetworkSession* gcm_network_session, | 55 net::HttpNetworkSession* gcm_network_session, |
| 54 net::HttpNetworkSession* http_network_session, | 56 net::HttpNetworkSession* http_network_session, |
| 55 net::NetLog* net_log, | 57 net::NetLog* net_log, |
| 56 GCMStatsRecorder* recorder) | 58 GCMStatsRecorder* recorder) |
| 57 : mcs_endpoints_(mcs_endpoints), | 59 : mcs_endpoints_(mcs_endpoints), |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 198 if (!last_login_time_.is_null()) { | 200 if (!last_login_time_.is_null()) { |
| 199 UMA_HISTOGRAM_CUSTOM_TIMES("GCM.ConnectionUpTime", | 201 UMA_HISTOGRAM_CUSTOM_TIMES("GCM.ConnectionUpTime", |
| 200 NowTicks() - last_login_time_, | 202 NowTicks() - last_login_time_, |
| 201 base::TimeDelta::FromSeconds(1), | 203 base::TimeDelta::FromSeconds(1), |
| 202 base::TimeDelta::FromHours(24), | 204 base::TimeDelta::FromHours(24), |
| 203 50); | 205 50); |
| 204 // |last_login_time_| will be reset below, before attempting the new | 206 // |last_login_time_| will be reset below, before attempting the new |
| 205 // connection. | 207 // connection. |
| 206 } | 208 } |
| 207 | 209 |
| 210 // Record that the connection has ended. | |
| 211 if (logging_in_) { | |
| 212 // If this was a login failure, the connection established time would have | |
| 213 // been set and it would have marked a successful connection, so explicitly | |
| 214 // clear that. | |
| 215 current_event_.set_type(mcs_proto::ClientEvent::FAILED_CONNECTION); | |
| 216 current_event_.clear_time_connection_established_ms(); | |
| 217 // TODO(harkness): What error code do we want to set? | |
| 218 } | |
| 219 current_event_.set_time_connection_ended_ms(NowTicks().ToInternalValue()); | |
|
Peter Beverloo
2016/11/28 15:05:14
Here and elsewhere:
I'm not comfortable using ToI
harkness
2016/12/01 10:34:34
Sure, that seems reasonable.
| |
| 220 | |
| 208 CloseSocket(); | 221 CloseSocket(); |
| 209 DCHECK(!IsEndpointReachable()); | 222 DCHECK(!IsEndpointReachable()); |
| 210 | 223 |
| 211 // TODO(zea): if the network is offline, don't attempt to connect. | 224 // TODO(zea): if the network is offline, don't attempt to connect. |
| 212 // See crbug.com/396687 | 225 // See crbug.com/396687 |
| 213 | 226 |
| 214 // Network changes get special treatment as they can trigger a one-off canary | 227 // Network changes get special treatment as they can trigger a one-off canary |
| 215 // request that bypasses backoff (but does nothing if a connection is in | 228 // request that bypasses backoff (but does nothing if a connection is in |
| 216 // progress). Other connection reset events can be ignored as a connection | 229 // progress). Other connection reset events can be ignored as a connection |
| 217 // is already awaiting backoff expiration. | 230 // is already awaiting backoff expiration. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 } | 266 } |
| 254 | 267 |
| 255 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const { | 268 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const { |
| 256 if (!backoff_entry_) | 269 if (!backoff_entry_) |
| 257 return base::TimeTicks(); | 270 return base::TimeTicks(); |
| 258 return backoff_entry_->GetReleaseTime(); | 271 return backoff_entry_->GetReleaseTime(); |
| 259 } | 272 } |
| 260 | 273 |
| 261 void ConnectionFactoryImpl::OnNetworkChanged( | 274 void ConnectionFactoryImpl::OnNetworkChanged( |
| 262 net::NetworkChangeNotifier::ConnectionType type) { | 275 net::NetworkChangeNotifier::ConnectionType type) { |
| 276 // Record the current network type. | |
| 277 network_type_ = type; | |
|
Peter Beverloo
2016/11/28 15:05:15
Since we only fire OnNetworkChanged() when it actu
harkness
2016/12/01 10:34:34
You're right, that is going to be a problem. I hav
| |
| 278 | |
| 263 if (type == net::NetworkChangeNotifier::CONNECTION_NONE) { | 279 if (type == net::NetworkChangeNotifier::CONNECTION_NONE) { |
| 264 DVLOG(1) << "Network lost, resettion connection."; | 280 DVLOG(1) << "Network lost, resettion connection."; |
| 265 waiting_for_network_online_ = true; | 281 waiting_for_network_online_ = true; |
| 266 | 282 |
| 267 // Will do nothing due to |waiting_for_network_online_ == true|. | 283 // Will do nothing due to |waiting_for_network_online_ == true|. |
| 268 // TODO(zea): make the above statement actually true. See crbug.com/396687 | 284 // TODO(zea): make the above statement actually true. See crbug.com/396687 |
| 269 SignalConnectionReset(NETWORK_CHANGE); | 285 SignalConnectionReset(NETWORK_CHANGE); |
| 270 return; | 286 return; |
| 271 } | 287 } |
| 272 | 288 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 289 | 305 |
| 290 net::IPEndPoint ip_endpoint; | 306 net::IPEndPoint ip_endpoint; |
| 291 int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint); | 307 int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint); |
| 292 if (result != net::OK) | 308 if (result != net::OK) |
| 293 return net::IPEndPoint(); | 309 return net::IPEndPoint(); |
| 294 | 310 |
| 295 return ip_endpoint; | 311 return ip_endpoint; |
| 296 } | 312 } |
| 297 | 313 |
| 298 void ConnectionFactoryImpl::ConnectImpl() { | 314 void ConnectionFactoryImpl::ConnectImpl() { |
| 315 if (total_client_events_ >= 0) { | |
|
Peter Beverloo
2016/11/28 15:05:15
Instead of having |total_client_events_|, I think
harkness
2016/12/01 10:34:34
Refactored this into the ClientEventTracker, which
| |
| 316 // If starting a new connection, the previous connection is completed, so | |
| 317 // move | |
| 318 // the current client event onto the list of past events. | |
| 319 mcs_proto::ClientEvent* client_event = nullptr; | |
| 320 if (total_client_events_ < kMaxClientEvents) { | |
| 321 client_event = client_events_.Add(); | |
| 322 } else { | |
| 323 // If the maximum number of stored events has been exceeded, start | |
| 324 // overwriting older entries. | |
| 325 client_event = | |
| 326 client_events_.Mutable(total_client_events_ % kMaxClientEvents); | |
| 327 } | |
| 328 client_event->CopyFrom(current_event_); | |
| 329 current_event_.Clear(); | |
|
Peter Beverloo
2016/11/28 15:05:15
it seems to me like this code would become *a lot*
harkness
2016/12/01 10:34:34
Done.
| |
| 330 } | |
| 331 total_client_events_++; | |
| 332 | |
| 333 current_event_.set_time_connection_started_ms(NowTicks().ToInternalValue()); | |
| 334 current_event_.set_network_type(network_type_); | |
| 335 | |
| 336 StartConnection(); | |
| 337 } | |
| 338 | |
| 339 void ConnectionFactoryImpl::StartConnection() { | |
| 299 DCHECK(!IsEndpointReachable()); | 340 DCHECK(!IsEndpointReachable()); |
| 300 // TODO(zea): Make this a dcheck again. crbug.com/462319 | 341 // TODO(zea): Make this a dcheck again. crbug.com/462319 |
| 301 CHECK(!socket_handle_.socket()); | 342 CHECK(!socket_handle_.socket()); |
| 302 | 343 |
| 303 // TODO(zea): if the network is offline, don't attempt to connect. | 344 // TODO(zea): if the network is offline, don't attempt to connect. |
| 304 // See crbug.com/396687 | 345 // See crbug.com/396687 |
| 305 | 346 |
| 306 connecting_ = true; | 347 connecting_ = true; |
| 307 GURL current_endpoint = GetCurrentEndpoint(); | 348 GURL current_endpoint = GetCurrentEndpoint(); |
| 308 recorder_->RecordConnectionInitiated(current_endpoint.host()); | 349 recorder_->RecordConnectionInitiated(current_endpoint.host()); |
| 309 RebuildNetworkSessionAuthCache(); | 350 RebuildNetworkSessionAuthCache(); |
| 310 int status = gcm_network_session_->proxy_service()->ResolveProxy( | 351 int status = gcm_network_session_->proxy_service()->ResolveProxy( |
| 311 current_endpoint, | 352 current_endpoint, |
| 312 std::string(), | 353 std::string(), |
| 313 &proxy_info_, | 354 &proxy_info_, |
| 314 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, | 355 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
| 315 weak_ptr_factory_.GetWeakPtr()), | 356 weak_ptr_factory_.GetWeakPtr()), |
| 316 &pac_request_, | 357 &pac_request_, |
| 317 NULL, | 358 NULL, |
| 318 net_log_); | 359 net_log_); |
| 319 if (status != net::ERR_IO_PENDING) | 360 if (status != net::ERR_IO_PENDING) |
| 320 OnProxyResolveDone(status); | 361 OnProxyResolveDone(status); |
| 321 } | 362 } |
| 322 | 363 |
| 323 void ConnectionFactoryImpl::InitHandler() { | 364 void ConnectionFactoryImpl::InitHandler() { |
| 324 // May be null in tests. | 365 // May be null in tests. |
| 325 mcs_proto::LoginRequest login_request; | 366 mcs_proto::LoginRequest login_request; |
| 326 if (!request_builder_.is_null()) { | 367 if (!request_builder_.is_null()) { |
| 368 // TODO(harkness): Pass the previous ClientEvents into the request builder. | |
|
Peter Beverloo
2016/11/28 15:05:15
This also needs to build a ClientEvent for DISCARD
harkness
2016/12/01 10:34:34
TODO added.
| |
| 327 request_builder_.Run(&login_request); | 369 request_builder_.Run(&login_request); |
| 328 DCHECK(login_request.IsInitialized()); | 370 DCHECK(login_request.IsInitialized()); |
| 329 } | 371 } |
| 330 | 372 |
| 331 connection_handler_->Init(login_request, socket_handle_.socket()); | 373 connection_handler_->Init(login_request, socket_handle_.socket()); |
| 332 } | 374 } |
| 333 | 375 |
| 334 std::unique_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry( | 376 std::unique_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry( |
| 335 const net::BackoffEntry::Policy* const policy) { | 377 const net::BackoffEntry::Policy* const policy) { |
| 336 return std::unique_ptr<net::BackoffEntry>(new net::BackoffEntry(policy)); | 378 return std::unique_ptr<net::BackoffEntry>(new net::BackoffEntry(policy)); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 364 DCHECK_NE(result, net::OK); | 406 DCHECK_NE(result, net::OK); |
| 365 if (result == net::ERR_IO_PENDING) | 407 if (result == net::ERR_IO_PENDING) |
| 366 return; // Proxy reconsideration pending. Return. | 408 return; // Proxy reconsideration pending. Return. |
| 367 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result; | 409 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result; |
| 368 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false); | 410 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false); |
| 369 recorder_->RecordConnectionFailure(result); | 411 recorder_->RecordConnectionFailure(result); |
| 370 CloseSocket(); | 412 CloseSocket(); |
| 371 backoff_entry_->InformOfRequest(false); | 413 backoff_entry_->InformOfRequest(false); |
| 372 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); | 414 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); |
| 373 | 415 |
| 416 // Record the failed connection so information about it can be sent in the | |
| 417 // next login request. | |
| 418 current_event_.set_type(mcs_proto::ClientEvent::FAILED_CONNECTION); | |
| 419 current_event_.set_time_connection_ended_ms(NowTicks().ToInternalValue()); | |
| 420 current_event_.set_error_code(result); | |
| 421 | |
| 374 // If there are other endpoints available, use the next endpoint on the | 422 // If there are other endpoints available, use the next endpoint on the |
| 375 // subsequent retry. | 423 // subsequent retry. |
| 376 next_endpoint_++; | 424 next_endpoint_++; |
| 377 if (next_endpoint_ >= mcs_endpoints_.size()) | 425 if (next_endpoint_ >= mcs_endpoints_.size()) |
| 378 next_endpoint_ = 0; | 426 next_endpoint_ = 0; |
| 379 connecting_ = false; | 427 connecting_ = false; |
| 380 Connect(); | 428 Connect(); |
| 381 return; | 429 return; |
| 382 } | 430 } |
| 383 | 431 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 412 | 460 |
| 413 // Handshake complete, reset backoff. If the login failed with an error, | 461 // Handshake complete, reset backoff. If the login failed with an error, |
| 414 // the client should invoke SignalConnectionReset(LOGIN_FAILURE), which will | 462 // the client should invoke SignalConnectionReset(LOGIN_FAILURE), which will |
| 415 // restore the previous backoff. | 463 // restore the previous backoff. |
| 416 DVLOG(1) << "Handshake complete."; | 464 DVLOG(1) << "Handshake complete."; |
| 417 last_login_time_ = NowTicks(); | 465 last_login_time_ = NowTicks(); |
| 418 previous_backoff_.swap(backoff_entry_); | 466 previous_backoff_.swap(backoff_entry_); |
| 419 backoff_entry_->Reset(); | 467 backoff_entry_->Reset(); |
| 420 logging_in_ = false; | 468 logging_in_ = false; |
| 421 | 469 |
| 470 // Record the successful connection so information about it can be sent in the | |
| 471 // next login request. If there is a login failure, this will need to be | |
| 472 // updated to a failed connection. | |
| 473 current_event_.set_type(mcs_proto::ClientEvent::SUCCESSFUL_CONNECTION); | |
| 474 current_event_.set_time_connection_established_ms( | |
| 475 NowTicks().ToInternalValue()); | |
| 476 | |
| 477 // A completed connection means that the old client event data has now been | |
| 478 // sent to GCM. Delete old data and reinitialize the count. | |
| 479 client_events_.Clear(); | |
| 480 total_client_events_ = 0; | |
| 481 | |
| 422 if (listener_) | 482 if (listener_) |
| 423 listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP()); | 483 listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP()); |
| 424 } | 484 } |
| 425 | 485 |
| 426 // This has largely been copied from | 486 // This has largely been copied from |
| 427 // HttpStreamFactoryImpl::Job::DoResolveProxyComplete. This should be | 487 // HttpStreamFactoryImpl::Job::DoResolveProxyComplete. This should be |
| 428 // refactored into some common place. | 488 // refactored into some common place. |
| 429 void ConnectionFactoryImpl::OnProxyResolveDone(int status) { | 489 void ConnectionFactoryImpl::OnProxyResolveDone(int status) { |
| 430 pac_request_ = NULL; | 490 pac_request_ = NULL; |
| 431 DVLOG(1) << "Proxy resolution status: " << status; | 491 DVLOG(1) << "Proxy resolution status: " << status; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 | 633 |
| 574 void ConnectionFactoryImpl::RebuildNetworkSessionAuthCache() { | 634 void ConnectionFactoryImpl::RebuildNetworkSessionAuthCache() { |
| 575 if (!http_network_session_ || !http_network_session_->http_auth_cache()) | 635 if (!http_network_session_ || !http_network_session_->http_auth_cache()) |
| 576 return; | 636 return; |
| 577 | 637 |
| 578 gcm_network_session_->http_auth_cache()->UpdateAllFrom( | 638 gcm_network_session_->http_auth_cache()->UpdateAllFrom( |
| 579 *http_network_session_->http_auth_cache()); | 639 *http_network_session_->http_auth_cache()); |
| 580 } | 640 } |
| 581 | 641 |
| 582 } // namespace gcm | 642 } // namespace gcm |
| OLD | NEW |