• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "remoting/host/signaling_connector.h"
6 
7 #include "base/bind.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"
15 
16 namespace remoting {
17 
18 namespace {
19 
20 // The delay between reconnect attempts will increase exponentially up
21 // to the maximum specified here.
22 const int kMaxReconnectDelaySeconds = 10 * 60;
23 
24 }  // namespace
25 
SignalingConnector(XmppSignalStrategy * signal_strategy,scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,const base::Closure & auth_failed_callback)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();
40 }
41 
~SignalingConnector()42 SignalingConnector::~SignalingConnector() {
43   signal_strategy_->RemoveListener(this);
44   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
45   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
46 }
47 
EnableOAuth(OAuthTokenGetter * oauth_token_getter)48 void SignalingConnector::EnableOAuth(OAuthTokenGetter* oauth_token_getter) {
49   oauth_token_getter_ = oauth_token_getter;
50 }
51 
OnSignalStrategyStateChange(SignalStrategy::State state)52 void SignalingConnector::OnSignalStrategyStateChange(
53     SignalStrategy::State state) {
54   DCHECK(CalledOnValidThread());
55 
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_++;
62 
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();
67     } else {
68       ScheduleTryReconnect();
69     }
70   }
71 }
72 
OnSignalStrategyIncomingStanza(const buzz::XmlElement * stanza)73 bool SignalingConnector::OnSignalStrategyIncomingStanza(
74     const buzz::XmlElement* stanza) {
75   return false;
76 }
77 
OnConnectionTypeChanged(net::NetworkChangeNotifier::ConnectionType type)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();
85   }
86 }
87 
OnIPAddressChanged()88 void SignalingConnector::OnIPAddressChanged() {
89   DCHECK(CalledOnValidThread());
90   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) {
91     HOST_LOG << "IP address has changed.";
92     ResetAndTryReconnect();
93   }
94 }
95 
OnAccessToken(OAuthTokenGetter::Status status,const std::string & user_email,const std::string & access_token)96 void SignalingConnector::OnAccessToken(OAuthTokenGetter::Status status,
97                                        const std::string& user_email,
98                                        const std::string& access_token) {
99   DCHECK(CalledOnValidThread());
100 
101   if (status == OAuthTokenGetter::AUTH_ERROR) {
102     auth_failed_callback_.Run();
103     return;
104   } else if (status == OAuthTokenGetter::NETWORK_ERROR) {
105     OnNetworkError();
106     return;
107   }
108 
109   DCHECK_EQ(status, OAuthTokenGetter::SUCCESS);
110   HOST_LOG << "Received user info.";
111 
112   signal_strategy_->SetAuthInfo(user_email, access_token, "oauth2");
113 
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();
118 }
119 
OnNetworkError()120 void SignalingConnector::OnNetworkError() {
121   DCHECK(CalledOnValidThread());
122   reconnect_attempts_++;
123   ScheduleTryReconnect();
124 }
125 
ScheduleTryReconnect()126 void SignalingConnector::ScheduleTryReconnect() {
127   DCHECK(CalledOnValidThread());
128   if (timer_.IsRunning() || net::NetworkChangeNotifier::IsOffline())
129     return;
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);
134 }
135 
ResetAndTryReconnect()136 void SignalingConnector::ResetAndTryReconnect() {
137   DCHECK(CalledOnValidThread());
138   signal_strategy_->Disconnect();
139   reconnect_attempts_ = 0;
140   timer_.Stop();
141   ScheduleTryReconnect();
142 }
143 
TryReconnect()144 void SignalingConnector::TryReconnect() {
145   DCHECK(CalledOnValidThread());
146   DCHECK(dns_blackhole_checker_.get());
147 
148   // This will check if this machine is allowed to access the chromoting
149   // host talkgadget.
150   dns_blackhole_checker_->CheckForDnsBlackhole(
151       base::Bind(&SignalingConnector::OnDnsBlackholeCheckerDone,
152                  base::Unretained(this)));
153 }
154 
OnDnsBlackholeCheckerDone(bool allow)155 void SignalingConnector::OnDnsBlackholeCheckerDone(bool allow) {
156   DCHECK(CalledOnValidThread());
157 
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.
161   if (!allow) {
162     reconnect_attempts_++;
163     HOST_LOG << "Talkgadget check failed. Scheduling reconnect. Attempt "
164               << reconnect_attempts_;
165     ScheduleTryReconnect();
166     return;
167   }
168 
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()));
173   }
174 }
175 
176 }  // namespace remoting
177