Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/signaling_connector.h" | 5 #include "remoting/host/signaling_connector.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "net/url_request/url_fetcher.h" | |
| 9 #include "remoting/host/chromoting_host_context.h" | 10 #include "remoting/host/chromoting_host_context.h" |
| 11 #include "remoting/host/constants.h" | |
| 12 #include "remoting/host/dns_blackhole_checker.h" | |
| 10 #include "remoting/host/url_request_context.h" | 13 #include "remoting/host/url_request_context.h" |
| 11 | 14 |
| 12 namespace remoting { | 15 namespace remoting { |
| 13 | 16 |
| 14 namespace { | 17 namespace { |
| 15 | 18 |
| 16 // The delay between reconnect attempts will increase exponentially up | 19 // The delay between reconnect attempts will increase exponentially up |
| 17 // to the maximum specified here. | 20 // to the maximum specified here. |
| 18 const int kMaxReconnectDelaySeconds = 10 * 60; | 21 const int kMaxReconnectDelaySeconds = 10 * 60; |
| 19 | 22 |
| 20 // Time when we we try to update OAuth token before its expiration. | 23 // Time when we we try to update OAuth token before its expiration. |
| 21 const int kTokenUpdateTimeBeforeExpirySeconds = 60; | 24 const int kTokenUpdateTimeBeforeExpirySeconds = 60; |
| 22 | 25 |
| 23 } // namespace | 26 } // namespace |
| 24 | 27 |
| 25 SignalingConnector::OAuthCredentials::OAuthCredentials( | 28 SignalingConnector::OAuthCredentials::OAuthCredentials( |
| 26 const std::string& login_value, | 29 const std::string& login_value, |
| 27 const std::string& refresh_token_value, | 30 const std::string& refresh_token_value, |
| 28 const OAuthClientInfo& client_info_value) | 31 const OAuthClientInfo& client_info_value) |
| 29 : login(login_value), | 32 : login(login_value), |
| 30 refresh_token(refresh_token_value), | 33 refresh_token(refresh_token_value), |
| 31 client_info(client_info_value) { | 34 client_info(client_info_value) { |
| 32 } | 35 } |
| 33 | 36 |
| 34 SignalingConnector::SignalingConnector( | 37 SignalingConnector::SignalingConnector( |
| 35 XmppSignalStrategy* signal_strategy, | 38 XmppSignalStrategy* signal_strategy, |
| 39 ChromotingHostContext* context, | |
| 40 DnsBlackholeChecker* dns_blackhole_checker, | |
| 36 const base::Closure& auth_failed_callback) | 41 const base::Closure& auth_failed_callback) |
| 37 : signal_strategy_(signal_strategy), | 42 : signal_strategy_(signal_strategy), |
| 43 context_(context), | |
| 38 auth_failed_callback_(auth_failed_callback), | 44 auth_failed_callback_(auth_failed_callback), |
| 45 dns_blackhole_checker_(dns_blackhole_checker), | |
| 39 reconnect_attempts_(0), | 46 reconnect_attempts_(0), |
| 40 refreshing_oauth_token_(false) { | 47 refreshing_oauth_token_(false) { |
| 41 DCHECK(!auth_failed_callback_.is_null()); | 48 DCHECK(!auth_failed_callback_.is_null()); |
| 42 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 49 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 43 net::NetworkChangeNotifier::AddIPAddressObserver(this); | 50 net::NetworkChangeNotifier::AddIPAddressObserver(this); |
| 44 signal_strategy_->AddListener(this); | 51 signal_strategy_->AddListener(this); |
| 45 ScheduleTryReconnect(); | 52 ScheduleTryReconnect(); |
| 46 } | 53 } |
| 47 | 54 |
| 48 SignalingConnector::~SignalingConnector() { | 55 SignalingConnector::~SignalingConnector() { |
| 49 signal_strategy_->RemoveListener(this); | 56 signal_strategy_->RemoveListener(this); |
| 50 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 57 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 51 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 58 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 52 } | 59 } |
| 53 | 60 |
| 54 void SignalingConnector::EnableOAuth( | 61 void SignalingConnector::EnableOAuth( |
| 55 scoped_ptr<OAuthCredentials> oauth_credentials, | 62 scoped_ptr<OAuthCredentials> oauth_credentials) { |
| 56 net::URLRequestContextGetter* url_context) { | |
| 57 oauth_credentials_ = oauth_credentials.Pass(); | 63 oauth_credentials_ = oauth_credentials.Pass(); |
| 58 gaia_oauth_client_.reset(new GaiaOAuthClient( | 64 gaia_oauth_client_.reset(new GaiaOAuthClient( |
| 59 OAuthProviderInfo::GetDefault(), url_context)); | 65 OAuthProviderInfo::GetDefault(), context_->url_request_context_getter())); |
| 60 } | 66 } |
| 61 | 67 |
| 62 void SignalingConnector::OnSignalStrategyStateChange( | 68 void SignalingConnector::OnSignalStrategyStateChange( |
| 63 SignalStrategy::State state) { | 69 SignalStrategy::State state) { |
| 64 DCHECK(CalledOnValidThread()); | 70 DCHECK(CalledOnValidThread()); |
| 65 | 71 |
| 66 if (state == SignalStrategy::CONNECTED) { | 72 if (state == SignalStrategy::CONNECTED) { |
| 67 LOG(INFO) << "Signaling connected."; | 73 LOG(INFO) << "Signaling connected."; |
| 68 reconnect_attempts_ = 0; | 74 reconnect_attempts_ = 0; |
| 69 } else if (state == SignalStrategy::DISCONNECTED) { | 75 } else if (state == SignalStrategy::DISCONNECTED) { |
| 70 LOG(INFO) << "Signaling disconnected."; | 76 LOG(INFO) << "Signaling disconnected."; |
| 71 reconnect_attempts_++; | 77 reconnect_attempts_++; |
| 72 | 78 |
| 73 // If authentication failed then we have an invalid OAuth token, | 79 // If authentication failed then we have an invalid OAuth token, |
| 74 // inform the upper layer about it. | 80 // inform the upper layer about it. |
| 75 if (signal_strategy_->GetError() == SignalStrategy::AUTHENTICATION_FAILED) { | 81 if (signal_strategy_->GetError() == SignalStrategy::AUTHENTICATION_FAILED) { |
| 76 auth_failed_callback_.Run(); | 82 auth_failed_callback_.Run(); |
| 77 } else { | 83 } else { |
| 78 ScheduleTryReconnect(); | 84 ScheduleTryReconnect(); |
| 79 } | 85 } |
| 80 } | 86 } |
| 81 } | 87 } |
| 82 | 88 |
| 83 bool SignalingConnector::OnSignalStrategyIncomingStanza( | 89 bool SignalingConnector::OnSignalStrategyIncomingStanza( |
| 84 const buzz::XmlElement* stanza) { | 90 const buzz::XmlElement* stanza) { |
| 85 return false; | 91 return false; |
| 86 } | 92 } |
| 87 | 93 |
| 88 void SignalingConnector::OnIPAddressChanged() { | |
| 89 DCHECK(CalledOnValidThread()); | |
| 90 LOG(INFO) << "IP address has changed."; | |
| 91 ResetAndTryReconnect(); | |
| 92 } | |
| 93 | |
| 94 void SignalingConnector::OnConnectionTypeChanged( | 94 void SignalingConnector::OnConnectionTypeChanged( |
| 95 net::NetworkChangeNotifier::ConnectionType type) { | 95 net::NetworkChangeNotifier::ConnectionType type) { |
| 96 DCHECK(CalledOnValidThread()); | 96 DCHECK(CalledOnValidThread()); |
| 97 if (type != net::NetworkChangeNotifier::CONNECTION_NONE) { | 97 if (type != net::NetworkChangeNotifier::CONNECTION_NONE) { |
| 98 LOG(INFO) << "Network state changed to online."; | 98 LOG(INFO) << "Network state changed to online."; |
| 99 ResetAndTryReconnect(); | 99 ResetAndTryReconnect(); |
| 100 } | 100 } |
| 101 } | 101 } |
| 102 | 102 |
| 103 void SignalingConnector::OnIPAddressChanged() { | |
| 104 DCHECK(CalledOnValidThread()); | |
| 105 LOG(INFO) << "IP address has changed."; | |
| 106 ResetAndTryReconnect(); | |
| 107 } | |
| 108 | |
| 103 void SignalingConnector::OnRefreshTokenResponse(const std::string& user_email, | 109 void SignalingConnector::OnRefreshTokenResponse(const std::string& user_email, |
| 104 const std::string& access_token, | 110 const std::string& access_token, |
| 105 int expires_seconds) { | 111 int expires_seconds) { |
| 106 DCHECK(CalledOnValidThread()); | 112 DCHECK(CalledOnValidThread()); |
| 107 DCHECK(oauth_credentials_.get()); | 113 DCHECK(oauth_credentials_.get()); |
| 108 LOG(INFO) << "Received OAuth token."; | 114 LOG(INFO) << "Received OAuth token."; |
| 109 | 115 |
| 110 if (user_email != oauth_credentials_->login) { | 116 if (user_email != oauth_credentials_->login) { |
| 111 LOG(ERROR) << "OAuth token and email address do not refer to " | 117 LOG(ERROR) << "OAuth token and email address do not refer to " |
| 112 "the same account."; | 118 "the same account."; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 140 << response_code; | 146 << response_code; |
| 141 refreshing_oauth_token_ = false; | 147 refreshing_oauth_token_ = false; |
| 142 reconnect_attempts_++; | 148 reconnect_attempts_++; |
| 143 ScheduleTryReconnect(); | 149 ScheduleTryReconnect(); |
| 144 } | 150 } |
| 145 | 151 |
| 146 void SignalingConnector::ScheduleTryReconnect() { | 152 void SignalingConnector::ScheduleTryReconnect() { |
| 147 DCHECK(CalledOnValidThread()); | 153 DCHECK(CalledOnValidThread()); |
| 148 if (timer_.IsRunning() || net::NetworkChangeNotifier::IsOffline()) | 154 if (timer_.IsRunning() || net::NetworkChangeNotifier::IsOffline()) |
| 149 return; | 155 return; |
| 150 int delay_s = std::min(1 << (reconnect_attempts_ * 2), | 156 int delay_s = std::min(1 << reconnect_attempts_, |
|
Sergey Ulanov
2012/08/30 18:05:01
Why remove *2 here. Do we still have the problem w
garykac
2012/08/31 18:28:23
Yes. I haven't been able to find any reason why th
Sergey Ulanov
2012/08/31 23:40:16
I actually see the same issue fetching OAuth token
| |
| 151 kMaxReconnectDelaySeconds); | 157 kMaxReconnectDelaySeconds); |
| 152 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_s), | 158 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_s), |
| 153 this, &SignalingConnector::TryReconnect); | 159 this, &SignalingConnector::TryReconnect); |
| 154 } | 160 } |
| 155 | 161 |
| 156 void SignalingConnector::ResetAndTryReconnect() { | 162 void SignalingConnector::ResetAndTryReconnect() { |
| 157 DCHECK(CalledOnValidThread()); | 163 DCHECK(CalledOnValidThread()); |
| 158 signal_strategy_->Disconnect(); | 164 signal_strategy_->Disconnect(); |
| 159 reconnect_attempts_ = 0; | 165 reconnect_attempts_ = 0; |
| 160 timer_.Stop(); | 166 timer_.Stop(); |
| 161 ScheduleTryReconnect(); | 167 ScheduleTryReconnect(); |
| 162 } | 168 } |
| 163 | 169 |
| 164 void SignalingConnector::TryReconnect() { | 170 void SignalingConnector::TryReconnect() { |
| 165 DCHECK(CalledOnValidThread()); | 171 DCHECK(CalledOnValidThread()); |
| 172 DCHECK(dns_blackhole_checker_); | |
|
Sergey Ulanov
2012/08/30 18:05:01
maybe put this DCHECK in constructor?
garykac
2012/08/31 18:28:23
Done.
| |
| 173 | |
| 174 // This will check if this machine is allowed to access the chromoting | |
| 175 // host talkgadget. | |
| 176 dns_blackhole_checker_->CheckForDnsBlackhole( | |
| 177 base::Bind(&SignalingConnector::OnDnsBlackholeCheckerDone, | |
| 178 base::Unretained(this))); | |
| 179 } | |
| 180 | |
| 181 void SignalingConnector::OnDnsBlackholeCheckerDone(bool allow) { | |
| 182 DCHECK(CalledOnValidThread()); | |
| 183 | |
| 184 // Unable to access the host talkgadget. Don't allow the connection, but | |
| 185 // schedule a reconnect in case this is a transient problem rather than | |
| 186 // an outright block. | |
| 187 if (!allow) { | |
| 188 reconnect_attempts_++; | |
| 189 LOG(INFO) << "Scheduling reconnect. Attempt " << reconnect_attempts_; | |
| 190 ScheduleTryReconnect(); | |
| 191 return; | |
| 192 } | |
| 193 | |
| 166 if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { | 194 if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { |
| 167 bool need_new_auth_token = oauth_credentials_.get() && | 195 bool need_new_auth_token = oauth_credentials_.get() && |
| 168 (auth_token_expiry_time_.is_null() || | 196 (auth_token_expiry_time_.is_null() || |
| 169 base::Time::Now() >= auth_token_expiry_time_); | 197 base::Time::Now() >= auth_token_expiry_time_); |
| 170 if (need_new_auth_token) { | 198 if (need_new_auth_token) { |
| 171 RefreshOAuthToken(); | 199 RefreshOAuthToken(); |
| 172 } else { | 200 } else { |
| 173 LOG(INFO) << "Attempting to connect signaling."; | 201 LOG(INFO) << "Attempting to connect signaling."; |
| 174 signal_strategy_->Connect(); | 202 signal_strategy_->Connect(); |
| 175 } | 203 } |
| 176 } | 204 } |
| 177 } | 205 } |
| 178 | 206 |
| 179 void SignalingConnector::RefreshOAuthToken() { | 207 void SignalingConnector::RefreshOAuthToken() { |
| 180 DCHECK(CalledOnValidThread()); | 208 DCHECK(CalledOnValidThread()); |
| 181 LOG(INFO) << "Refreshing OAuth token."; | 209 LOG(INFO) << "Refreshing OAuth token."; |
| 182 DCHECK(!refreshing_oauth_token_); | 210 DCHECK(!refreshing_oauth_token_); |
| 183 | 211 |
| 184 refreshing_oauth_token_ = true; | 212 refreshing_oauth_token_ = true; |
| 185 gaia_oauth_client_->RefreshToken( | 213 gaia_oauth_client_->RefreshToken( |
| 186 oauth_credentials_->client_info, | 214 oauth_credentials_->client_info, |
| 187 oauth_credentials_->refresh_token, this); | 215 oauth_credentials_->refresh_token, this); |
| 188 } | 216 } |
| 189 | 217 |
| 190 } // namespace remoting | 218 } // namespace remoting |
| OLD | NEW |