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