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

Unified Diff: jingle/notifier/communicator/login.cc

Issue 2809056: Rewrote handing of auto-reconnection and network changes for sync notifier. (Closed)
Patch Set: Fixed bug Created 10 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « jingle/notifier/communicator/login.h ('k') | jingle/notifier/communicator/login_connection_state.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: jingle/notifier/communicator/login.cc
diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc
index 7cf4952e092ddef459993932ec0872be6297172b..7d3c4c89819db96fb92331172f587b99e04e7213 100644
--- a/jingle/notifier/communicator/login.cc
+++ b/jingle/notifier/communicator/login.cc
@@ -7,8 +7,8 @@
#include "jingle/notifier/communicator/login.h"
#include "base/logging.h"
+#include "base/rand_util.h"
#include "base/time.h"
-#include "jingle/notifier/communicator/auto_reconnect.h"
#include "jingle/notifier/communicator/connection_options.h"
#include "jingle/notifier/communicator/login_settings.h"
#include "jingle/notifier/communicator/product_info.h"
@@ -31,9 +31,6 @@ namespace notifier {
// Redirect valid for 5 minutes.
static const int kRedirectTimeoutMinutes = 5;
-// Disconnect if network stays down for more than 10 seconds.
-static const int kDisconnectionDelaySecs = 10;
-
Login::Login(talk_base::TaskParent* parent,
bool use_chrome_async_socket,
const buzz::XmppClientSettings& user_settings,
@@ -43,8 +40,7 @@ Login::Login(talk_base::TaskParent* parent,
ServerInformation* server_list,
int server_count,
talk_base::FirewallManager* firewall,
- bool proxy_only,
- bool previous_login_successful)
+ bool proxy_only)
: parent_(parent),
use_chrome_async_socket_(use_chrome_async_socket),
login_settings_(new LoginSettings(user_settings,
@@ -55,38 +51,15 @@ Login::Login(talk_base::TaskParent* parent,
server_count,
firewall,
proxy_only)),
+ state_(STATE_DISCONNECTED),
single_attempt_(NULL),
- successful_connection_(previous_login_successful),
- state_(STATE_OPENING),
- redirect_port_(0),
- unexpected_disconnect_occurred_(false),
- google_host_(user_settings.host()),
- google_user_(user_settings.user()) {
- // Hook up all the signals and observers.
+ redirect_port_(0) {
net::NetworkChangeNotifier::AddObserver(this);
- auto_reconnect_.SignalStartConnection.connect(this,
- &Login::StartConnection);
- auto_reconnect_.SignalTimerStartStop.connect(
- this,
- &Login::OnAutoReconnectTimerChange);
- SignalClientStateChange.connect(&auto_reconnect_,
- &AutoReconnect::OnClientStateChange);
- SignalIdleChange.connect(&auto_reconnect_,
- &AutoReconnect::set_idle);
- SignalPowerSuspended.connect(&auto_reconnect_,
- &AutoReconnect::OnPowerSuspend);
-
- // Then check the initial state of the connection.
- CheckConnection();
+ ResetReconnectState();
}
-// Defined so that the destructors are executed here (and the corresponding
-// classes don't need to be included in the header file).
Login::~Login() {
- if (single_attempt_) {
- single_attempt_->Abort();
- single_attempt_ = NULL;
- }
+ Disconnect();
net::NetworkChangeNotifier::RemoveObserver(this);
}
@@ -103,126 +76,68 @@ void Login::StartConnection() {
login_settings_->clear_server_override();
}
- if (single_attempt_) {
- single_attempt_->Abort();
- single_attempt_ = NULL;
- }
+ Disconnect();
+
+ LOG(INFO) << "Starting connection...";
+
single_attempt_ = new SingleLoginAttempt(parent_,
login_settings_.get(),
use_chrome_async_socket_,
- successful_connection_);
+ true);
// Do the signaling hook-ups.
- single_attempt_->SignalLoginFailure.connect(this, &Login::OnLoginFailure);
- single_attempt_->SignalRedirect.connect(this, &Login::OnRedirect);
- single_attempt_->SignalClientStateChange.connect(
- this,
- &Login::OnClientStateChange);
single_attempt_->SignalUnexpectedDisconnect.connect(
this,
- &Login::OnUnexpectedDisconnect);
+ &Login::TryReconnect);
+ single_attempt_->SignalNeedAutoReconnect.connect(
+ this,
+ &Login::TryReconnect);
+ single_attempt_->SignalLoginFailure.connect(this, &Login::OnLoginFailure);
single_attempt_->SignalLogoff.connect(
this,
- &Login::OnLogoff);
- single_attempt_->SignalNeedAutoReconnect.connect(
+ &Login::Disconnect);
+ single_attempt_->SignalRedirect.connect(this, &Login::OnRedirect);
+ single_attempt_->SignalClientStateChange.connect(
this,
- &Login::DoAutoReconnect);
+ &Login::OnClientStateChange);
SignalLogInput.repeat(single_attempt_->SignalLogInput);
SignalLogOutput.repeat(single_attempt_->SignalLogOutput);
single_attempt_->Start();
}
-const std::string& Login::google_host() const {
- return google_host_;
-}
-
-const std::string& Login::google_user() const {
- return google_user_;
-}
-
-const talk_base::ProxyInfo& Login::proxy() const {
- return proxy_info_;
-}
-
void Login::OnLoginFailure(const LoginFailure& failure) {
- auto_reconnect_.StopReconnectTimer();
- HandleClientStateChange(STATE_CLOSED);
SignalLoginFailure(failure);
+ TryReconnect();
}
-void Login::OnLogoff() {
- HandleClientStateChange(STATE_CLOSED);
-}
-
-void Login::OnClientStateChange(buzz::XmppEngine::State state) {
- LoginConnectionState new_state = STATE_CLOSED;
-
- switch (state) {
- case buzz::XmppEngine::STATE_NONE:
- case buzz::XmppEngine::STATE_CLOSED:
- // Ignore the closed state (because we may be trying the next dns entry).
- //
- // But we go to this state for other signals when there is no retry
- // happening.
- new_state = state_;
- break;
-
- case buzz::XmppEngine::STATE_START:
- case buzz::XmppEngine::STATE_OPENING:
- new_state = STATE_OPENING;
- break;
+void Login::OnRedirect(const std::string& redirect_server, int redirect_port) {
+ DCHECK_NE(redirect_port_, 0);
- case buzz::XmppEngine::STATE_OPEN:
- new_state = STATE_OPENED;
- break;
+ redirect_time_ = base::Time::Now();
+ redirect_server_ = redirect_server;
+ redirect_port_ = redirect_port;
- default:
- DCHECK(false);
- break;
- }
- HandleClientStateChange(new_state);
+ // Drop the current connection, and start the login process again.
+ StartConnection();
}
-void Login::HandleClientStateChange(LoginConnectionState new_state) {
- // Do we need to transition between the retrying and closed states?
- if (auto_reconnect_.is_retrying()) {
- if (new_state == STATE_CLOSED) {
- new_state = STATE_RETRYING;
- }
- } else {
- if (new_state == STATE_RETRYING) {
- new_state = STATE_CLOSED;
- }
+void Login::OnClientStateChange(buzz::XmppEngine::State state) {
+ // We only care about when we're connected.
+ if (state == buzz::XmppEngine::STATE_OPEN) {
+ ResetReconnectState();
+ ChangeState(STATE_CONNECTED);
}
+}
- if (new_state != state_) {
+void Login::ChangeState(LoginConnectionState new_state) {
+ if (state_ != new_state) {
state_ = new_state;
- reset_unexpected_timer_.Stop();
-
- if (state_ == STATE_OPENED) {
- successful_connection_ = true;
-
- google_host_ = single_attempt_->xmpp_client()->jid().domain();
- google_user_ = single_attempt_->xmpp_client()->jid().node();
- proxy_info_ = single_attempt_->proxy();
-
- reset_unexpected_timer_.Start(
- base::TimeDelta::FromSeconds(kResetReconnectInfoDelaySec),
- this, &Login::ResetUnexpectedDisconnect);
- }
+ LOG(INFO) << "Signalling new state " << state_;
SignalClientStateChange(state_);
}
}
-void Login::OnAutoReconnectTimerChange() {
- if (!single_attempt_ || !single_attempt_->xmpp_client()) {
- HandleClientStateChange(STATE_CLOSED);
- return;
- }
- OnClientStateChange(single_attempt_->xmpp_client()->GetState());
-}
-
buzz::XmppClient* Login::xmpp_client() {
if (!single_attempt_) {
return NULL;
@@ -230,122 +145,48 @@ buzz::XmppClient* Login::xmpp_client() {
return single_attempt_->xmpp_client();
}
-void Login::UseNextConnection() {
- if (!single_attempt_) {
- // Just in case, there is an obscure case that causes this to get called
- // when there is no single_attempt_.
- return;
- }
- single_attempt_->UseNextConnection();
-}
-
-void Login::UseCurrentConnection() {
- if (!single_attempt_) {
- // Just in case, there is an obscure case that causes this to get called
- // when there is no single_attempt_.
- return;
- }
- single_attempt_->UseCurrentConnection();
-}
-
-void Login::OnRedirect(const std::string& redirect_server, int redirect_port) {
- DCHECK_NE(redirect_port_, 0);
-
- redirect_time_ = base::Time::Now();
- redirect_server_ = redirect_server;
- redirect_port_ = redirect_port;
-
- // Drop the current connection, and start the login process again.
- StartConnection();
-}
-
-void Login::OnUnexpectedDisconnect() {
- reset_unexpected_timer_.Stop();
-
- // Start the login process again.
- if (unexpected_disconnect_occurred_) {
- // If we already have received an unexpected disconnect recently, then our
- // account may have be jailed due to abuse, so we shouldn't make the
- // situation worse by trying really hard to reconnect. Instead, we'll do
- // the autoreconnect route, which has exponential back-off.
- DoAutoReconnect();
- return;
- }
- StartConnection();
- unexpected_disconnect_occurred_ = true;
-}
-
-void Login::ResetUnexpectedDisconnect() {
- unexpected_disconnect_occurred_ = false;
+void Login::OnIPAddressChanged() {
+ LOG(INFO) << "Detected IP address change";
+ // Reconnect in 1 to 9 seconds (vary the time a little to try to
+ // avoid spikey behavior on network hiccups).
+ reconnect_interval_ = base::TimeDelta::FromSeconds(base::RandInt(1, 9));
+ TryReconnect();
}
-void Login::DoAutoReconnect() {
- bool allow_auto_reconnect =
- login_settings_->connection_options().auto_reconnect();
- // Start the reconnect time before aborting the connection to ensure that
- // AutoReconnect::is_retrying() is true, so that the Login doesn't
- // transition to the CLOSED state (which would cause the reconnection timer
- // to reset and not double).
- if (allow_auto_reconnect) {
- auto_reconnect_.StartReconnectTimer();
- }
-
+void Login::Disconnect() {
if (single_attempt_) {
+ LOG(INFO) << "Disconnecting";
single_attempt_->Abort();
single_attempt_ = NULL;
}
-
- if (!allow_auto_reconnect) {
- HandleClientStateChange(STATE_CLOSED);
- return;
- }
+ ChangeState(STATE_DISCONNECTED);
}
-void Login::OnIPAddressChanged() {
- LOG(INFO) << "IP address change detected";
- CheckConnection();
+void Login::ResetReconnectState() {
+ reconnect_interval_ =
+ base::TimeDelta::FromSeconds(base::RandInt(5, 25));
+ reconnect_timer_.Stop();
}
-void Login::CheckConnection() {
- // We don't check the connection if we're using ChromeAsyncSocket,
- // as this code requires a libjingle thread to be running. This
- // code will go away in a future cleanup CL, anyway.
- if (!use_chrome_async_socket_) {
- LOG(INFO) << "Checking connection";
- talk_base::PhysicalSocketServer physical;
- scoped_ptr<talk_base::Socket> socket(physical.CreateSocket(SOCK_STREAM));
- bool alive =
- !socket->Connect(talk_base::SocketAddress("talk.google.com", 5222));
- LOG(INFO) << "Network is " << (alive ? "alive" : "not alive");
- if (alive) {
- // Our connection is up. If we have a disconnect timer going,
- // stop it so we don't disconnect.
- disconnect_timer_.Stop();
- } else {
- // Our network connection is down. Start the disconnect timer if
- // it's not already going. Don't disconnect immediately to avoid
- // constant connection/disconnection due to flaky network
- // interfaces.
- if (!disconnect_timer_.IsRunning()) {
- disconnect_timer_.Start(
- base::TimeDelta::FromSeconds(kDisconnectionDelaySecs),
- this, &Login::OnDisconnectTimeout);
- }
- }
- auto_reconnect_.NetworkStateChanged(alive);
- }
+void Login::TryReconnect() {
+ DCHECK_GT(reconnect_interval_.InSeconds(), 0);
+ Disconnect();
+ reconnect_timer_.Stop();
+ LOG(INFO) << "Reconnecting in "
+ << reconnect_interval_.InSeconds() << " seconds";
+ reconnect_timer_.Start(
+ reconnect_interval_, this, &Login::DoReconnect);
}
-void Login::OnDisconnectTimeout() {
- if (state_ != STATE_OPENED) {
- return;
+void Login::DoReconnect() {
+ // Double reconnect time up to 30 minutes.
+ const base::TimeDelta kMaxReconnectInterval =
+ base::TimeDelta::FromMinutes(30);
+ reconnect_interval_ *= 2;
+ if (reconnect_interval_ > kMaxReconnectInterval) {
+ reconnect_interval_ = kMaxReconnectInterval;
}
-
- if (single_attempt_) {
- single_attempt_->Abort();
- single_attempt_ = NULL;
- }
-
+ LOG(INFO) << "Reconnecting...";
StartConnection();
}
« no previous file with comments | « jingle/notifier/communicator/login.h ('k') | jingle/notifier/communicator/login_connection_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698