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

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

Issue 1956001: Moved XMPP notifier library from chrome/browser/sync to chrome/common.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 7 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
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 proxy_only,
45 bool previous_login_successful)
46 : login_settings_(new LoginSettings(user_settings,
47 options,
48 lang,
49 server_list,
50 server_count,
51 firewall,
52 proxy_only)),
53 single_attempt_(NULL),
54 successful_connection_(previous_login_successful),
55 parent_(parent),
56 state_(STATE_OPENING),
57 redirect_time_ns_(0),
58 redirect_port_(0),
59 unexpected_disconnect_occurred_(false),
60 reset_unexpected_timer_(NULL),
61 google_host_(user_settings.host()),
62 google_user_(user_settings.user()),
63 disconnect_timer_(NULL) {
64 if (!network_status) {
65 network_status = NetworkStatusDetectorTask::Create(parent_);
66 if (network_status) {
67 // On linux we don't have an implementation of NetworkStatusDetectorTask.
68 network_status->Start();
69 }
70 }
71
72 if (network_status) {
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
90 // Defined so that the destructors are executed here (and the corresponding
91 // classes don't need to be included in 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 we may be trying the next dns entry).
170 //
171 // But we go to this state for other signals when there is no retry
172 // happening.
173 new_state = state_;
174 break;
175
176 case buzz::XmppEngine::STATE_START:
177 case buzz::XmppEngine::STATE_OPENING:
178 new_state = STATE_OPENING;
179 break;
180
181 case buzz::XmppEngine::STATE_OPEN:
182 new_state = STATE_OPENED;
183 break;
184
185 default:
186 ASSERT(false);
187 break;
188 }
189 HandleClientStateChange(new_state);
190 }
191
192 void Login::HandleClientStateChange(ConnectionState new_state) {
193 // Do we need to transition between the retrying and closed states?
194 if (auto_reconnect_.get() && auto_reconnect_->is_retrying()) {
195 if (new_state == STATE_CLOSED) {
196 new_state = STATE_RETRYING;
197 }
198 } else {
199 if (new_state == STATE_RETRYING) {
200 new_state = STATE_CLOSED;
201 }
202 }
203
204 if (new_state != state_) {
205 state_ = new_state;
206 if (reset_unexpected_timer_) {
207 reset_unexpected_timer_->Abort();
208 reset_unexpected_timer_ = NULL;
209 }
210
211 if (state_ == STATE_OPENED) {
212 successful_connection_ = true;
213
214 google_host_ = single_attempt_->xmpp_client()->jid().domain();
215 google_user_ = single_attempt_->xmpp_client()->jid().node();
216 proxy_info_ = single_attempt_->proxy();
217
218 reset_unexpected_timer_ = new Timer(parent_,
219 kResetReconnectInfoDelaySec,
220 false); // Repeat.
221 reset_unexpected_timer_->SignalTimeout.connect(
222 this,
223 &Login::ResetUnexpectedDisconnect);
224 }
225 SignalClientStateChange(state_);
226 }
227 }
228
229 void Login::OnAutoReconnectTimerChange() {
230 if (!single_attempt_ || !single_attempt_->xmpp_client()) {
231 HandleClientStateChange(STATE_CLOSED);
232 return;
233 }
234 OnClientStateChange(single_attempt_->xmpp_client()->GetState());
235 }
236
237 buzz::XmppClient* Login::xmpp_client() {
238 if (!single_attempt_) {
239 return NULL;
240 }
241 return single_attempt_->xmpp_client();
242 }
243
244 int Login::seconds_until_reconnect() const {
245 return auto_reconnect_->seconds_until();
246 }
247
248 void Login::UseNextConnection() {
249 if (!single_attempt_) {
250 // Just in case, there is an obscure case that causes this to get called
251 // when there is no single_attempt_.
252 return;
253 }
254 single_attempt_->UseNextConnection();
255 }
256
257 void Login::UseCurrentConnection() {
258 if (!single_attempt_) {
259 // Just in case, there is an obscure case that causes this to get called
260 // when there is no single_attempt_.
261 return;
262 }
263 single_attempt_->UseCurrentConnection();
264 }
265
266 void Login::OnRedirect(const std::string& redirect_server, int redirect_port) {
267 ASSERT(redirect_port_ != 0);
268
269 redirect_time_ns_ = GetCurrent100NSTime();
270 redirect_server_ = redirect_server;
271 redirect_port_ = redirect_port;
272
273 // Drop the current connection, and start the login process again.
274 StartConnection();
275 }
276
277 void Login::OnUnexpectedDisconnect() {
278 if (reset_unexpected_timer_) {
279 reset_unexpected_timer_->Abort();
280 reset_unexpected_timer_ = NULL;
281 }
282
283 // Start the login process again.
284 if (unexpected_disconnect_occurred_) {
285 // If we already have received an unexpected disconnect recently, then our
286 // account may have be jailed due to abuse, so we shouldn't make the
287 // situation worse by trying really hard to reconnect. Instead, we'll do
288 // the autoreconnect route, which has exponential back-off.
289 DoAutoReconnect();
290 return;
291 }
292 StartConnection();
293 unexpected_disconnect_occurred_ = true;
294 }
295
296 void Login::ResetUnexpectedDisconnect() {
297 reset_unexpected_timer_ = NULL;
298 unexpected_disconnect_occurred_ = false;
299 }
300
301 void Login::DoAutoReconnect() {
302 bool allow_auto_reconnect =
303 login_settings_->connection_options().auto_reconnect();
304 // Start the reconnect time before aborting the connection to ensure that
305 // AutoReconnect::is_retrying() is true, so that the Login doesn't
306 // transition to the CLOSED state (which would cause the reconnection timer
307 // to reset and not double).
308 if (allow_auto_reconnect) {
309 auto_reconnect_->StartReconnectTimer();
310 }
311
312 if (single_attempt_) {
313 single_attempt_->Abort();
314 single_attempt_ = NULL;
315 }
316
317 if (!allow_auto_reconnect) {
318 HandleClientStateChange(STATE_CLOSED);
319 return;
320 }
321 }
322
323 void Login::OnNetworkStateDetected(bool was_alive, bool is_alive) {
324 if (was_alive && !is_alive) {
325 // Our network connection just went down. Setup a timer to disconnect.
326 // Don't disconnect immediately to avoid constant
327 // connection/disconnection due to flaky network interfaces.
328 ASSERT(disconnect_timer_ == NULL);
329 disconnect_timer_ = new Timer(parent_, kDisconnectionDelaySecs, false);
330 disconnect_timer_->SignalTimeout.connect(this,
331 &Login::OnDisconnectTimeout);
332 } else if (!was_alive && is_alive) {
333 // Our connection has come back up. If we have a disconnect timer going,
334 // abort it so we don't disconnect.
335 if (disconnect_timer_) {
336 disconnect_timer_->Abort();
337 // It will free itself.
338 disconnect_timer_ = NULL;
339 }
340 }
341 }
342
343 void Login::OnDisconnectTimeout() {
344 disconnect_timer_ = NULL;
345
346 if (state_ != STATE_OPENED) {
347 return;
348 }
349
350 if (single_attempt_) {
351 single_attempt_->Abort();
352 single_attempt_ = NULL;
353 }
354
355 StartConnection();
356 }
357
358 } // namespace notifier
OLDNEW
« no previous file with comments | « chrome/browser/sync/notifier/communicator/login.h ('k') | chrome/browser/sync/notifier/communicator/login_failure.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698