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 "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/metrics/sparse_histogram.h" | 9 #include "base/metrics/sparse_histogram.h" |
10 #include "google_apis/gcm/engine/connection_handler_impl.h" | 10 #include "google_apis/gcm/engine/connection_handler_impl.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time, | 34 bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time, |
35 const base::TimeTicks& now_ticks) { | 35 const base::TimeTicks& now_ticks) { |
36 return !login_time.is_null() && | 36 return !login_time.is_null() && |
37 now_ticks - login_time <= | 37 now_ticks - login_time <= |
38 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs); | 38 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs); |
39 } | 39 } |
40 | 40 |
41 } // namespace | 41 } // namespace |
42 | 42 |
43 ConnectionFactoryImpl::ConnectionFactoryImpl( | 43 ConnectionFactoryImpl::ConnectionFactoryImpl( |
44 const GURL& mcs_endpoint, | 44 const std::vector<GURL>& mcs_endpoints, |
45 const net::BackoffEntry::Policy& backoff_policy, | 45 const net::BackoffEntry::Policy& backoff_policy, |
46 scoped_refptr<net::HttpNetworkSession> network_session, | 46 scoped_refptr<net::HttpNetworkSession> network_session, |
47 net::NetLog* net_log) | 47 net::NetLog* net_log) |
48 : mcs_endpoint_(mcs_endpoint), | 48 : mcs_endpoints_(mcs_endpoints), |
| 49 next_endpoint_(0), |
| 50 last_successful_endpoint_(0), |
49 backoff_policy_(backoff_policy), | 51 backoff_policy_(backoff_policy), |
50 network_session_(network_session), | 52 network_session_(network_session), |
51 bound_net_log_( | 53 bound_net_log_( |
52 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), | 54 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), |
53 pac_request_(NULL), | 55 pac_request_(NULL), |
54 connecting_(false), | 56 connecting_(false), |
55 logging_in_(false), | 57 logging_in_(false), |
56 weak_ptr_factory_(this) { | 58 weak_ptr_factory_(this) { |
| 59 DCHECK_GE(mcs_endpoints_.size(), 1U); |
57 } | 60 } |
58 | 61 |
59 ConnectionFactoryImpl::~ConnectionFactoryImpl() { | 62 ConnectionFactoryImpl::~ConnectionFactoryImpl() { |
60 if (pac_request_) { | 63 if (pac_request_) { |
61 network_session_->proxy_service()->CancelPacRequest(pac_request_); | 64 network_session_->proxy_service()->CancelPacRequest(pac_request_); |
62 pac_request_ = NULL; | 65 pac_request_ = NULL; |
63 } | 66 } |
64 } | 67 } |
65 | 68 |
66 void ConnectionFactoryImpl::Initialize( | 69 void ConnectionFactoryImpl::Initialize( |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 // necessary, so no need to call again. | 180 // necessary, so no need to call again. |
178 } | 181 } |
179 | 182 |
180 void ConnectionFactoryImpl::OnIPAddressChanged() { | 183 void ConnectionFactoryImpl::OnIPAddressChanged() { |
181 DVLOG(1) << "IP Address changed, resetting backoff."; | 184 DVLOG(1) << "IP Address changed, resetting backoff."; |
182 backoff_entry_->Reset(); | 185 backoff_entry_->Reset(); |
183 // Connect(..) should be retrying with backoff already if a connection is | 186 // Connect(..) should be retrying with backoff already if a connection is |
184 // necessary, so no need to call again. | 187 // necessary, so no need to call again. |
185 } | 188 } |
186 | 189 |
| 190 GURL ConnectionFactoryImpl::GetCurrentEndpoint() const { |
| 191 // Note that IsEndpointReachable() returns false anytime connecting_ is true, |
| 192 // so while connecting this always uses |next_endpoint_|. |
| 193 if (IsEndpointReachable()) |
| 194 return mcs_endpoints_[last_successful_endpoint_]; |
| 195 return mcs_endpoints_[next_endpoint_]; |
| 196 } |
| 197 |
187 void ConnectionFactoryImpl::ConnectImpl() { | 198 void ConnectionFactoryImpl::ConnectImpl() { |
188 DCHECK(connecting_); | 199 DCHECK(connecting_); |
189 DCHECK(!socket_handle_.socket()); | 200 DCHECK(!socket_handle_.socket()); |
190 | 201 |
191 int status = network_session_->proxy_service()->ResolveProxy( | 202 int status = network_session_->proxy_service()->ResolveProxy( |
192 mcs_endpoint_, | 203 GetCurrentEndpoint(), |
193 &proxy_info_, | 204 &proxy_info_, |
194 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, | 205 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
195 weak_ptr_factory_.GetWeakPtr()), | 206 weak_ptr_factory_.GetWeakPtr()), |
196 &pac_request_, | 207 &pac_request_, |
197 bound_net_log_); | 208 bound_net_log_); |
198 if (status != net::ERR_IO_PENDING) | 209 if (status != net::ERR_IO_PENDING) |
199 OnProxyResolveDone(status); | 210 OnProxyResolveDone(status); |
200 } | 211 } |
201 | 212 |
202 void ConnectionFactoryImpl::InitHandler() { | 213 void ConnectionFactoryImpl::InitHandler() { |
(...skipping 24 matching lines...) Expand all Loading... |
227 // not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering | 238 // not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering |
228 // another proxy. | 239 // another proxy. |
229 DCHECK_NE(result, net::OK); | 240 DCHECK_NE(result, net::OK); |
230 if (result == net::ERR_IO_PENDING) | 241 if (result == net::ERR_IO_PENDING) |
231 return; // Proxy reconsideration pending. Return. | 242 return; // Proxy reconsideration pending. Return. |
232 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result; | 243 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result; |
233 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false); | 244 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false); |
234 CloseSocket(); | 245 CloseSocket(); |
235 backoff_entry_->InformOfRequest(false); | 246 backoff_entry_->InformOfRequest(false); |
236 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); | 247 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); |
| 248 |
| 249 // If there are other endpoints available, use the next endpoint on the |
| 250 // subsequent retry. |
| 251 next_endpoint_++; |
| 252 if (next_endpoint_ >= mcs_endpoints_.size()) |
| 253 next_endpoint_ = 0; |
237 Connect(); | 254 Connect(); |
238 return; | 255 return; |
239 } | 256 } |
240 | 257 |
241 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", true); | 258 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", true); |
| 259 UMA_HISTOGRAM_COUNTS("GCM.ConnectionEndpoint", next_endpoint_); |
| 260 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectedViaProxy", |
| 261 !(proxy_info_.is_empty() || proxy_info_.is_direct())); |
242 ReportSuccessfulProxyConnection(); | 262 ReportSuccessfulProxyConnection(); |
243 | 263 |
| 264 // Reset the endpoint back to the default. |
| 265 // TODO(zea): consider prioritizing endpoints more intelligently based on |
| 266 // which ones succeed most for this client? Although that will affect |
| 267 // measuring the success rate of the default endpoint vs fallback. |
| 268 last_successful_endpoint_ = next_endpoint_; |
| 269 next_endpoint_ = 0; |
244 connecting_ = false; | 270 connecting_ = false; |
245 logging_in_ = true; | 271 logging_in_ = true; |
246 DVLOG(1) << "MCS endpoint socket connection success, starting login."; | 272 DVLOG(1) << "MCS endpoint socket connection success, starting login."; |
247 InitHandler(); | 273 InitHandler(); |
248 } | 274 } |
249 | 275 |
250 void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) { | 276 void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) { |
251 DCHECK(!connecting_); | 277 DCHECK(!connecting_); |
252 if (result != net::OK) { | 278 if (result != net::OK) { |
253 // TODO(zea): Consider how to handle errors that may require some sort of | 279 // TODO(zea): Consider how to handle errors that may require some sort of |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 // Failed to resolve proxy. Retry later. | 319 // Failed to resolve proxy. Retry later. |
294 OnConnectDone(status); | 320 OnConnectDone(status); |
295 return; | 321 return; |
296 } | 322 } |
297 | 323 |
298 DVLOG(1) << "Resolved proxy with PAC:" << proxy_info_.ToPacString(); | 324 DVLOG(1) << "Resolved proxy with PAC:" << proxy_info_.ToPacString(); |
299 | 325 |
300 net::SSLConfig ssl_config; | 326 net::SSLConfig ssl_config; |
301 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); | 327 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); |
302 status = net::InitSocketHandleForTlsConnect( | 328 status = net::InitSocketHandleForTlsConnect( |
303 net::HostPortPair::FromURL(mcs_endpoint_), | 329 net::HostPortPair::FromURL(GetCurrentEndpoint()), |
304 network_session_.get(), | 330 network_session_.get(), |
305 proxy_info_, | 331 proxy_info_, |
306 ssl_config, | 332 ssl_config, |
307 ssl_config, | 333 ssl_config, |
308 net::kPrivacyModeDisabled, | 334 net::kPrivacyModeDisabled, |
309 bound_net_log_, | 335 bound_net_log_, |
310 &socket_handle_, | 336 &socket_handle_, |
311 base::Bind(&ConnectionFactoryImpl::OnConnectDone, | 337 base::Bind(&ConnectionFactoryImpl::OnConnectDone, |
312 weak_ptr_factory_.GetWeakPtr())); | 338 weak_ptr_factory_.GetWeakPtr())); |
313 if (status != net::ERR_IO_PENDING) | 339 if (status != net::ERR_IO_PENDING) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 } | 393 } |
368 | 394 |
369 net::SSLConfig ssl_config; | 395 net::SSLConfig ssl_config; |
370 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); | 396 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); |
371 if (proxy_info_.is_https() && ssl_config.send_client_cert) { | 397 if (proxy_info_.is_https() && ssl_config.send_client_cert) { |
372 network_session_->ssl_client_auth_cache()->Remove( | 398 network_session_->ssl_client_auth_cache()->Remove( |
373 proxy_info_.proxy_server().host_port_pair()); | 399 proxy_info_.proxy_server().host_port_pair()); |
374 } | 400 } |
375 | 401 |
376 int status = network_session_->proxy_service()->ReconsiderProxyAfterError( | 402 int status = network_session_->proxy_service()->ReconsiderProxyAfterError( |
377 mcs_endpoint_, &proxy_info_, | 403 GetCurrentEndpoint(), &proxy_info_, |
378 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, | 404 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
379 weak_ptr_factory_.GetWeakPtr()), | 405 weak_ptr_factory_.GetWeakPtr()), |
380 &pac_request_, | 406 &pac_request_, |
381 bound_net_log_); | 407 bound_net_log_); |
382 if (status == net::OK || status == net::ERR_IO_PENDING) { | 408 if (status == net::OK || status == net::ERR_IO_PENDING) { |
383 CloseSocket(); | 409 CloseSocket(); |
384 } else { | 410 } else { |
385 // If ReconsiderProxyAfterError() failed synchronously, it means | 411 // If ReconsiderProxyAfterError() failed synchronously, it means |
386 // there was nothing left to fall-back to, so fail the transaction | 412 // there was nothing left to fall-back to, so fail the transaction |
387 // with the last connection error we got. | 413 // with the last connection error we got. |
(...skipping 22 matching lines...) Expand all Loading... |
410 // the destroyed socket. | 436 // the destroyed socket. |
411 if (connection_handler_) | 437 if (connection_handler_) |
412 connection_handler_->Reset(); | 438 connection_handler_->Reset(); |
413 | 439 |
414 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected()) | 440 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected()) |
415 socket_handle_.socket()->Disconnect(); | 441 socket_handle_.socket()->Disconnect(); |
416 socket_handle_.Reset(); | 442 socket_handle_.Reset(); |
417 } | 443 } |
418 | 444 |
419 } // namespace gcm | 445 } // namespace gcm |
OLD | NEW |