Home | History | Annotate | Download | only in communicator
      1 // Copyright (c) 2012 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 "jingle/notifier/communicator/login.h"
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/rand_util.h"
     11 #include "base/time/time.h"
     12 #include "net/base/host_port_pair.h"
     13 #include "talk/base/common.h"
     14 #include "talk/base/firewallsocketserver.h"
     15 #include "talk/base/logging.h"
     16 #include "talk/base/physicalsocketserver.h"
     17 #include "talk/base/taskrunner.h"
     18 #include "talk/xmllite/xmlelement.h"
     19 #include "talk/xmpp/asyncsocket.h"
     20 #include "talk/xmpp/prexmppauth.h"
     21 #include "talk/xmpp/xmppclient.h"
     22 #include "talk/xmpp/xmppclientsettings.h"
     23 #include "talk/xmpp/xmppengine.h"
     24 
     25 namespace notifier {
     26 
     27 // Redirect valid for 5 minutes.
     28 static const int kRedirectTimeoutMinutes = 5;
     29 
     30 Login::Delegate::~Delegate() {}
     31 
     32 Login::Login(Delegate* delegate,
     33              const buzz::XmppClientSettings& user_settings,
     34              const scoped_refptr<net::URLRequestContextGetter>&
     35                 request_context_getter,
     36              const ServerList& servers,
     37              bool try_ssltcp_first,
     38              const std::string& auth_mechanism)
     39     : delegate_(delegate),
     40       login_settings_(user_settings,
     41                       request_context_getter,
     42                       servers,
     43                       try_ssltcp_first,
     44                       auth_mechanism) {
     45   net::NetworkChangeNotifier::AddIPAddressObserver(this);
     46   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
     47   // TODO(akalin): Add as DNSObserver once bug 130610 is fixed.
     48   ResetReconnectState();
     49 }
     50 
     51 Login::~Login() {
     52   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
     53   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
     54 }
     55 
     56 void Login::StartConnection() {
     57   DVLOG(1) << "Starting connection...";
     58   single_attempt_.reset(new SingleLoginAttempt(login_settings_, this));
     59 }
     60 
     61 void Login::UpdateXmppSettings(const buzz::XmppClientSettings& user_settings) {
     62   DVLOG(1) << "XMPP settings updated";
     63   login_settings_.set_user_settings(user_settings);
     64 }
     65 
     66 // In the code below, we assume that calling a delegate method may end
     67 // up in ourselves being deleted, so we always call it last.
     68 //
     69 // TODO(akalin): Add unit tests to enforce the behavior above.
     70 
     71 void Login::OnConnect(base::WeakPtr<buzz::XmppTaskParentInterface> base_task) {
     72   DVLOG(1) << "Connected";
     73   ResetReconnectState();
     74   delegate_->OnConnect(base_task);
     75 }
     76 
     77 void Login::OnRedirect(const ServerInformation& redirect_server) {
     78   DVLOG(1) << "Redirected";
     79   login_settings_.SetRedirectServer(redirect_server);
     80   // Drop the current connection, and start the login process again.
     81   StartConnection();
     82   delegate_->OnTransientDisconnection();
     83 }
     84 
     85 void Login::OnCredentialsRejected() {
     86   DVLOG(1) << "Credentials rejected";
     87   TryReconnect();
     88   delegate_->OnCredentialsRejected();
     89 }
     90 
     91 void Login::OnSettingsExhausted() {
     92   DVLOG(1) << "Settings exhausted";
     93   TryReconnect();
     94   delegate_->OnTransientDisconnection();
     95 }
     96 
     97 void Login::OnIPAddressChanged() {
     98   DVLOG(1) << "IP address changed";
     99   OnNetworkEvent();
    100 }
    101 
    102 void Login::OnConnectionTypeChanged(
    103     net::NetworkChangeNotifier::ConnectionType type) {
    104   DVLOG(1) << "Connection type changed";
    105   OnNetworkEvent();
    106 }
    107 
    108 void Login::OnDNSChanged() {
    109   DVLOG(1) << "DNS changed";
    110   OnNetworkEvent();
    111 }
    112 
    113 void Login::OnNetworkEvent() {
    114   // Reconnect in 1 to 9 seconds (vary the time a little to try to
    115   // avoid spikey behavior on network hiccups).
    116   reconnect_interval_ = base::TimeDelta::FromSeconds(base::RandInt(1, 9));
    117   TryReconnect();
    118   delegate_->OnTransientDisconnection();
    119 }
    120 
    121 void Login::ResetReconnectState() {
    122   reconnect_interval_ =
    123       base::TimeDelta::FromSeconds(base::RandInt(5, 25));
    124   reconnect_timer_.Stop();
    125 }
    126 
    127 void Login::TryReconnect() {
    128   DCHECK_GT(reconnect_interval_.InSeconds(), 0);
    129   single_attempt_.reset();
    130   reconnect_timer_.Stop();
    131   DVLOG(1) << "Reconnecting in "
    132            << reconnect_interval_.InSeconds() << " seconds";
    133   reconnect_timer_.Start(
    134       FROM_HERE, reconnect_interval_, this, &Login::DoReconnect);
    135 }
    136 
    137 void Login::DoReconnect() {
    138   // Double reconnect time up to 30 minutes.
    139   const base::TimeDelta kMaxReconnectInterval =
    140       base::TimeDelta::FromMinutes(30);
    141   reconnect_interval_ *= 2;
    142   if (reconnect_interval_ > kMaxReconnectInterval)
    143     reconnect_interval_ = kMaxReconnectInterval;
    144   DVLOG(1) << "Reconnecting...";
    145   StartConnection();
    146 }
    147 
    148 }  // namespace notifier
    149