summaryrefslogtreecommitdiff
path: root/chromium/jingle/notifier/communicator/login.cc
blob: 1a877e1cd49c482844a2873ea00d9ac5ecc16eab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "jingle/notifier/communicator/login.h"

#include <string>

#include "base/logging.h"
#include "base/rand_util.h"
#include "base/time/time.h"
#include "net/base/host_port_pair.h"
#include "talk/base/common.h"
#include "talk/base/firewallsocketserver.h"
#include "talk/base/logging.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/taskrunner.h"
#include "talk/xmllite/xmlelement.h"
#include "talk/xmpp/asyncsocket.h"
#include "talk/xmpp/prexmppauth.h"
#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
#include "talk/xmpp/xmppengine.h"

namespace notifier {

Login::Delegate::~Delegate() {}

Login::Login(Delegate* delegate,
             const buzz::XmppClientSettings& user_settings,
             const scoped_refptr<net::URLRequestContextGetter>&
                request_context_getter,
             const ServerList& servers,
             bool try_ssltcp_first,
             const std::string& auth_mechanism)
    : delegate_(delegate),
      login_settings_(user_settings,
                      request_context_getter,
                      servers,
                      try_ssltcp_first,
                      auth_mechanism) {
  net::NetworkChangeNotifier::AddIPAddressObserver(this);
  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
  // TODO(akalin): Add as DNSObserver once bug 130610 is fixed.
  ResetReconnectState();
}

Login::~Login() {
  net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
}

void Login::StartConnection() {
  DVLOG(1) << "Starting connection...";
  single_attempt_.reset(new SingleLoginAttempt(login_settings_, this));
}

void Login::UpdateXmppSettings(const buzz::XmppClientSettings& user_settings) {
  DVLOG(1) << "XMPP settings updated";
  login_settings_.set_user_settings(user_settings);
}

// In the code below, we assume that calling a delegate method may end
// up in ourselves being deleted, so we always call it last.
//
// TODO(akalin): Add unit tests to enforce the behavior above.

void Login::OnConnect(base::WeakPtr<buzz::XmppTaskParentInterface> base_task) {
  DVLOG(1) << "Connected";
  ResetReconnectState();
  delegate_->OnConnect(base_task);
}

void Login::OnRedirect(const ServerInformation& redirect_server) {
  DVLOG(1) << "Redirected";
  login_settings_.SetRedirectServer(redirect_server);
  // Drop the current connection, and start the login process again.
  StartConnection();
  delegate_->OnTransientDisconnection();
}

void Login::OnCredentialsRejected() {
  DVLOG(1) << "Credentials rejected";
  TryReconnect();
  delegate_->OnCredentialsRejected();
}

void Login::OnSettingsExhausted() {
  DVLOG(1) << "Settings exhausted";
  TryReconnect();
  delegate_->OnTransientDisconnection();
}

void Login::OnIPAddressChanged() {
  DVLOG(1) << "IP address changed";
  OnNetworkEvent();
}

void Login::OnConnectionTypeChanged(
    net::NetworkChangeNotifier::ConnectionType type) {
  DVLOG(1) << "Connection type changed";
  OnNetworkEvent();
}

void Login::OnDNSChanged() {
  DVLOG(1) << "DNS changed";
  OnNetworkEvent();
}

void Login::OnNetworkEvent() {
  // 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();
  delegate_->OnTransientDisconnection();
}

void Login::ResetReconnectState() {
  reconnect_interval_ =
      base::TimeDelta::FromSeconds(base::RandInt(5, 25));
  reconnect_timer_.Stop();
}

void Login::TryReconnect() {
  DCHECK_GT(reconnect_interval_.InSeconds(), 0);
  single_attempt_.reset();
  reconnect_timer_.Stop();
  DVLOG(1) << "Reconnecting in "
           << reconnect_interval_.InSeconds() << " seconds";
  reconnect_timer_.Start(
      FROM_HERE, reconnect_interval_, this, &Login::DoReconnect);
}

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;
  DVLOG(1) << "Reconnecting...";
  StartConnection();
}

}  // namespace notifier