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

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

Issue 54743007: [GCM] Add connection factory for creating MCS connections (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix Created 7 years, 1 month 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
new file mode 100644
index 0000000000000000000000000000000000000000..c7e5cb586392cd7ad74711fb622760a48fa6ba9b
--- /dev/null
+++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "google_apis/gcm/engine/connection_factory_impl.h"
+
+#include "base/message_loop/message_loop.h"
+#include "google_apis/gcm/engine/connection_handler_impl.h"
+#include "google_apis/gcm/protocol/mcs.pb.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_request_headers.h"
+#include "net/proxy/proxy_info.h"
+#include "net/socket/client_socket_handle.h"
+#include "net/socket/client_socket_pool_manager.h"
+#include "net/ssl/ssl_config_service.h"
+
+namespace gcm {
+
+namespace {
+
+// The amount of time a Socket read should wait before timing out.
+const int kReadTimeoutMs = 30000; // 30 seconds.
+
+// Backoff policy.
+const net::BackoffEntry::Policy kConnectionBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
+
+ // Initial delay for exponential back-off in ms.
+ 10000, // 10 seconds.
+
+ // Factor by which the waiting time will be multiplied.
+ 2,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.2, // 20%.
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ 1000 * 3600 * 4, // 4 hours.
+
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
+
+ // Don't use initial delay unless the last request was an error.
+ false,
+};
+
+// Callback for hostname resolution attempts. Just returns an error if no
+// addresses were resolved.
+int OnResolutionDone(const net::AddressList& address_list,
+ const net::BoundNetLog& net_log) {
+ if (address_list.empty()) {
+ LOG(ERROR) << "Failed to resolve hostname.";
+ return net::ERR_NAME_RESOLUTION_FAILED;
+ }
+ DVLOG(1) << "MCS Hostname resolution success.";
+ return net::OK;
+}
+
+} // namespace
+
+ConnectionFactoryImpl::ConnectionFactoryImpl(
+ const GURL& mcs_endpoint,
+ scoped_refptr<net::HttpNetworkSession> network_session,
+ net::NetLog* net_log)
+ : mcs_endpoint_(mcs_endpoint),
+ network_session_(network_session),
+ net_log_(net_log),
+ weak_ptr_factory_(this) {
+}
+
+ConnectionFactoryImpl::~ConnectionFactoryImpl() {
+}
+
+ConnectionHandler* ConnectionFactoryImpl::BuildConnectionHandler(
+ const ConnectionHandler::ProtoReceivedCallback& read_callback,
+ const ConnectionHandler::ProtoSentCallback& write_callback) {
+ if (connection_handler_) {
+ NOTREACHED();
+ return NULL;
akalin 2013/11/21 04:13:09 hmm on second thought, it's likely that the caller
Nicolas Zea 2013/11/22 05:39:18 True. Opted for DCHECK + return always returning c
+ }
+
+ backoff_entry_ = CreateBackoffEntry(&kConnectionBackoffPolicy);
+
+ 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())));
+ return connection_handler_.get();
+}
+
+void ConnectionFactoryImpl::Connect(
+ const mcs_proto::LoginRequest& login_request) {
+ DCHECK(connection_handler_);
+ DCHECK(!IsEndpointReachable());
+
+ if (login_request.IsInitialized()) {
+ DCHECK(!login_request_.IsInitialized());
+ login_request_ = login_request;
+ }
+
+ if (backoff_entry_->ShouldRejectRequest()) {
+ DVLOG(1) << "Delaying MCS endpoint connection for "
+ << backoff_entry_->GetTimeUntilRelease().InMilliseconds()
+ << " milliseconds.";
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ConnectionFactoryImpl::Connect,
+ weak_ptr_factory_.GetWeakPtr(),
+ login_request_),
+ NextRetryAttempt() - base::TimeTicks::Now());
+ return;
+ }
+
+ DVLOG(1) << "Attempting connection to MCS endpoint.";
+ ConnectImpl();
+}
+
+bool ConnectionFactoryImpl::IsEndpointReachable() const {
+ return connection_handler_ && connection_handler_->CanSendMessage();
+}
+
+base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const {
+ if (!backoff_entry_)
+ return base::TimeTicks();
+ return backoff_entry_->GetReleaseTime();
+}
+
+void ConnectionFactoryImpl::OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ 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.
+}
+
+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.
+}
+
+void ConnectionFactoryImpl::ConnectImpl() {
+ DCHECK(!IsEndpointReachable());
+
+ // TODO(zea): resolve proxies.
akalin 2013/11/21 04:13:09 this is probably for a future CL, but you can copy
Nicolas Zea 2013/11/22 05:39:18 Will do. I plan to add some fallback logic in gene
+ net::ProxyInfo proxy_info;
+ proxy_info.UseDirect();
+ net::SSLConfig ssl_config;
+ network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
+
+ // TODO(zea): This should probably be a raw request, but there's no good
akalin 2013/11/21 03:21:12 yeah, I think adding a InitSocketHandleForTlsConne
Nicolas Zea 2013/11/22 05:39:18 Done.
+ // way to force SSL for a raw request yet. Instead, pretend to be an https
+ // request (which provides hostname resolution as well).
+ int status = net::InitSocketHandleForHttpRequest(
+ mcs_endpoint_,
+ net::HttpRequestHeaders(),
+ 0, // No load flags.
+ net::MEDIUM, // Normal priority.
+ network_session_.get(),
+ proxy_info,
+ false, // Don't force SPDY over SSL.
+ false, // Don't want SPDY over NPN.
+ ssl_config,
+ ssl_config,
+ net::kPrivacyModeDisabled,
+ net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_SOCKET),
+ &socket_handle_,
+ base::Bind(&OnResolutionDone),
+ base::Bind(&ConnectionFactoryImpl::OnConnectDone,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (status != net::ERR_IO_PENDING)
+ OnConnectDone(status);
+}
+
+void ConnectionFactoryImpl::InitHandler() {
+ connection_handler_->Init(login_request_, socket_handle_.PassSocket());
+}
+
+scoped_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
akalin 2013/11/21 04:13:09 this is used once -- do you need it to be a separa
Nicolas Zea 2013/11/22 05:39:18 Doing it this way allows me to override this metho
+ const net::BackoffEntry::Policy* const policy) {
+ return scoped_ptr<net::BackoffEntry>(new net::BackoffEntry(policy));
+}
+
+void ConnectionFactoryImpl::OnConnectDone(int result) {
+ if (result != net::OK) {
+ LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
+ backoff_entry_->InformOfRequest(false);
+ Connect(mcs_proto::LoginRequest());
+ return;
+ }
+
+ DVLOG(1) << "MCS endpoint connection success.";
+
+ // Reset the backoff.
+ backoff_entry_->Reset();
+
+ InitHandler();
+}
+
+void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
+ // TODO(zea): Consider how to handle errors that may require some sort of
+ // user intervention (login page, etc.).
+ LOG(ERROR) << "Connection reset with error " << result;
+ backoff_entry_->InformOfRequest(false);
+ Connect(mcs_proto::LoginRequest());
+}
+
+} // namespace gcm

Powered by Google App Engine
This is Rietveld 408576698