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 "third_party/libjingle_xmpp/task_runner/taskrunner.h"
14 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
15 #include "third_party/libjingle_xmpp/xmpp/asyncsocket.h"
16 #include "third_party/libjingle_xmpp/xmpp/prexmppauth.h"
17 #include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
18 #include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
19 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
20 #include "third_party/webrtc/rtc_base/firewall_socket_server.h"
21 #include "third_party/webrtc/rtc_base/physical_socket_server.h"
22 #include "third_party/webrtc_overrides/rtc_base/logging.h"
23 
24 namespace notifier {
25 
~Delegate()26 Login::Delegate::~Delegate() {}
27 
Login(Delegate * delegate,const jingle_xmpp::XmppClientSettings & user_settings,jingle_glue::GetProxyResolvingSocketFactoryCallback get_socket_factory_callback,const ServerList & servers,bool try_ssltcp_first,const std::string & auth_mechanism,const net::NetworkTrafficAnnotationTag & traffic_annotation,network::NetworkConnectionTracker * network_connection_tracker)28 Login::Login(Delegate* delegate,
29              const jingle_xmpp::XmppClientSettings& user_settings,
30              jingle_glue::GetProxyResolvingSocketFactoryCallback
31                  get_socket_factory_callback,
32              const ServerList& servers,
33              bool try_ssltcp_first,
34              const std::string& auth_mechanism,
35              const net::NetworkTrafficAnnotationTag& traffic_annotation,
36              network::NetworkConnectionTracker* network_connection_tracker)
37     : delegate_(delegate),
38       login_settings_(user_settings,
39                       get_socket_factory_callback,
40                       servers,
41                       try_ssltcp_first,
42                       auth_mechanism,
43                       traffic_annotation),
44       network_connection_tracker_(network_connection_tracker) {
45   if (network_connection_tracker_)
46     network_connection_tracker_->AddNetworkConnectionObserver(this);
47   // TODO(akalin): Add as DNSObserver once bug 130610 is fixed.
48   ResetReconnectState();
49 }
50 
~Login()51 Login::~Login() {
52   if (network_connection_tracker_)
53     network_connection_tracker_->RemoveNetworkConnectionObserver(this);
54 }
55 
StartConnection()56 void Login::StartConnection() {
57   DVLOG(1) << "Starting connection...";
58   single_attempt_.reset(new SingleLoginAttempt(login_settings_, this));
59 }
60 
UpdateXmppSettings(const jingle_xmpp::XmppClientSettings & user_settings)61 void Login::UpdateXmppSettings(const jingle_xmpp::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 
OnConnect(base::WeakPtr<jingle_xmpp::XmppTaskParentInterface> base_task)71 void Login::OnConnect(base::WeakPtr<jingle_xmpp::XmppTaskParentInterface> base_task) {
72   DVLOG(1) << "Connected";
73   ResetReconnectState();
74   delegate_->OnConnect(base_task);
75 }
76 
OnRedirect(const ServerInformation & redirect_server)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 
OnCredentialsRejected()85 void Login::OnCredentialsRejected() {
86   DVLOG(1) << "Credentials rejected";
87   TryReconnect();
88   delegate_->OnCredentialsRejected();
89 }
90 
OnSettingsExhausted()91 void Login::OnSettingsExhausted() {
92   DVLOG(1) << "Settings exhausted";
93   TryReconnect();
94   delegate_->OnTransientDisconnection();
95 }
96 
OnConnectionChanged(network::mojom::ConnectionType type)97 void Login::OnConnectionChanged(network::mojom::ConnectionType type) {
98   if (type == network::mojom::ConnectionType::CONNECTION_NONE)
99     return;
100 
101   DVLOG(1) << "Network changed";
102   OnNetworkEvent();
103 }
104 
OnDNSChanged()105 void Login::OnDNSChanged() {
106   DVLOG(1) << "DNS changed";
107   OnNetworkEvent();
108 }
109 
OnNetworkEvent()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 
ResetReconnectState()118 void Login::ResetReconnectState() {
119   reconnect_interval_ =
120       base::TimeDelta::FromSeconds(base::RandInt(5, 25));
121   reconnect_timer_.Stop();
122 }
123 
TryReconnect()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 
DoReconnect()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