1 // Copyright 2019 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 "remoting/host/ftl_signaling_connector.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/strings/string_util.h"
12 #include "google_apis/google_api_keys.h"
13 #include "net/url_request/url_fetcher.h"
14 #include "net/url_request/url_request_context_getter.h"
15 #include "remoting/base/logging.h"
16 #include "remoting/signaling/signaling_address.h"
17 
18 namespace remoting {
19 
20 namespace {
21 
22 constexpr base::TimeDelta kBackoffResetDelay = base::TimeDelta::FromSeconds(30);
23 constexpr base::TimeDelta kNetworkChangeDelay = base::TimeDelta::FromSeconds(5);
24 
25 const net::BackoffEntry::Policy kBackoffPolicy = {
26     // Number of initial errors (in sequence) to ignore before applying
27     // exponential back-off rules.
28     0,
29 
30     // Initial delay for exponential back-off in ms. (1s)
31     1000,
32 
33     // Factor by which the waiting time will be multiplied.
34     2,
35 
36     // Fuzzing percentage. ex: 10% will spread requests randomly
37     // between 90%-100% of the calculated time.
38     0.5,
39 
40     // Maximum amount of time we are willing to delay our request in ms. (1m)
41     60000,
42 
43     // Time to keep an entry from being discarded even when it
44     // has no significant state, -1 to never discard.
45     -1,
46 
47     // Starts with initial delay.
48     false,
49 };
50 
SignalStrategyErrorToString(SignalStrategy::Error error)51 const char* SignalStrategyErrorToString(SignalStrategy::Error error) {
52   switch (error) {
53     case SignalStrategy::OK:
54       return "OK";
55     case SignalStrategy::AUTHENTICATION_FAILED:
56       return "AUTHENTICATION_FAILED";
57     case SignalStrategy::NETWORK_ERROR:
58       return "NETWORK_ERROR";
59     case SignalStrategy::PROTOCOL_ERROR:
60       return "PROTOCOL_ERROR";
61   }
62   return "";
63 }
64 
65 }  // namespace
66 
FtlSignalingConnector(SignalStrategy * signal_strategy,base::OnceClosure auth_failed_callback)67 FtlSignalingConnector::FtlSignalingConnector(
68     SignalStrategy* signal_strategy,
69     base::OnceClosure auth_failed_callback)
70     : signal_strategy_(signal_strategy),
71       auth_failed_callback_(std::move(auth_failed_callback)),
72       backoff_(&kBackoffPolicy) {
73   DCHECK(signal_strategy_);
74   DCHECK(auth_failed_callback_);
75   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
76   signal_strategy_->AddListener(this);
77 }
78 
~FtlSignalingConnector()79 FtlSignalingConnector::~FtlSignalingConnector() {
80   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
81   signal_strategy_->RemoveListener(this);
82   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
83 }
84 
Start()85 void FtlSignalingConnector::Start() {
86   TryReconnect(base::TimeDelta());
87 }
88 
OnSignalStrategyStateChange(SignalStrategy::State state)89 void FtlSignalingConnector::OnSignalStrategyStateChange(
90     SignalStrategy::State state) {
91   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
92 
93   if (state == SignalStrategy::CONNECTED) {
94     HOST_LOG << "Signaling connected. New JID: "
95              << signal_strategy_->GetLocalAddress().id();
96     backoff_reset_timer_.Start(FROM_HERE, kBackoffResetDelay, &backoff_,
97                                &net::BackoffEntry::Reset);
98   } else if (state == SignalStrategy::DISCONNECTED) {
99     HOST_LOG << "Signaling disconnected. error="
100              << SignalStrategyErrorToString(signal_strategy_->GetError());
101     backoff_reset_timer_.AbandonAndStop();
102     backoff_.InformOfRequest(false);
103     if (signal_strategy_->IsSignInError() &&
104         signal_strategy_->GetError() == SignalStrategy::AUTHENTICATION_FAILED) {
105       if (auth_failed_callback_) {
106         std::move(auth_failed_callback_).Run();
107       }
108       return;
109     }
110     TryReconnect(backoff_.GetTimeUntilRelease());
111   }
112 }
113 
OnSignalStrategyIncomingStanza(const jingle_xmpp::XmlElement * stanza)114 bool FtlSignalingConnector::OnSignalStrategyIncomingStanza(
115     const jingle_xmpp::XmlElement* stanza) {
116   return false;
117 }
118 
OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type)119 void FtlSignalingConnector::OnNetworkChanged(
120     net::NetworkChangeNotifier::ConnectionType type) {
121   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
122   if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
123       signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) {
124     HOST_LOG << "Network state changed to online.";
125     TryReconnect(kNetworkChangeDelay);
126   }
127 }
128 
TryReconnect(base::TimeDelta delay)129 void FtlSignalingConnector::TryReconnect(base::TimeDelta delay) {
130   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
131   timer_.Start(FROM_HERE, delay, this, &FtlSignalingConnector::DoReconnect);
132 }
133 
DoReconnect()134 void FtlSignalingConnector::DoReconnect() {
135   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
136   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) {
137     HOST_LOG << "Attempting to reconnect signaling.";
138     signal_strategy_->Connect();
139   }
140 }
141 
142 }  // namespace remoting
143