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

Side by Side Diff: chrome/browser/sync/notifier/communicator/login.cc

Issue 194065: Initial commit of sync engine code to browser/sync.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Fixes to gtest include path, reverted syncapi. Created 11 years, 3 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 unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 <string>
6
7 #include "chrome/browser/sync/notifier/communicator/login.h"
8
9 #include "chrome/browser/sync/notifier/base/network_status_detector_task.h"
10 #include "chrome/browser/sync/notifier/base/time.h"
11 #include "chrome/browser/sync/notifier/base/timer.h"
12 #include "chrome/browser/sync/notifier/communicator/auto_reconnect.h"
13 #include "chrome/browser/sync/notifier/communicator/connection_options.h"
14 #include "chrome/browser/sync/notifier/communicator/login_settings.h"
15 #include "chrome/browser/sync/notifier/communicator/product_info.h"
16 #include "chrome/browser/sync/notifier/communicator/single_login_attempt.h"
17 #include "talk/base/common.h"
18 #include "talk/base/firewallsocketserver.h"
19 #include "talk/base/logging.h"
20 #include "talk/base/taskrunner.h"
21 #include "talk/xmllite/xmlelement.h"
22 #include "talk/xmpp/asyncsocket.h"
23 #include "talk/xmpp/prexmppauth.h"
24 #include "talk/xmpp/xmppclient.h"
25 #include "talk/xmpp/xmppclientsettings.h"
26 #include "talk/xmpp/xmppengine.h"
27
28 namespace notifier {
29
30 // redirect valid for 5 minutes
31 static const time64 kRedirectTimeoutNs = 5 * kMinsTo100ns;
32
33 // Disconnect if network stays down for more than 10 seconds.
34 static const int kDisconnectionDelaySecs = 10;
35
36 Login::Login(talk_base::Task* parent,
37 const buzz::XmppClientSettings& user_settings,
38 const ConnectionOptions& options,
39 std::string lang,
40 ServerInformation* server_list,
41 int server_count,
42 NetworkStatusDetectorTask* network_status,
43 talk_base::FirewallManager* firewall,
44 bool no_gaia_auth,
45 bool proxy_only,
46 bool previous_login_successful)
47 : login_settings_(new LoginSettings(user_settings,
48 options,
49 lang,
50 server_list,
51 server_count,
52 firewall,
53 no_gaia_auth,
54 proxy_only)),
55 single_attempt_(NULL),
56 successful_connection_(previous_login_successful),
57 parent_(parent),
58 state_(STATE_OPENING),
59 redirect_time_ns_(0),
60 redirect_port_(0),
61 unexpected_disconnect_occurred_(false),
62 reset_unexpected_timer_(NULL),
63 google_host_(user_settings.host()),
64 google_user_(user_settings.user()),
65 disconnect_timer_(NULL) {
66 if (!network_status) {
67 network_status = NetworkStatusDetectorTask::Create(parent_);
68 if (network_status) {
69 // On linux we don't have an implementation of NetworkStatusDetectorTask.
70 network_status->Start();
71 }
72 }
73 network_status->SignalNetworkStateDetected.connect(
74 this, &Login::OnNetworkStateDetected);
75 auto_reconnect_.reset(new AutoReconnect(parent_, network_status));
76 auto_reconnect_->SignalStartConnection.connect(this,
77 &Login::StartConnection);
78 auto_reconnect_->SignalTimerStartStop.connect(
79 this,
80 &Login::OnAutoReconnectTimerChange);
81 SignalClientStateChange.connect(auto_reconnect_.get(),
82 &AutoReconnect::OnClientStateChange);
83 SignalIdleChange.connect(auto_reconnect_.get(),
84 &AutoReconnect::set_idle);
85 SignalPowerSuspended.connect(auto_reconnect_.get(),
86 &AutoReconnect::OnPowerSuspend);
87 }
88
89 // defined so that the destructors are executed here (and
90 // the corresponding classes don't need to be included in
91 // the header file)
92 Login::~Login() {
93 if (single_attempt_) {
94 single_attempt_->Abort();
95 single_attempt_ = NULL;
96 }
97 }
98
99 void Login::StartConnection() {
100 // If there is a server redirect, use it.
101 if (GetCurrent100NSTime() < redirect_time_ns_ + kRedirectTimeoutNs) {
102 // Override server/port with redirect values
103 talk_base::SocketAddress server_override;
104 server_override.SetIP(redirect_server_, false);
105 ASSERT(redirect_port_ != 0);
106 server_override.SetPort(redirect_port_);
107 login_settings_->set_server_override(server_override);
108 } else {
109 login_settings_->clear_server_override();
110 }
111
112 if (single_attempt_) {
113 single_attempt_->Abort();
114 single_attempt_ = NULL;
115 }
116 single_attempt_ = new SingleLoginAttempt(parent_,
117 login_settings_.get(),
118 successful_connection_);
119
120 // Do the signaling hook-ups.
121 single_attempt_->SignalLoginFailure.connect(this, &Login::OnLoginFailure);
122 single_attempt_->SignalRedirect.connect(this, &Login::OnRedirect);
123 single_attempt_->SignalClientStateChange.connect(
124 this,
125 &Login::OnClientStateChange) ;
126 single_attempt_->SignalUnexpectedDisconnect.connect(
127 this,
128 &Login::OnUnexpectedDisconnect);
129 single_attempt_->SignalLogoff.connect(
130 this,
131 &Login::OnLogoff);
132 single_attempt_->SignalNeedAutoReconnect.connect(
133 this,
134 &Login::DoAutoReconnect);
135 SignalLogInput.repeat(single_attempt_->SignalLogInput);
136 SignalLogOutput.repeat(single_attempt_->SignalLogOutput);
137
138 single_attempt_->Start();
139 }
140
141 const std::string& Login::google_host() const {
142 return google_host_;
143 }
144
145 const std::string& Login::google_user() const {
146 return google_user_;
147 }
148
149 const talk_base::ProxyInfo& Login::proxy() const {
150 return proxy_info_;
151 }
152
153 void Login::OnLoginFailure(const LoginFailure& failure) {
154 auto_reconnect_->StopReconnectTimer();
155 HandleClientStateChange(STATE_CLOSED);
156 SignalLoginFailure(failure);
157 }
158
159 void Login::OnLogoff() {
160 HandleClientStateChange(STATE_CLOSED);
161 }
162
163 void Login::OnClientStateChange(buzz::XmppEngine::State state) {
164 ConnectionState new_state = STATE_CLOSED;
165
166 switch (state) {
167 case buzz::XmppEngine::STATE_NONE:
168 case buzz::XmppEngine::STATE_CLOSED:
169 // Ignore the closed state (because
170 // we may be trying the next dns entry).
171 //
172 // But we go to this state for other
173 // signals when there is no retry happening.
174 new_state = state_;
175 break;
176
177 case buzz::XmppEngine::STATE_START:
178 case buzz::XmppEngine::STATE_OPENING:
179 new_state = STATE_OPENING;
180 break;
181
182 case buzz::XmppEngine::STATE_OPEN:
183 new_state = STATE_OPENED;
184 break;
185
186 default:
187 ASSERT(false);
188 break;
189 }
190 HandleClientStateChange(new_state);
191 }
192
193 void Login::HandleClientStateChange(ConnectionState new_state) {
194 // Do we need to transition between the retrying and closed states?
195 if (auto_reconnect_->is_retrying()) {
196 if (new_state == STATE_CLOSED) {
197 new_state = STATE_RETRYING;
198 }
199 } else {
200 if (new_state == STATE_RETRYING) {
201 new_state = STATE_CLOSED;
202 }
203 }
204
205 if (new_state != state_) {
206 state_ = new_state;
207 if (reset_unexpected_timer_) {
208 reset_unexpected_timer_->Abort();
209 reset_unexpected_timer_ = NULL;
210 }
211
212 if (state_ == STATE_OPENED) {
213 successful_connection_ = true;
214
215 google_host_ = single_attempt_->xmpp_client()->jid().domain();
216 google_user_ = single_attempt_->xmpp_client()->jid().node();
217 proxy_info_ = single_attempt_->proxy();
218
219 reset_unexpected_timer_ = new Timer(parent_,
220 kResetReconnectInfoDelaySec,
221 false); // repeat
222 reset_unexpected_timer_->SignalTimeout.connect(
223 this,
224 &Login::ResetUnexpectedDisconnect);
225 }
226 SignalClientStateChange(state_);
227 }
228 }
229
230 void Login::OnAutoReconnectTimerChange() {
231 if (!single_attempt_ || !single_attempt_->xmpp_client()) {
232 HandleClientStateChange(STATE_CLOSED);
233 return;
234 }
235 OnClientStateChange(single_attempt_->xmpp_client()->GetState());
236 }
237
238 buzz::XmppClient* Login::xmpp_client() {
239 if (!single_attempt_) {
240 return NULL;
241 }
242 return single_attempt_->xmpp_client();
243 }
244
245 int Login::seconds_until_reconnect() const {
246 return auto_reconnect_->seconds_until();
247 }
248
249 void Login::UseNextConnection() {
250 if (!single_attempt_) {
251 // Just in case, there is an obscure case that causes
252 // this to get called when there is no single_attempt_.
253 return;
254 }
255 single_attempt_->UseNextConnection();
256 }
257
258 void Login::UseCurrentConnection() {
259 if (!single_attempt_) {
260 // Just in case, there is an obscure case that causes
261 // this to get called when there is no single_attempt_.
262 return;
263 }
264 single_attempt_->UseCurrentConnection();
265 }
266
267 void Login::OnRedirect(const std::string& redirect_server, int redirect_port) {
268 ASSERT(redirect_port_ != 0);
269
270 redirect_time_ns_ = GetCurrent100NSTime();
271 redirect_server_ = redirect_server;
272 redirect_port_ = redirect_port;
273
274 // Drop the current connection, and start the login process again
275 StartConnection();
276 }
277
278 void Login::OnUnexpectedDisconnect() {
279 if (reset_unexpected_timer_) {
280 reset_unexpected_timer_->Abort();
281 reset_unexpected_timer_ = NULL;
282 }
283
284 // Start the login process again
285 if (unexpected_disconnect_occurred_) {
286 // If we already have received an unexpected disconnect recently,
287 // then our account may have be jailed due to abuse, so we shouldn't
288 // make the situation worse by trying really hard to reconnect.
289 // Instead, we'll do the autoreconnect route, which has exponential
290 // back-off.
291 DoAutoReconnect();
292 return;
293 }
294 StartConnection();
295 unexpected_disconnect_occurred_ = true;
296 }
297
298 void Login::ResetUnexpectedDisconnect() {
299 reset_unexpected_timer_ = NULL;
300 unexpected_disconnect_occurred_ = false;
301 }
302
303 void Login::DoAutoReconnect() {
304 bool allow_auto_reconnect =
305 login_settings_->connection_options().auto_reconnect();
306 // Start the reconnect time before aborting the connection
307 // to ensure that AutoReconnect::is_retrying() is true, so
308 // that the Login doesn't transition to the CLOSED state
309 // (which would cause the reconnection timer to reset
310 // and not double).
311 if (allow_auto_reconnect) {
312 auto_reconnect_->StartReconnectTimer();
313 }
314
315 if (single_attempt_) {
316 single_attempt_->Abort();
317 single_attempt_ = NULL;
318 }
319
320 if (!allow_auto_reconnect) {
321 HandleClientStateChange(STATE_CLOSED);
322 return;
323 }
324 }
325
326 void Login::OnNetworkStateDetected(bool was_alive, bool is_alive) {
327 if (was_alive && !is_alive) {
328 // Our network connection just went down.
329 // Setup a timer to disconnect. Don't disconnect immediately to avoid
330 // constant connection/disconnection due to flaky network interfaces.
331 ASSERT(disconnect_timer_ == NULL);
332 disconnect_timer_ = new Timer(parent_, kDisconnectionDelaySecs, false);
333 disconnect_timer_->SignalTimeout.connect(this,
334 &Login::OnDisconnectTimeout);
335 } else if (!was_alive && is_alive) {
336 // Our connection has come back up. If we have a disconnect timer going,
337 // abort it so we don't disconnect.
338 if (disconnect_timer_) {
339 disconnect_timer_->Abort();
340 // It will free itself.
341 disconnect_timer_ = NULL;
342 }
343 }
344 }
345
346 void Login::OnDisconnectTimeout() {
347 disconnect_timer_ = NULL;
348
349 if (state_ != STATE_OPENED) {
350 return;
351 }
352
353 if (single_attempt_) {
354 single_attempt_->Abort();
355 single_attempt_ = NULL;
356 }
357
358 StartConnection();
359 }
360
361 } // namespace notifier
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698