Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / google_apis / gcm / engine / connection_factory_impl.cc
index 9dff1f6..4963f13 100644 (file)
@@ -8,7 +8,9 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "google_apis/gcm/engine/connection_handler_impl.h"
+#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
 #include "google_apis/gcm/protocol/mcs.pb.h"
+#include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_request_headers.h"
@@ -43,26 +45,36 @@ bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time,
 ConnectionFactoryImpl::ConnectionFactoryImpl(
     const std::vector<GURL>& mcs_endpoints,
     const net::BackoffEntry::Policy& backoff_policy,
-    scoped_refptr<net::HttpNetworkSession> network_session,
-    net::NetLog* net_log)
+    const scoped_refptr<net::HttpNetworkSession>& gcm_network_session,
+    const scoped_refptr<net::HttpNetworkSession>& http_network_session,
+    net::NetLog* net_log,
+    GCMStatsRecorder* recorder)
   : mcs_endpoints_(mcs_endpoints),
     next_endpoint_(0),
     last_successful_endpoint_(0),
     backoff_policy_(backoff_policy),
-    network_session_(network_session),
+    gcm_network_session_(gcm_network_session),
+    http_network_session_(http_network_session),
     bound_net_log_(
         net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)),
     pac_request_(NULL),
     connecting_(false),
     waiting_for_backoff_(false),
+    waiting_for_network_online_(false),
     logging_in_(false),
+    recorder_(recorder),
+    listener_(NULL),
     weak_ptr_factory_(this) {
   DCHECK_GE(mcs_endpoints_.size(), 1U);
+  DCHECK(!http_network_session_.get() ||
+         (gcm_network_session_.get() != http_network_session_.get()));
 }
 
 ConnectionFactoryImpl::~ConnectionFactoryImpl() {
+  CloseSocket();
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
   if (pac_request_) {
-    network_session_->proxy_service()->CancelPacRequest(pac_request_);
+    gcm_network_session_->proxy_service()->CancelPacRequest(pac_request_);
     pac_request_ = NULL;
   }
 }
@@ -77,8 +89,8 @@ void ConnectionFactoryImpl::Initialize(
   backoff_entry_ = CreateBackoffEntry(&backoff_policy_);
   request_builder_ = request_builder;
 
-  net::NetworkChangeNotifier::AddIPAddressObserver(this);
-  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  waiting_for_network_online_ = net::NetworkChangeNotifier::IsOffline();
   connection_handler_ = CreateConnectionHandler(
       base::TimeDelta::FromMilliseconds(kReadTimeoutMs),
       read_callback,
@@ -106,7 +118,7 @@ void ConnectionFactoryImpl::Connect() {
 void ConnectionFactoryImpl::ConnectWithBackoff() {
   // If a canary managed to connect while a backoff expiration was pending,
   // just cleanup the internal state.
-  if (connecting_ || IsEndpointReachable()) {
+  if (connecting_ || logging_in_ || IsEndpointReachable()) {
     waiting_for_backoff_ = false;
     return;
   }
@@ -116,6 +128,8 @@ void ConnectionFactoryImpl::ConnectWithBackoff() {
              << backoff_entry_->GetTimeUntilRelease().InMilliseconds()
              << " milliseconds.";
     waiting_for_backoff_ = true;
+    recorder_->RecordConnectionDelayedDueToBackoff(
+        backoff_entry_->GetTimeUntilRelease().InMilliseconds());
     base::MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&ConnectionFactoryImpl::ConnectWithBackoff,
@@ -133,6 +147,20 @@ bool ConnectionFactoryImpl::IsEndpointReachable() const {
   return connection_handler_ && connection_handler_->CanSendMessage();
 }
 
+std::string ConnectionFactoryImpl::GetConnectionStateString() const {
+  if (IsEndpointReachable())
+    return "CONNECTED";
+  if (logging_in_)
+    return "LOGGING IN";
+  if (connecting_)
+    return "CONNECTING";
+  if (waiting_for_backoff_)
+    return "WAITING FOR BACKOFF";
+  if (waiting_for_network_online_)
+    return "WAITING FOR NETWORK CHANGE";
+  return "NOT CONNECTED";
+}
+
 void ConnectionFactoryImpl::SignalConnectionReset(
     ConnectionResetReason reason) {
   // A failure can trigger multiple resets, so no need to do anything if a
@@ -142,9 +170,13 @@ void ConnectionFactoryImpl::SignalConnectionReset(
     return;
   }
 
+  if (listener_)
+    listener_->OnDisconnected();
+
   UMA_HISTOGRAM_ENUMERATION("GCM.ConnectionResetReason",
                             reason,
                             CONNECTION_RESET_COUNT);
+  recorder_->RecordConnectionResetSignaled(reason);
   if (!last_login_time_.is_null()) {
     UMA_HISTOGRAM_CUSTOM_TIMES("GCM.ConnectionUpTime",
                                NowTicks() - last_login_time_,
@@ -158,6 +190,9 @@ void ConnectionFactoryImpl::SignalConnectionReset(
   CloseSocket();
   DCHECK(!IsEndpointReachable());
 
+  // TODO(zea): if the network is offline, don't attempt to connect.
+  // See crbug.com/396687
+
   // Network changes get special treatment as they can trigger a one-off canary
   // request that bypasses backoff (but does nothing if a connection is in
   // progress). Other connection reset events can be ignored as a connection
@@ -184,8 +219,6 @@ void ConnectionFactoryImpl::SignalConnectionReset(
     // We shouldn't be in backoff in thise case.
     DCHECK_EQ(0, backoff_entry_->failure_count());
   }
-  DCHECK(!connecting_);
-  DCHECK(!waiting_for_backoff_);
 
   // At this point the last login time has been consumed or deemed irrelevant,
   // reset it.
@@ -194,27 +227,31 @@ void ConnectionFactoryImpl::SignalConnectionReset(
   Connect();
 }
 
+void ConnectionFactoryImpl::SetConnectionListener(
+    ConnectionListener* listener) {
+  listener_ = listener;
+}
+
 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const {
   if (!backoff_entry_)
     return base::TimeTicks();
   return backoff_entry_->GetReleaseTime();
 }
 
-void ConnectionFactoryImpl::OnConnectionTypeChanged(
+void ConnectionFactoryImpl::OnNetworkChanged(
     net::NetworkChangeNotifier::ConnectionType type) {
-  if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
+  if (type == net::NetworkChangeNotifier::CONNECTION_NONE) {
+    DVLOG(1) << "Network lost, resettion connection.";
+    waiting_for_network_online_ = true;
+
+    // Will do nothing due to |waiting_for_network_online_ == true|.
+    // TODO(zea): make the above statement actually true. See crbug.com/396687
+    SignalConnectionReset(NETWORK_CHANGE);
     return;
+  }
 
   DVLOG(1) << "Connection type changed to " << type << ", reconnecting.";
-
-  // The connection may have been silently dropped, attempt to reconnect.
-  SignalConnectionReset(NETWORK_CHANGE);
-}
-
-void ConnectionFactoryImpl::OnIPAddressChanged() {
-  DVLOG(1) << "IP Address changed, reconnecting.";
-
-  // The connection may have been silently dropped, attempt to reconnect.
+  waiting_for_network_online_ = false;
   SignalConnectionReset(NETWORK_CHANGE);
 }
 
@@ -226,17 +263,37 @@ GURL ConnectionFactoryImpl::GetCurrentEndpoint() const {
   return mcs_endpoints_[next_endpoint_];
 }
 
+net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() {
+  if (!socket_handle_.socket())
+    return net::IPEndPoint();
+
+  net::IPEndPoint ip_endpoint;
+  int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint);
+  if (result != net::OK)
+    return net::IPEndPoint();
+
+  return ip_endpoint;
+}
+
 void ConnectionFactoryImpl::ConnectImpl() {
   DCHECK(!IsEndpointReachable());
   DCHECK(!socket_handle_.socket());
 
+  // TODO(zea): if the network is offline, don't attempt to connect.
+  // See crbug.com/396687
+
   connecting_ = true;
-  int status = network_session_->proxy_service()->ResolveProxy(
-      GetCurrentEndpoint(),
+  GURL current_endpoint = GetCurrentEndpoint();
+  recorder_->RecordConnectionInitiated(current_endpoint.host());
+  RebuildNetworkSessionAuthCache();
+  int status = gcm_network_session_->proxy_service()->ResolveProxy(
+      current_endpoint,
+      net::LOAD_NORMAL,
       &proxy_info_,
       base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone,
                  weak_ptr_factory_.GetWeakPtr()),
       &pac_request_,
+      NULL,
       bound_net_log_);
   if (status != net::ERR_IO_PENDING)
     OnProxyResolveDone(status);
@@ -286,6 +343,7 @@ void ConnectionFactoryImpl::OnConnectDone(int result) {
       return;  // Proxy reconsideration pending. Return.
     LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
     UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false);
+    recorder_->RecordConnectionFailure(result);
     CloseSocket();
     backoff_entry_->InformOfRequest(false);
     UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result);
@@ -305,6 +363,7 @@ void ConnectionFactoryImpl::OnConnectDone(int result) {
   UMA_HISTOGRAM_BOOLEAN("GCM.ConnectedViaProxy",
                         !(proxy_info_.is_empty() || proxy_info_.is_direct()));
   ReportSuccessfulProxyConnection();
+  recorder_->RecordConnectionSuccess();
 
   // Reset the endpoint back to the default.
   // TODO(zea): consider prioritizing endpoints more intelligently based on
@@ -336,6 +395,9 @@ void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
   previous_backoff_.swap(backoff_entry_);
   backoff_entry_->Reset();
   logging_in_ = false;
+
+  if (listener_)
+    listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP());
 }
 
 // This has largely been copied from
@@ -369,14 +431,14 @@ void ConnectionFactoryImpl::OnProxyResolveDone(int status) {
   DVLOG(1) << "Resolved proxy with PAC:" << proxy_info_.ToPacString();
 
   net::SSLConfig ssl_config;
-  network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
+  gcm_network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
   status = net::InitSocketHandleForTlsConnect(
       net::HostPortPair::FromURL(GetCurrentEndpoint()),
-      network_session_.get(),
+      gcm_network_session_.get(),
       proxy_info_,
       ssl_config,
       ssl_config,
-      net::kPrivacyModeDisabled,
+      net::PRIVACY_MODE_DISABLED,
       bound_net_log_,
       &socket_handle_,
       base::Bind(&ConnectionFactoryImpl::OnConnectDone,
@@ -438,17 +500,18 @@ int ConnectionFactoryImpl::ReconsiderProxyAfterError(int error) {
   }
 
   net::SSLConfig ssl_config;
-  network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
+  gcm_network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
   if (proxy_info_.is_https() && ssl_config.send_client_cert) {
-    network_session_->ssl_client_auth_cache()->Remove(
+    gcm_network_session_->ssl_client_auth_cache()->Remove(
         proxy_info_.proxy_server().host_port_pair());
   }
 
-  int status = network_session_->proxy_service()->ReconsiderProxyAfterError(
-      GetCurrentEndpoint(), &proxy_info_,
+  int status = gcm_network_session_->proxy_service()->ReconsiderProxyAfterError(
+      GetCurrentEndpoint(), net::LOAD_NORMAL, error, &proxy_info_,
       base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone,
                  weak_ptr_factory_.GetWeakPtr()),
       &pac_request_,
+      NULL,
       bound_net_log_);
   if (status == net::OK || status == net::ERR_IO_PENDING) {
     CloseSocket();
@@ -472,8 +535,8 @@ int ConnectionFactoryImpl::ReconsiderProxyAfterError(int error) {
 }
 
 void ConnectionFactoryImpl::ReportSuccessfulProxyConnection() {
-  if (network_session_ && network_session_->proxy_service())
-    network_session_->proxy_service()->ReportSuccess(proxy_info_);
+  if (gcm_network_session_ && gcm_network_session_->proxy_service())
+    gcm_network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL);
 }
 
 void ConnectionFactoryImpl::CloseSocket() {
@@ -487,4 +550,12 @@ void ConnectionFactoryImpl::CloseSocket() {
   socket_handle_.Reset();
 }
 
+void ConnectionFactoryImpl::RebuildNetworkSessionAuthCache() {
+  if (!http_network_session_ || !http_network_session_->http_auth_cache())
+    return;
+
+  gcm_network_session_->http_auth_cache()->UpdateAllFrom(
+      *http_network_session_->http_auth_cache());
+}
+
 }  // namespace gcm