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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 : mcs_endpoints_(mcs_endpoints), | 50 : mcs_endpoints_(mcs_endpoints), |
51 next_endpoint_(0), | 51 next_endpoint_(0), |
52 last_successful_endpoint_(0), | 52 last_successful_endpoint_(0), |
53 backoff_policy_(backoff_policy), | 53 backoff_policy_(backoff_policy), |
54 network_session_(network_session), | 54 network_session_(network_session), |
55 bound_net_log_( | 55 bound_net_log_( |
56 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), | 56 net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), |
57 pac_request_(NULL), | 57 pac_request_(NULL), |
58 connecting_(false), | 58 connecting_(false), |
59 waiting_for_backoff_(false), | 59 waiting_for_backoff_(false), |
| 60 waiting_for_network_change_(false), |
60 logging_in_(false), | 61 logging_in_(false), |
61 recorder_(recorder), | 62 recorder_(recorder), |
62 listener_(NULL), | 63 listener_(NULL), |
63 weak_ptr_factory_(this) { | 64 weak_ptr_factory_(this) { |
64 DCHECK_GE(mcs_endpoints_.size(), 1U); | 65 DCHECK_GE(mcs_endpoints_.size(), 1U); |
65 } | 66 } |
66 | 67 |
67 ConnectionFactoryImpl::~ConnectionFactoryImpl() { | 68 ConnectionFactoryImpl::~ConnectionFactoryImpl() { |
68 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 69 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
69 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | |
70 if (pac_request_) { | 70 if (pac_request_) { |
71 network_session_->proxy_service()->CancelPacRequest(pac_request_); | 71 network_session_->proxy_service()->CancelPacRequest(pac_request_); |
72 pac_request_ = NULL; | 72 pac_request_ = NULL; |
73 } | 73 } |
74 } | 74 } |
75 | 75 |
76 void ConnectionFactoryImpl::Initialize( | 76 void ConnectionFactoryImpl::Initialize( |
77 const BuildLoginRequestCallback& request_builder, | 77 const BuildLoginRequestCallback& request_builder, |
78 const ConnectionHandler::ProtoReceivedCallback& read_callback, | 78 const ConnectionHandler::ProtoReceivedCallback& read_callback, |
79 const ConnectionHandler::ProtoSentCallback& write_callback) { | 79 const ConnectionHandler::ProtoSentCallback& write_callback) { |
80 DCHECK(!connection_handler_); | 80 DCHECK(!connection_handler_); |
81 | 81 |
82 previous_backoff_ = CreateBackoffEntry(&backoff_policy_); | 82 previous_backoff_ = CreateBackoffEntry(&backoff_policy_); |
83 backoff_entry_ = CreateBackoffEntry(&backoff_policy_); | 83 backoff_entry_ = CreateBackoffEntry(&backoff_policy_); |
84 request_builder_ = request_builder; | 84 request_builder_ = request_builder; |
85 | 85 |
86 net::NetworkChangeNotifier::AddIPAddressObserver(this); | 86 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
87 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 87 waiting_for_network_change_ = net::NetworkChangeNotifier::IsOffline(); |
88 connection_handler_ = CreateConnectionHandler( | 88 connection_handler_ = CreateConnectionHandler( |
89 base::TimeDelta::FromMilliseconds(kReadTimeoutMs), | 89 base::TimeDelta::FromMilliseconds(kReadTimeoutMs), |
90 read_callback, | 90 read_callback, |
91 write_callback, | 91 write_callback, |
92 base::Bind(&ConnectionFactoryImpl::ConnectionHandlerCallback, | 92 base::Bind(&ConnectionFactoryImpl::ConnectionHandlerCallback, |
93 weak_ptr_factory_.GetWeakPtr())).Pass(); | 93 weak_ptr_factory_.GetWeakPtr())).Pass(); |
94 } | 94 } |
95 | 95 |
96 ConnectionHandler* ConnectionFactoryImpl::GetConnectionHandler() const { | 96 ConnectionHandler* ConnectionFactoryImpl::GetConnectionHandler() const { |
97 return connection_handler_.get(); | 97 return connection_handler_.get(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 | 143 |
144 std::string ConnectionFactoryImpl::GetConnectionStateString() const { | 144 std::string ConnectionFactoryImpl::GetConnectionStateString() const { |
145 if (IsEndpointReachable()) | 145 if (IsEndpointReachable()) |
146 return "CONNECTED"; | 146 return "CONNECTED"; |
147 if (logging_in_) | 147 if (logging_in_) |
148 return "LOGGING IN"; | 148 return "LOGGING IN"; |
149 if (connecting_) | 149 if (connecting_) |
150 return "CONNECTING"; | 150 return "CONNECTING"; |
151 if (waiting_for_backoff_) | 151 if (waiting_for_backoff_) |
152 return "WAITING FOR BACKOFF"; | 152 return "WAITING FOR BACKOFF"; |
| 153 if (waiting_for_network_change_) |
| 154 return "WAITING FOR NETWORK CHANGE"; |
153 return "NOT CONNECTED"; | 155 return "NOT CONNECTED"; |
154 } | 156 } |
155 | 157 |
156 void ConnectionFactoryImpl::SignalConnectionReset( | 158 void ConnectionFactoryImpl::SignalConnectionReset( |
157 ConnectionResetReason reason) { | 159 ConnectionResetReason reason) { |
158 // A failure can trigger multiple resets, so no need to do anything if a | 160 // A failure can trigger multiple resets, so no need to do anything if a |
159 // connection is already in progress. | 161 // connection is already in progress. |
160 if (connecting_) { | 162 if (connecting_) { |
161 DVLOG(1) << "Connection in progress, ignoring reset."; | 163 DVLOG(1) << "Connection in progress, ignoring reset."; |
162 return; | 164 return; |
(...skipping 12 matching lines...) Expand all Loading... |
175 base::TimeDelta::FromSeconds(1), | 177 base::TimeDelta::FromSeconds(1), |
176 base::TimeDelta::FromHours(24), | 178 base::TimeDelta::FromHours(24), |
177 50); | 179 50); |
178 // |last_login_time_| will be reset below, before attempting the new | 180 // |last_login_time_| will be reset below, before attempting the new |
179 // connection. | 181 // connection. |
180 } | 182 } |
181 | 183 |
182 CloseSocket(); | 184 CloseSocket(); |
183 DCHECK(!IsEndpointReachable()); | 185 DCHECK(!IsEndpointReachable()); |
184 | 186 |
| 187 if (waiting_for_network_change_) |
| 188 return; |
| 189 |
185 // Network changes get special treatment as they can trigger a one-off canary | 190 // Network changes get special treatment as they can trigger a one-off canary |
186 // request that bypasses backoff (but does nothing if a connection is in | 191 // request that bypasses backoff (but does nothing if a connection is in |
187 // progress). Other connection reset events can be ignored as a connection | 192 // progress). Other connection reset events can be ignored as a connection |
188 // is already awaiting backoff expiration. | 193 // is already awaiting backoff expiration. |
189 if (waiting_for_backoff_ && reason != NETWORK_CHANGE) { | 194 if (waiting_for_backoff_ && reason != NETWORK_CHANGE) { |
190 DVLOG(1) << "Backoff expiration pending, ignoring reset."; | 195 DVLOG(1) << "Backoff expiration pending, ignoring reset."; |
191 return; | 196 return; |
192 } | 197 } |
193 | 198 |
194 if (logging_in_) { | 199 if (logging_in_) { |
195 // Failures prior to login completion just reuse the existing backoff entry. | 200 // Failures prior to login completion just reuse the existing backoff entry. |
196 logging_in_ = false; | 201 logging_in_ = false; |
197 backoff_entry_->InformOfRequest(false); | 202 backoff_entry_->InformOfRequest(false); |
198 } else if (reason == LOGIN_FAILURE || | 203 } else if (reason == LOGIN_FAILURE || |
199 ShouldRestorePreviousBackoff(last_login_time_, NowTicks())) { | 204 ShouldRestorePreviousBackoff(last_login_time_, NowTicks())) { |
200 // Failures due to login, or within the reset window of a login, restore | 205 // Failures due to login, or within the reset window of a login, restore |
201 // the backoff entry that was saved off at login completion time. | 206 // the backoff entry that was saved off at login completion time. |
202 backoff_entry_.swap(previous_backoff_); | 207 backoff_entry_.swap(previous_backoff_); |
203 backoff_entry_->InformOfRequest(false); | 208 backoff_entry_->InformOfRequest(false); |
204 } else if (reason == NETWORK_CHANGE) { | 209 } else if (reason == NETWORK_CHANGE) { |
205 ConnectImpl(); // Canary attempts bypass backoff without resetting it. | 210 ConnectImpl(); // Canary attempts bypass backoff without resetting it. |
206 return; | 211 return; |
207 } else { | 212 } else { |
208 // We shouldn't be in backoff in thise case. | 213 // We shouldn't be in backoff in thise case. |
209 DCHECK_EQ(0, backoff_entry_->failure_count()); | 214 DCHECK_EQ(0, backoff_entry_->failure_count()); |
210 } | 215 } |
211 DCHECK(!connecting_); | |
212 DCHECK(!waiting_for_backoff_); | |
213 | 216 |
214 // At this point the last login time has been consumed or deemed irrelevant, | 217 // At this point the last login time has been consumed or deemed irrelevant, |
215 // reset it. | 218 // reset it. |
216 last_login_time_ = base::TimeTicks(); | 219 last_login_time_ = base::TimeTicks(); |
217 | 220 |
218 Connect(); | 221 Connect(); |
219 } | 222 } |
220 | 223 |
221 void ConnectionFactoryImpl::SetConnectionListener( | 224 void ConnectionFactoryImpl::SetConnectionListener( |
222 ConnectionListener* listener) { | 225 ConnectionListener* listener) { |
223 listener_ = listener; | 226 listener_ = listener; |
224 } | 227 } |
225 | 228 |
226 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const { | 229 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const { |
227 if (!backoff_entry_) | 230 if (!backoff_entry_) |
228 return base::TimeTicks(); | 231 return base::TimeTicks(); |
229 return backoff_entry_->GetReleaseTime(); | 232 return backoff_entry_->GetReleaseTime(); |
230 } | 233 } |
231 | 234 |
232 void ConnectionFactoryImpl::OnConnectionTypeChanged( | 235 void ConnectionFactoryImpl::OnNetworkChanged( |
233 net::NetworkChangeNotifier::ConnectionType type) { | 236 net::NetworkChangeNotifier::ConnectionType type) { |
234 if (type == net::NetworkChangeNotifier::CONNECTION_NONE) | 237 if (type == net::NetworkChangeNotifier::CONNECTION_NONE) { |
| 238 DVLOG(1) << "Network lost, resettion connection."; |
| 239 waiting_for_network_change_ = true; |
| 240 |
| 241 // Will do nothing due to |waiting_for_network_change_ == true|. |
| 242 SignalConnectionReset(NETWORK_CHANGE); |
235 return; | 243 return; |
| 244 } |
236 | 245 |
237 DVLOG(1) << "Connection type changed to " << type << ", reconnecting."; | 246 DVLOG(1) << "Connection type changed to " << type << ", reconnecting."; |
238 | 247 waiting_for_network_change_ = false; |
239 // The connection may have been silently dropped, attempt to reconnect. | |
240 SignalConnectionReset(NETWORK_CHANGE); | 248 SignalConnectionReset(NETWORK_CHANGE); |
241 } | 249 } |
242 | 250 |
243 void ConnectionFactoryImpl::OnIPAddressChanged() { | |
244 DVLOG(1) << "IP Address changed, reconnecting."; | |
245 | |
246 // The connection may have been silently dropped, attempt to reconnect. | |
247 SignalConnectionReset(NETWORK_CHANGE); | |
248 } | |
249 | |
250 GURL ConnectionFactoryImpl::GetCurrentEndpoint() const { | 251 GURL ConnectionFactoryImpl::GetCurrentEndpoint() const { |
251 // Note that IsEndpointReachable() returns false anytime connecting_ is true, | 252 // Note that IsEndpointReachable() returns false anytime connecting_ is true, |
252 // so while connecting this always uses |next_endpoint_|. | 253 // so while connecting this always uses |next_endpoint_|. |
253 if (IsEndpointReachable()) | 254 if (IsEndpointReachable()) |
254 return mcs_endpoints_[last_successful_endpoint_]; | 255 return mcs_endpoints_[last_successful_endpoint_]; |
255 return mcs_endpoints_[next_endpoint_]; | 256 return mcs_endpoints_[next_endpoint_]; |
256 } | 257 } |
257 | 258 |
258 net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() { | 259 net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() { |
259 if (!socket_handle_.socket()) | 260 if (!socket_handle_.socket()) |
260 return net::IPEndPoint(); | 261 return net::IPEndPoint(); |
261 | 262 |
262 net::IPEndPoint ip_endpoint; | 263 net::IPEndPoint ip_endpoint; |
263 int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint); | 264 int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint); |
264 if (result != net::OK) | 265 if (result != net::OK) |
265 return net::IPEndPoint(); | 266 return net::IPEndPoint(); |
266 | 267 |
267 return ip_endpoint; | 268 return ip_endpoint; |
268 } | 269 } |
269 | 270 |
270 void ConnectionFactoryImpl::ConnectImpl() { | 271 void ConnectionFactoryImpl::ConnectImpl() { |
271 DCHECK(!IsEndpointReachable()); | 272 DCHECK(!IsEndpointReachable()); |
272 DCHECK(!socket_handle_.socket()); | 273 DCHECK(!socket_handle_.socket()); |
273 | 274 |
| 275 if (waiting_for_network_change_) |
| 276 return; |
| 277 |
274 connecting_ = true; | 278 connecting_ = true; |
275 GURL current_endpoint = GetCurrentEndpoint(); | 279 GURL current_endpoint = GetCurrentEndpoint(); |
276 recorder_->RecordConnectionInitiated(current_endpoint.host()); | 280 recorder_->RecordConnectionInitiated(current_endpoint.host()); |
277 int status = network_session_->proxy_service()->ResolveProxy( | 281 int status = network_session_->proxy_service()->ResolveProxy( |
278 current_endpoint, | 282 current_endpoint, |
279 &proxy_info_, | 283 &proxy_info_, |
280 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, | 284 base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone, |
281 weak_ptr_factory_.GetWeakPtr()), | 285 weak_ptr_factory_.GetWeakPtr()), |
282 &pac_request_, | 286 &pac_request_, |
283 bound_net_log_); | 287 bound_net_log_); |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 // the destroyed socket. | 533 // the destroyed socket. |
530 if (connection_handler_) | 534 if (connection_handler_) |
531 connection_handler_->Reset(); | 535 connection_handler_->Reset(); |
532 | 536 |
533 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected()) | 537 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected()) |
534 socket_handle_.socket()->Disconnect(); | 538 socket_handle_.socket()->Disconnect(); |
535 socket_handle_.Reset(); | 539 socket_handle_.Reset(); |
536 } | 540 } |
537 | 541 |
538 } // namespace gcm | 542 } // namespace gcm |
OLD | NEW |