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