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.
5 #include "remoting/host/signaling_connector.h"
8 #include "base/callback.h"
9 #include "base/strings/string_util.h"
10 #include "google_apis/google_api_keys.h"
11 #include "net/url_request/url_fetcher.h"
12 #include "net/url_request/url_request_context_getter.h"
13 #include "remoting/base/logging.h"
14 #include "remoting/host/dns_blackhole_checker.h"
20 // The delay between reconnect attempts will increase exponentially up
21 // to the maximum specified here.
22 const int kMaxReconnectDelaySeconds
= 10 * 60;
26 SignalingConnector::SignalingConnector(
27 XmppSignalStrategy
* signal_strategy
,
28 scoped_ptr
<DnsBlackholeChecker
> dns_blackhole_checker
,
29 const base::Closure
& auth_failed_callback
)
30 : signal_strategy_(signal_strategy
),
31 auth_failed_callback_(auth_failed_callback
),
32 dns_blackhole_checker_(dns_blackhole_checker
.Pass()),
33 reconnect_attempts_(0) {
34 DCHECK(!auth_failed_callback_
.is_null());
35 DCHECK(dns_blackhole_checker_
.get());
36 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
37 net::NetworkChangeNotifier::AddIPAddressObserver(this);
38 signal_strategy_
->AddListener(this);
39 ScheduleTryReconnect();
42 SignalingConnector::~SignalingConnector() {
43 signal_strategy_
->RemoveListener(this);
44 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
45 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
48 void SignalingConnector::EnableOAuth(OAuthTokenGetter
* oauth_token_getter
) {
49 oauth_token_getter_
= oauth_token_getter
;
52 void SignalingConnector::OnSignalStrategyStateChange(
53 SignalStrategy::State state
) {
54 DCHECK(CalledOnValidThread());
56 if (state
== SignalStrategy::CONNECTED
) {
57 HOST_LOG
<< "Signaling connected.";
58 reconnect_attempts_
= 0;
59 } else if (state
== SignalStrategy::DISCONNECTED
) {
60 HOST_LOG
<< "Signaling disconnected.";
61 reconnect_attempts_
++;
63 // If authentication failed then we have an invalid OAuth token,
64 // inform the upper layer about it.
65 if (signal_strategy_
->GetError() == SignalStrategy::AUTHENTICATION_FAILED
) {
66 auth_failed_callback_
.Run();
68 ScheduleTryReconnect();
73 bool SignalingConnector::OnSignalStrategyIncomingStanza(
74 const buzz::XmlElement
* stanza
) {
78 void SignalingConnector::OnConnectionTypeChanged(
79 net::NetworkChangeNotifier::ConnectionType type
) {
80 DCHECK(CalledOnValidThread());
81 if (type
!= net::NetworkChangeNotifier::CONNECTION_NONE
&&
82 signal_strategy_
->GetState() == SignalStrategy::DISCONNECTED
) {
83 HOST_LOG
<< "Network state changed to online.";
84 ResetAndTryReconnect();
88 void SignalingConnector::OnIPAddressChanged() {
89 DCHECK(CalledOnValidThread());
90 if (signal_strategy_
->GetState() == SignalStrategy::DISCONNECTED
) {
91 HOST_LOG
<< "IP address has changed.";
92 ResetAndTryReconnect();
96 void SignalingConnector::OnAccessToken(OAuthTokenGetter::Status status
,
97 const std::string
& user_email
,
98 const std::string
& access_token
) {
99 DCHECK(CalledOnValidThread());
101 if (status
== OAuthTokenGetter::AUTH_ERROR
) {
102 auth_failed_callback_
.Run();
104 } else if (status
== OAuthTokenGetter::NETWORK_ERROR
) {
109 DCHECK_EQ(status
, OAuthTokenGetter::SUCCESS
);
110 HOST_LOG
<< "Received user info.";
112 signal_strategy_
->SetAuthInfo(user_email
, access_token
, "oauth2");
114 // Now that we've refreshed the token and verified that it's for the correct
115 // user account, try to connect using the new token.
116 DCHECK_EQ(signal_strategy_
->GetState(), SignalStrategy::DISCONNECTED
);
117 signal_strategy_
->Connect();
120 void SignalingConnector::OnNetworkError() {
121 DCHECK(CalledOnValidThread());
122 reconnect_attempts_
++;
123 ScheduleTryReconnect();
126 void SignalingConnector::ScheduleTryReconnect() {
127 DCHECK(CalledOnValidThread());
128 if (timer_
.IsRunning() || net::NetworkChangeNotifier::IsOffline())
130 int delay_s
= std::min(1 << reconnect_attempts_
,
131 kMaxReconnectDelaySeconds
);
132 timer_
.Start(FROM_HERE
, base::TimeDelta::FromSeconds(delay_s
),
133 this, &SignalingConnector::TryReconnect
);
136 void SignalingConnector::ResetAndTryReconnect() {
137 DCHECK(CalledOnValidThread());
138 signal_strategy_
->Disconnect();
139 reconnect_attempts_
= 0;
141 ScheduleTryReconnect();
144 void SignalingConnector::TryReconnect() {
145 DCHECK(CalledOnValidThread());
146 DCHECK(dns_blackhole_checker_
.get());
148 // This will check if this machine is allowed to access the chromoting
150 dns_blackhole_checker_
->CheckForDnsBlackhole(
151 base::Bind(&SignalingConnector::OnDnsBlackholeCheckerDone
,
152 base::Unretained(this)));
155 void SignalingConnector::OnDnsBlackholeCheckerDone(bool allow
) {
156 DCHECK(CalledOnValidThread());
158 // Unable to access the host talkgadget. Don't allow the connection, but
159 // schedule a reconnect in case this is a transient problem rather than
160 // an outright block.
162 reconnect_attempts_
++;
163 HOST_LOG
<< "Talkgadget check failed. Scheduling reconnect. Attempt "
164 << reconnect_attempts_
;
165 ScheduleTryReconnect();
169 if (signal_strategy_
->GetState() == SignalStrategy::DISCONNECTED
) {
170 HOST_LOG
<< "Attempting to connect signaling.";
171 oauth_token_getter_
->CallWithToken(
172 base::Bind(&SignalingConnector::OnAccessToken
, AsWeakPtr()));
176 } // namespace remoting