Index: google_apis/gcm/engine/connection_factory_impl.cc |
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc |
index ebfd367c9a85c571da3b3914477dab303e1fc673..deb810264171bab7fe326114fcc3dec19249fc90 100644 |
--- a/google_apis/gcm/engine/connection_factory_impl.cc |
+++ b/google_apis/gcm/engine/connection_factory_impl.cc |
@@ -41,11 +41,13 @@ bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time, |
} // namespace |
ConnectionFactoryImpl::ConnectionFactoryImpl( |
- const GURL& mcs_endpoint, |
+ const std::vector<GURL>& mcs_endpoints, |
const net::BackoffEntry::Policy& backoff_policy, |
scoped_refptr<net::HttpNetworkSession> network_session, |
net::NetLog* net_log) |
- : mcs_endpoint_(mcs_endpoint), |
+ : mcs_endpoints_(mcs_endpoints), |
+ next_endpoint_(0), |
+ last_successful_endpoint_(0), |
backoff_policy_(backoff_policy), |
network_session_(network_session), |
bound_net_log_( |
@@ -54,6 +56,7 @@ ConnectionFactoryImpl::ConnectionFactoryImpl( |
connecting_(false), |
logging_in_(false), |
weak_ptr_factory_(this) { |
+ DCHECK_GE(mcs_endpoints_.size(), 1U); |
} |
ConnectionFactoryImpl::~ConnectionFactoryImpl() { |
@@ -184,12 +187,20 @@ void ConnectionFactoryImpl::OnIPAddressChanged() { |
// necessary, so no need to call again. |
} |
+GURL ConnectionFactoryImpl::GetCurrentEndpoint() const { |
+ // Note that IsEndpointReachable() returns false anytime connecting_ is true, |
+ // so while connecting this always uses |next_endpoint_|. |
+ if (IsEndpointReachable()) |
+ return mcs_endpoints_[last_successful_endpoint_]; |
+ return mcs_endpoints_[next_endpoint_]; |
+} |
+ |
void ConnectionFactoryImpl::ConnectImpl() { |
DCHECK(connecting_); |
DCHECK(!socket_handle_.socket()); |
int status = network_session_->proxy_service()->ResolveProxy( |
- mcs_endpoint_, |
+ GetCurrentEndpoint(), |
&proxy_info_, |
base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
weak_ptr_factory_.GetWeakPtr()), |
@@ -234,13 +245,28 @@ void ConnectionFactoryImpl::OnConnectDone(int result) { |
CloseSocket(); |
backoff_entry_->InformOfRequest(false); |
UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); |
+ |
+ // If there are other endpoints available, use the next endpoint on the |
+ // subsequent retry. |
+ next_endpoint_++; |
+ if (next_endpoint_ >= mcs_endpoints_.size()) |
+ next_endpoint_ = 0; |
Connect(); |
return; |
} |
UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", true); |
+ UMA_HISTOGRAM_COUNTS("GCM.ConnectionEndpoint", next_endpoint_); |
+ UMA_HISTOGRAM_BOOLEAN("GCM.ConnectedViaProxy", |
+ !(proxy_info_.is_empty() || proxy_info_.is_direct())); |
ReportSuccessfulProxyConnection(); |
+ // Reset the endpoint back to the default. |
+ // TODO(zea): consider prioritizing endpoints more intelligently based on |
+ // which ones succeed most for this client? Although that will affect |
+ // measuring the success rate of the default endpoint vs fallback. |
+ last_successful_endpoint_ = next_endpoint_; |
+ next_endpoint_ = 0; |
connecting_ = false; |
logging_in_ = true; |
DVLOG(1) << "MCS endpoint socket connection success, starting login."; |
@@ -300,7 +326,7 @@ void ConnectionFactoryImpl::OnProxyResolveDone(int status) { |
net::SSLConfig ssl_config; |
network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); |
status = net::InitSocketHandleForTlsConnect( |
- net::HostPortPair::FromURL(mcs_endpoint_), |
+ net::HostPortPair::FromURL(GetCurrentEndpoint()), |
network_session_.get(), |
proxy_info_, |
ssl_config, |
@@ -374,7 +400,7 @@ int ConnectionFactoryImpl::ReconsiderProxyAfterError(int error) { |
} |
int status = network_session_->proxy_service()->ReconsiderProxyAfterError( |
- mcs_endpoint_, &proxy_info_, |
+ GetCurrentEndpoint(), &proxy_info_, |
base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
weak_ptr_factory_.GetWeakPtr()), |
&pac_request_, |