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

Unified Diff: google_apis/gcm/engine/connection_factory_impl.cc

Issue 213693002: [GCM] Add support for canary connection attempts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refactor tests Created 6 years, 9 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 side-by-side diff with in-line comments
Download patch
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 deb810264171bab7fe326114fcc3dec19249fc90..9dff1f69c8db392b62a6d2cf23ea8759d3c2fa73 100644
--- a/google_apis/gcm/engine/connection_factory_impl.cc
+++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -54,6 +54,7 @@ ConnectionFactoryImpl::ConnectionFactoryImpl(
net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)),
pac_request_(NULL),
connecting_(false),
+ waiting_for_backoff_(false),
logging_in_(false),
weak_ptr_factory_(this) {
DCHECK_GE(mcs_endpoints_.size(), 1U);
@@ -78,13 +79,12 @@ void ConnectionFactoryImpl::Initialize(
net::NetworkChangeNotifier::AddIPAddressObserver(this);
net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
- connection_handler_.reset(
- new ConnectionHandlerImpl(
- base::TimeDelta::FromMilliseconds(kReadTimeoutMs),
- read_callback,
- write_callback,
- base::Bind(&ConnectionFactoryImpl::ConnectionHandlerCallback,
- weak_ptr_factory_.GetWeakPtr())));
+ connection_handler_ = CreateConnectionHandler(
+ base::TimeDelta::FromMilliseconds(kReadTimeoutMs),
+ read_callback,
+ write_callback,
+ base::Bind(&ConnectionFactoryImpl::ConnectionHandlerCallback,
+ weak_ptr_factory_.GetWeakPtr())).Pass();
}
ConnectionHandler* ConnectionFactoryImpl::GetConnectionHandler() const {
@@ -94,35 +94,53 @@ ConnectionHandler* ConnectionFactoryImpl::GetConnectionHandler() const {
void ConnectionFactoryImpl::Connect() {
DCHECK(connection_handler_);
- connecting_ = true;
+ if (connecting_ || waiting_for_backoff_)
jianli 2014/03/28 04:26:13 Now it becomes a bit harder to follow all the logi
Nicolas Zea 2014/03/28 17:53:42 The problem is that, because of canaries, these tw
+ return; // Connection attempt already in progress or pending.
+
+ if (IsEndpointReachable())
+ return; // Already connected.
+
+ ConnectWithBackoff();
+}
+
+void ConnectionFactoryImpl::ConnectWithBackoff() {
+ // If a canary managed to connect while a backoff expiration was pending,
+ // just cleanup the internal state.
+ if (connecting_ || IsEndpointReachable()) {
+ waiting_for_backoff_ = false;
+ return;
+ }
+
if (backoff_entry_->ShouldRejectRequest()) {
DVLOG(1) << "Delaying MCS endpoint connection for "
<< backoff_entry_->GetTimeUntilRelease().InMilliseconds()
<< " milliseconds.";
+ waiting_for_backoff_ = true;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
- base::Bind(&ConnectionFactoryImpl::Connect,
+ base::Bind(&ConnectionFactoryImpl::ConnectWithBackoff,
weak_ptr_factory_.GetWeakPtr()),
backoff_entry_->GetTimeUntilRelease());
return;
}
DVLOG(1) << "Attempting connection to MCS endpoint.";
+ waiting_for_backoff_ = false;
ConnectImpl();
}
bool ConnectionFactoryImpl::IsEndpointReachable() const {
- return connection_handler_ &&
- connection_handler_->CanSendMessage() &&
- !connecting_;
+ return connection_handler_ && connection_handler_->CanSendMessage();
}
void ConnectionFactoryImpl::SignalConnectionReset(
ConnectionResetReason reason) {
// A failure can trigger multiple resets, so no need to do anything if a
// connection is already in progress.
- if (connecting_)
+ if (connecting_) {
+ DVLOG(1) << "Connection in progress, ignoring reset.";
return;
+ }
UMA_HISTOGRAM_ENUMERATION("GCM.ConnectionResetReason",
reason,
@@ -138,6 +156,16 @@ void ConnectionFactoryImpl::SignalConnectionReset(
}
CloseSocket();
+ DCHECK(!IsEndpointReachable());
+
+ // 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
+ // is already awaiting backoff expiration.
+ if (waiting_for_backoff_ && reason != NETWORK_CHANGE) {
+ DVLOG(1) << "Backoff expiration pending, ignoring reset.";
+ return;
+ }
if (logging_in_) {
// Failures prior to login completion just reuse the existing backoff entry.
@@ -149,10 +177,15 @@ void ConnectionFactoryImpl::SignalConnectionReset(
// the backoff entry that was saved off at login completion time.
backoff_entry_.swap(previous_backoff_);
backoff_entry_->InformOfRequest(false);
+ } else if (reason == NETWORK_CHANGE) {
+ ConnectImpl(); // Canary attempts bypass backoff without resetting it.
+ return;
} else {
// 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.
@@ -172,19 +205,17 @@ void ConnectionFactoryImpl::OnConnectionTypeChanged(
if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
return;
- // TODO(zea): implement different backoff/retry policies based on connection
- // type.
- DVLOG(1) << "Connection type changed to " << type << ", resetting backoff.";
- backoff_entry_->Reset();
- // Connect(..) should be retrying with backoff already if a connection is
- // necessary, so no need to call again.
+ 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, resetting backoff.";
- backoff_entry_->Reset();
- // Connect(..) should be retrying with backoff already if a connection is
- // necessary, so no need to call again.
+ DVLOG(1) << "IP Address changed, reconnecting.";
+
+ // The connection may have been silently dropped, attempt to reconnect.
+ SignalConnectionReset(NETWORK_CHANGE);
}
GURL ConnectionFactoryImpl::GetCurrentEndpoint() const {
@@ -196,9 +227,10 @@ GURL ConnectionFactoryImpl::GetCurrentEndpoint() const {
}
void ConnectionFactoryImpl::ConnectImpl() {
- DCHECK(connecting_);
+ DCHECK(!IsEndpointReachable());
DCHECK(!socket_handle_.socket());
+ connecting_ = true;
int status = network_session_->proxy_service()->ResolveProxy(
GetCurrentEndpoint(),
&proxy_info_,
@@ -226,6 +258,18 @@ scoped_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
return scoped_ptr<net::BackoffEntry>(new net::BackoffEntry(policy));
}
+scoped_ptr<ConnectionHandler> ConnectionFactoryImpl::CreateConnectionHandler(
+ base::TimeDelta read_timeout,
+ const ConnectionHandler::ProtoReceivedCallback& read_callback,
+ const ConnectionHandler::ProtoSentCallback& write_callback,
+ const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
+ return make_scoped_ptr<ConnectionHandler>(
+ new ConnectionHandlerImpl(read_timeout,
+ read_callback,
+ write_callback,
+ connection_callback));
+}
+
base::TimeTicks ConnectionFactoryImpl::NowTicks() {
return base::TimeTicks::Now();
}
@@ -251,6 +295,7 @@ void ConnectionFactoryImpl::OnConnectDone(int result) {
next_endpoint_++;
if (next_endpoint_ >= mcs_endpoints_.size())
next_endpoint_ = 0;
+ connecting_ = false;
Connect();
return;
}
« no previous file with comments | « google_apis/gcm/engine/connection_factory_impl.h ('k') | google_apis/gcm/engine/connection_factory_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698