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

Side by Side 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: Self review 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "google_apis/gcm/engine/connection_factory_impl.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "google_apis/gcm/engine/connection_handler_impl.h"
9 #include "google_apis/gcm/protocol/mcs.pb.h"
10 #include "net/base/net_errors.h"
11 #include "net/http/http_network_session.h"
12 #include "net/http/http_request_headers.h"
13 #include "net/proxy/proxy_info.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/client_socket_pool_manager.h"
16 #include "net/ssl/ssl_config_service.h"
17
18 namespace gcm {
19
20 namespace {
21
22 // The amount of time a Socket read should wait before timing out.
23 const int kReadTimeoutMs = 30000; // 30 seconds.
24
25 // Backoff policy.
26 const net::BackoffEntry::Policy kConnectionBackoffPolicy = {
27 // Number of initial errors (in sequence) to ignore before applying
28 // exponential back-off rules.
29 0,
30
31 // Initial delay for exponential back-off in ms.
32 10000, // 10 seconds.
33
34 // Factor by which the waiting time will be multiplied.
35 2,
36
37 // Fuzzing percentage. ex: 10% will spread requests randomly
38 // between 90%-100% of the calculated time.
39 0.2, // 20%.
40
41 // Maximum amount of time we are willing to delay our request in ms.
42 1000 * 3600 * 4, // 4 hours.
43
44 // Time to keep an entry from being discarded even when it
45 // has no significant state, -1 to never discard.
46 -1,
47
48 // Don't use initial delay unless the last request was an error.
49 false,
50 };
51
52 // Callback for hostname resolution attempts. Just returns an error if no
53 // addresses were resolved.
54 int OnResolutionDone(const net::AddressList& address_list,
55 const net::BoundNetLog& net_log) {
56 if (address_list.empty()) {
57 LOG(ERROR) << "Failed to resolve hostname.";
58 return net::ERR_NAME_RESOLUTION_FAILED;
59 }
60 DVLOG(1) << "MCS Hostname resolution success.";
61 return net::OK;
62 }
63
64 } // namespace
65
66 ConnectionFactoryImpl::ConnectionFactoryImpl(
67 const GURL& mcs_endpoint,
68 scoped_refptr<net::HttpNetworkSession> network_session,
69 net::NetLog* net_log)
70 : mcs_endpoint_(mcs_endpoint),
71 network_session_(network_session),
72 net_log_(net_log),
73 backoff_entry_(&kConnectionBackoffPolicy),
74 weak_ptr_factory_(this) {
75 }
76
77 ConnectionFactoryImpl::~ConnectionFactoryImpl() {
78 }
79
80 ConnectionHandler* ConnectionFactoryImpl::BuildConnectionHandler(
81 const ConnectionHandler::ProtoReceivedCallback& read_callback,
82 const ConnectionHandler::ProtoSentCallback& write_callback) {
83 DCHECK(!connection_handler_.get());
akalin 2013/11/02 00:15:43 i feel like you should do: if (!connection_handle
Nicolas Zea 2013/11/15 23:37:35 Assuming you mean if (connection_handler_), done.
84 net::NetworkChangeNotifier::AddIPAddressObserver(this);
85 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
86 connection_handler_.reset(
87 new ConnectionHandlerImpl(
88 base::TimeDelta::FromMilliseconds(kReadTimeoutMs),
89 read_callback,
90 write_callback,
91 base::Bind(&ConnectionFactoryImpl::ConnectionHandlerCallback,
92 weak_ptr_factory_.GetWeakPtr())));
93 return connection_handler_.get();
94 }
95
96 void ConnectionFactoryImpl::Connect(
97 const mcs_proto::LoginRequest& login_request) {
98 DCHECK(connection_handler_.get());
akalin 2013/11/02 00:15:43 no .get()
Nicolas Zea 2013/11/15 23:37:35 Done.
99 DCHECK(!IsEndpointReachable());
100
101 login_request_ = login_request;
102
103 ConnectImpl();
104 }
105
106 bool ConnectionFactoryImpl::IsEndpointReachable() const {
akalin 2013/11/02 00:15:43 no .get() (and everywhere else in a boolean contex
Nicolas Zea 2013/11/15 23:37:35 Done.
107 return connection_handler_.get() && connection_handler_->CanSendMessage();
108 }
109
110 void ConnectionFactoryImpl::OnConnectionTypeChanged(
111 net::NetworkChangeNotifier::ConnectionType type) {
112 // TODO(zea): implement different backoff/retry policies based on connection
113 // type.
114 DVLOG(1) << "Connection type changed to " << type << ", resetting backoff.";
115 backoff_entry_.Reset();
116 // ConnectImpl() should be retrying with backoff already if a connection is
117 // necessary, so no need to call again.
118 }
119
120 void ConnectionFactoryImpl::OnIPAddressChanged() {
121 DVLOG(1) << "IP Address changed, resetting backoff.";
122 backoff_entry_.Reset();
123 // ConnectImpl() should be retrying with backoff already if a connection is
124 // necessary, so no need to call again.
125 }
126
127 void ConnectionFactoryImpl::ConnectImpl() {
128 DCHECK(!IsEndpointReachable());
129
130 if (backoff_entry_.ShouldRejectRequest()) {
akalin 2013/11/02 00:15:43 i feel like this logic should be moved into Connec
Nicolas Zea 2013/11/15 23:37:35 Assuming you mean move to Connect, done.
131 DVLOG(1) << "Delaying MCS endpoint connection for "
132 << backoff_entry_.GetTimeUntilRelease().InSeconds() << " seconds.";
133 base::MessageLoop::current()->PostDelayedTask(
134 FROM_HERE,
135 base::Bind(&ConnectionFactoryImpl::ConnectImpl,
136 weak_ptr_factory_.GetWeakPtr()),
137 backoff_entry_.GetTimeUntilRelease());
138 return;
139 }
140
141 DVLOG(1) << "Attempting connection to MCS endpoint.";
142
143 // TODO(zea): resolve proxies.
144 net::ProxyInfo proxy_info;
145 proxy_info.UseDirect();
146 net::SSLConfig ssl_config;
147 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
148
149 // TODO(zea): This should probably be a raw request, but there's no good
akalin 2013/11/02 00:15:43 yeah, I think this should be a raw request. having
Nicolas Zea 2013/11/15 23:37:35 Raw connect takes a host/port pair, and prepends a
150 // way to force SSL for a raw request yet. Instead, pretend to be an https
151 // request (which provides hostname resolution as well).
152 int status = net::InitSocketHandleForHttpRequest(
153 mcs_endpoint_,
154 net::HttpRequestHeaders(),
155 0, // No load flags.
156 net::MEDIUM, // Normal priority.
157 network_session_.get(),
158 proxy_info,
159 false, // Don't force SPDY over SSL.
160 false, // Don't want SPDY over NPN.
161 ssl_config,
162 ssl_config,
163 net::kPrivacyModeDisabled,
164 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_SOCKET),
165 &socket_handle_,
166 base::Bind(&OnResolutionDone),
167 base::Bind(&ConnectionFactoryImpl::OnConnectDone,
168 weak_ptr_factory_.GetWeakPtr()));
169 if (status != net::ERR_IO_PENDING)
170 OnConnectDone(status);
171 }
172
173 void ConnectionFactoryImpl::OnConnectDone(int result) {
174 if (result != net::OK) {
175 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
176 backoff_entry_.InformOfRequest(false);
177 ConnectImpl();
178 return;
179 }
180
181 DVLOG(1) << "MCS endpoint connection success.";
182
183 // Reset the backoff.
184 backoff_entry_.Reset();
185
186 // Login to the server.
187 connection_handler_->Init(login_request_, socket_handle_.PassSocket());
188 }
189
190 void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
191 // TODO(zea): Consider how to handle errors that may require some sort of
192 // user intervention (login page, etc.).
193 LOG(ERROR) << "Connection reset with error " << result;
194 backoff_entry_.InformOfRequest(false);
195 ConnectImpl();
196 }
197
198 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698