| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/it2me/it2me_host.h" | 5 #include "remoting/host/it2me/it2me_host.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 policy_watcher_->StartWatching( | 75 policy_watcher_->StartWatching( |
| 76 base::Bind(&It2MeHost::OnPolicyUpdate, this), | 76 base::Bind(&It2MeHost::OnPolicyUpdate, this), |
| 77 base::Bind(&It2MeHost::OnPolicyError, this)); | 77 base::Bind(&It2MeHost::OnPolicyError, this)); |
| 78 | 78 |
| 79 // Switch to the network thread to start the actual connection. | 79 // Switch to the network thread to start the actual connection. |
| 80 host_context_->network_task_runner()->PostTask( | 80 host_context_->network_task_runner()->PostTask( |
| 81 FROM_HERE, base::Bind(&It2MeHost::ShowConfirmationPrompt, this)); | 81 FROM_HERE, base::Bind(&It2MeHost::ShowConfirmationPrompt, this)); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void It2MeHost::Disconnect() { | 84 void It2MeHost::Disconnect() { |
| 85 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 85 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 86 DCHECK(task_runner_->BelongsToCurrentThread()); | 86 host_context_->network_task_runner()->PostTask( |
| 87 host_context_->network_task_runner()->PostTask( | 87 FROM_HERE, base::Bind(&It2MeHost::Shutdown, this)); |
| 88 FROM_HERE, base::Bind(&It2MeHost::Disconnect, this)); | 88 } |
| 89 return; | 89 |
| 90 void It2MeHost::Shutdown() { |
| 91 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 92 |
| 93 confirmation_dialog_proxy_.reset(); |
| 94 |
| 95 host_event_logger_.reset(); |
| 96 if (host_) { |
| 97 host_->RemoveStatusObserver(this); |
| 98 host_.reset(); |
| 90 } | 99 } |
| 91 | 100 |
| 92 switch (state_) { | 101 register_request_.reset(); |
| 93 case kDisconnected: | 102 host_status_logger_.reset(); |
| 94 ShutdownOnNetworkThread(); | 103 signal_strategy_.reset(); |
| 95 return; | |
| 96 | 104 |
| 97 case kStarting: | 105 // Post tasks to delete UI objects on the UI thread. |
| 98 SetState(kDisconnecting, ""); | 106 host_context_->ui_task_runner()->DeleteSoon( |
| 99 SetState(kDisconnected, ""); | 107 FROM_HERE, desktop_environment_factory_.release()); |
| 100 ShutdownOnNetworkThread(); | 108 host_context_->ui_task_runner()->DeleteSoon(FROM_HERE, |
| 101 return; | 109 policy_watcher_.release()); |
| 102 | 110 |
| 103 case kDisconnecting: | 111 SetState(kDisconnected, ""); |
| 104 return; | |
| 105 | |
| 106 default: | |
| 107 SetState(kDisconnecting, ""); | |
| 108 | |
| 109 if (!host_) { | |
| 110 SetState(kDisconnected, ""); | |
| 111 ShutdownOnNetworkThread(); | |
| 112 return; | |
| 113 } | |
| 114 | |
| 115 // Deleting the host destroys SignalStrategy synchronously, but | |
| 116 // SignalStrategy::Listener handlers are not allowed to destroy | |
| 117 // SignalStrategy, so post task to destroy the host later. | |
| 118 host_context_->network_task_runner()->PostTask( | |
| 119 FROM_HERE, base::Bind(&It2MeHost::ShutdownOnNetworkThread, this)); | |
| 120 return; | |
| 121 } | |
| 122 } | 112 } |
| 123 | 113 |
| 124 void It2MeHost::RequestNatPolicy() { | 114 void It2MeHost::RequestNatPolicy() { |
| 125 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 115 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { |
| 126 DCHECK(task_runner_->BelongsToCurrentThread()); | 116 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 127 host_context_->network_task_runner()->PostTask( | 117 host_context_->network_task_runner()->PostTask( |
| 128 FROM_HERE, base::Bind(&It2MeHost::RequestNatPolicy, this)); | 118 FROM_HERE, base::Bind(&It2MeHost::RequestNatPolicy, this)); |
| 129 return; | 119 return; |
| 130 } | 120 } |
| 131 | 121 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 155 base::Bind(&It2MeHost::OnConfirmationResult, base::Unretained(this))); | 145 base::Bind(&It2MeHost::OnConfirmationResult, base::Unretained(this))); |
| 156 } | 146 } |
| 157 | 147 |
| 158 void It2MeHost::OnConfirmationResult(It2MeConfirmationDialog::Result result) { | 148 void It2MeHost::OnConfirmationResult(It2MeConfirmationDialog::Result result) { |
| 159 switch (result) { | 149 switch (result) { |
| 160 case It2MeConfirmationDialog::Result::OK: | 150 case It2MeConfirmationDialog::Result::OK: |
| 161 ReadPolicyAndConnect(); | 151 ReadPolicyAndConnect(); |
| 162 break; | 152 break; |
| 163 | 153 |
| 164 case It2MeConfirmationDialog::Result::CANCEL: | 154 case It2MeConfirmationDialog::Result::CANCEL: |
| 165 Disconnect(); | 155 Shutdown(); |
| 166 break; | 156 break; |
| 167 | 157 |
| 168 default: | 158 default: |
| 169 NOTREACHED(); | 159 NOTREACHED(); |
| 170 return; | 160 return; |
| 171 } | 161 } |
| 172 } | 162 } |
| 173 | 163 |
| 174 void It2MeHost::ReadPolicyAndConnect() { | 164 void It2MeHost::ReadPolicyAndConnect() { |
| 175 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 165 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); | 255 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); |
| 266 | 256 |
| 267 // Connect signaling and start the host. | 257 // Connect signaling and start the host. |
| 268 signal_strategy_->Connect(); | 258 signal_strategy_->Connect(); |
| 269 host_->Start(xmpp_server_config_.username); | 259 host_->Start(xmpp_server_config_.username); |
| 270 | 260 |
| 271 SetState(kRequestedAccessCode, ""); | 261 SetState(kRequestedAccessCode, ""); |
| 272 return; | 262 return; |
| 273 } | 263 } |
| 274 | 264 |
| 275 void It2MeHost::ShutdownOnNetworkThread() { | |
| 276 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | |
| 277 DCHECK(state_ == kDisconnecting || state_ == kDisconnected); | |
| 278 | |
| 279 confirmation_dialog_proxy_.reset(); | |
| 280 | |
| 281 if (state_ == kDisconnecting) { | |
| 282 host_event_logger_.reset(); | |
| 283 host_->RemoveStatusObserver(this); | |
| 284 host_.reset(); | |
| 285 | |
| 286 register_request_.reset(); | |
| 287 host_status_logger_.reset(); | |
| 288 signal_strategy_.reset(); | |
| 289 SetState(kDisconnected, ""); | |
| 290 } | |
| 291 | |
| 292 host_context_->ui_task_runner()->PostTask( | |
| 293 FROM_HERE, base::Bind(&It2MeHost::ShutdownOnUiThread, this)); | |
| 294 } | |
| 295 | |
| 296 void It2MeHost::ShutdownOnUiThread() { | |
| 297 DCHECK(host_context_->ui_task_runner()->BelongsToCurrentThread()); | |
| 298 | |
| 299 // Destroy the DesktopEnvironmentFactory, to free thread references. | |
| 300 desktop_environment_factory_.reset(); | |
| 301 | |
| 302 // Stop listening for policy updates. | |
| 303 policy_watcher_.reset(); | |
| 304 } | |
| 305 | |
| 306 void It2MeHost::OnAccessDenied(const std::string& jid) { | 265 void It2MeHost::OnAccessDenied(const std::string& jid) { |
| 307 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 266 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 308 | 267 |
| 309 ++failed_login_attempts_; | 268 ++failed_login_attempts_; |
| 310 if (failed_login_attempts_ == kMaxLoginAttempts) { | 269 if (failed_login_attempts_ == kMaxLoginAttempts) { |
| 311 Disconnect(); | 270 Shutdown(); |
| 312 } | 271 } |
| 313 } | 272 } |
| 314 | 273 |
| 315 void It2MeHost::OnClientAuthenticated(const std::string& jid) { | 274 void It2MeHost::OnClientConnected(const std::string& jid) { |
| 316 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 275 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 317 | 276 |
| 318 if (state_ == kDisconnecting) { | 277 // ChromotingHost doesn't allow multiple concurrent connection and the |
| 319 // Ignore the new connection if we are disconnecting. | 278 // host is destroyed in OnClientDisconnected() after the first connection. |
| 320 return; | 279 CHECK_NE(state_, kConnected); |
| 321 } | |
| 322 if (state_ == kConnected) { | |
| 323 // If we already connected another client then one of the connections may be | |
| 324 // an attacker, so both are suspect and we have to reject the second | |
| 325 // connection and shutdown the host. | |
| 326 host_->RejectAuthenticatingClient(); | |
| 327 Disconnect(); | |
| 328 return; | |
| 329 } | |
| 330 | 280 |
| 331 std::string client_username = jid; | 281 std::string client_username = jid; |
| 332 size_t pos = client_username.find('/'); | 282 size_t pos = client_username.find('/'); |
| 333 if (pos != std::string::npos) | 283 if (pos != std::string::npos) |
| 334 client_username.replace(pos, std::string::npos, ""); | 284 client_username.replace(pos, std::string::npos, ""); |
| 335 | 285 |
| 336 HOST_LOG << "Client " << client_username << " connected."; | 286 HOST_LOG << "Client " << client_username << " connected."; |
| 337 | 287 |
| 338 // Pass the client user name to the script object before changing state. | 288 // Pass the client user name to the script object before changing state. |
| 339 task_runner_->PostTask( | 289 task_runner_->PostTask( |
| 340 FROM_HERE, base::Bind(&It2MeHost::Observer::OnClientAuthenticated, | 290 FROM_HERE, base::Bind(&It2MeHost::Observer::OnClientAuthenticated, |
| 341 observer_, client_username)); | 291 observer_, client_username)); |
| 342 | 292 |
| 343 SetState(kConnected, ""); | 293 SetState(kConnected, ""); |
| 344 } | 294 } |
| 345 | 295 |
| 346 void It2MeHost::OnClientDisconnected(const std::string& jid) { | 296 void It2MeHost::OnClientDisconnected(const std::string& jid) { |
| 347 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 297 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 348 | 298 |
| 349 Disconnect(); | 299 Shutdown(); |
| 350 } | 300 } |
| 351 | 301 |
| 352 void It2MeHost::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { | 302 void It2MeHost::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { |
| 353 // The policy watcher runs on the |ui_task_runner|. | 303 // The policy watcher runs on the |ui_task_runner|. |
| 354 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 304 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { |
| 355 host_context_->network_task_runner()->PostTask( | 305 host_context_->network_task_runner()->PostTask( |
| 356 FROM_HERE, | 306 FROM_HERE, |
| 357 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); | 307 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); |
| 358 return; | 308 return; |
| 359 } | 309 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 381 } | 331 } |
| 382 | 332 |
| 383 void It2MeHost::UpdateNatPolicy(bool nat_traversal_enabled) { | 333 void It2MeHost::UpdateNatPolicy(bool nat_traversal_enabled) { |
| 384 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 334 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 385 | 335 |
| 386 VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled; | 336 VLOG(2) << "UpdateNatPolicy: " << nat_traversal_enabled; |
| 387 | 337 |
| 388 // When transitioning from enabled to disabled, force disconnect any | 338 // When transitioning from enabled to disabled, force disconnect any |
| 389 // existing session. | 339 // existing session. |
| 390 if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) { | 340 if (nat_traversal_enabled_ && !nat_traversal_enabled && IsConnected()) { |
| 391 Disconnect(); | 341 Shutdown(); |
| 392 } | 342 } |
| 393 | 343 |
| 394 nat_traversal_enabled_ = nat_traversal_enabled; | 344 nat_traversal_enabled_ = nat_traversal_enabled; |
| 395 | 345 |
| 396 // Notify the web-app of the policy setting. | 346 // Notify the web-app of the policy setting. |
| 397 task_runner_->PostTask( | 347 task_runner_->PostTask( |
| 398 FROM_HERE, base::Bind(&It2MeHost::Observer::OnNatPolicyChanged, | 348 FROM_HERE, base::Bind(&It2MeHost::Observer::OnNatPolicyChanged, |
| 399 observer_, nat_traversal_enabled_)); | 349 observer_, nat_traversal_enabled_)); |
| 400 } | 350 } |
| 401 | 351 |
| 402 void It2MeHost::UpdateHostDomainPolicy(const std::string& host_domain) { | 352 void It2MeHost::UpdateHostDomainPolicy(const std::string& host_domain) { |
| 403 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 353 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 404 | 354 |
| 405 VLOG(2) << "UpdateHostDomainPolicy: " << host_domain; | 355 VLOG(2) << "UpdateHostDomainPolicy: " << host_domain; |
| 406 | 356 |
| 407 // When setting a host domain policy, force disconnect any existing session. | 357 // When setting a host domain policy, force disconnect any existing session. |
| 408 if (!host_domain.empty() && IsConnected()) { | 358 if (!host_domain.empty() && IsConnected()) { |
| 409 Disconnect(); | 359 Shutdown(); |
| 410 } | 360 } |
| 411 | 361 |
| 412 required_host_domain_ = host_domain; | 362 required_host_domain_ = host_domain; |
| 413 } | 363 } |
| 414 | 364 |
| 415 It2MeHost::~It2MeHost() { | 365 It2MeHost::~It2MeHost() { |
| 416 // Check that resources that need to be torn down on the UI thread are gone. | 366 // Check that resources that need to be torn down on the UI thread are gone. |
| 417 DCHECK(!desktop_environment_factory_.get()); | 367 DCHECK(!desktop_environment_factory_.get()); |
| 418 DCHECK(!policy_watcher_.get()); | 368 DCHECK(!policy_watcher_.get()); |
| 419 } | 369 } |
| 420 | 370 |
| 421 void It2MeHost::SetState(It2MeHostState state, | 371 void It2MeHost::SetState(It2MeHostState state, |
| 422 const std::string& error_message) { | 372 const std::string& error_message) { |
| 423 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 373 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 424 | 374 |
| 425 switch (state_) { | 375 switch (state_) { |
| 426 case kDisconnected: | 376 case kDisconnected: |
| 427 DCHECK(state == kStarting || | 377 DCHECK(state == kStarting || |
| 428 state == kError) << state; | 378 state == kError) << state; |
| 429 break; | 379 break; |
| 430 case kStarting: | 380 case kStarting: |
| 431 DCHECK(state == kRequestedAccessCode || | 381 DCHECK(state == kRequestedAccessCode || |
| 432 state == kDisconnecting || | 382 state == kDisconnected || |
| 433 state == kError || | 383 state == kError || |
| 434 state == kInvalidDomainError) << state; | 384 state == kInvalidDomainError) << state; |
| 435 break; | 385 break; |
| 436 case kRequestedAccessCode: | 386 case kRequestedAccessCode: |
| 437 DCHECK(state == kReceivedAccessCode || | 387 DCHECK(state == kReceivedAccessCode || |
| 438 state == kDisconnecting || | 388 state == kDisconnected || |
| 439 state == kError) << state; | 389 state == kError) << state; |
| 440 break; | 390 break; |
| 441 case kReceivedAccessCode: | 391 case kReceivedAccessCode: |
| 442 DCHECK(state == kConnected || | 392 DCHECK(state == kConnected || |
| 443 state == kDisconnecting || | 393 state == kDisconnected || |
| 444 state == kError) << state; | 394 state == kError) << state; |
| 445 break; | 395 break; |
| 446 case kConnected: | 396 case kConnected: |
| 447 DCHECK(state == kDisconnecting || | 397 DCHECK(state == kDisconnected || |
| 448 state == kDisconnected || | |
| 449 state == kError) << state; | 398 state == kError) << state; |
| 450 break; | 399 break; |
| 451 case kDisconnecting: | 400 case kError: |
| 452 DCHECK(state == kDisconnected) << state; | 401 DCHECK(state == kDisconnected) << state; |
| 453 break; | 402 break; |
| 454 case kError: | |
| 455 DCHECK(state == kDisconnecting) << state; | |
| 456 break; | |
| 457 case kInvalidDomainError: | 403 case kInvalidDomainError: |
| 458 DCHECK(state == kDisconnecting) << state; | 404 DCHECK(state == kDisconnected) << state; |
| 459 break; | 405 break; |
| 460 }; | 406 }; |
| 461 | 407 |
| 462 state_ = state; | 408 state_ = state; |
| 463 | 409 |
| 464 // Post a state-change notification to the web-app. | 410 // Post a state-change notification to the web-app. |
| 465 task_runner_->PostTask( | 411 task_runner_->PostTask( |
| 466 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStateChanged, | 412 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStateChanged, |
| 467 observer_, state, error_message)); | 413 observer_, state, error_message)); |
| 468 } | 414 } |
| 469 | 415 |
| 470 bool It2MeHost::IsConnected() const { | 416 bool It2MeHost::IsConnected() const { |
| 471 return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode || | 417 return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode || |
| 472 state_ == kConnected; | 418 state_ == kConnected; |
| 473 } | 419 } |
| 474 | 420 |
| 475 void It2MeHost::OnReceivedSupportID( | 421 void It2MeHost::OnReceivedSupportID( |
| 476 const std::string& support_id, | 422 const std::string& support_id, |
| 477 const base::TimeDelta& lifetime, | 423 const base::TimeDelta& lifetime, |
| 478 const std::string& error_message) { | 424 const std::string& error_message) { |
| 479 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 425 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 480 | 426 |
| 481 if (!error_message.empty()) { | 427 if (!error_message.empty()) { |
| 482 SetState(kError, error_message); | 428 SetState(kError, error_message); |
| 483 Disconnect(); | 429 Shutdown(); |
| 484 return; | 430 return; |
| 485 } | 431 } |
| 486 | 432 |
| 487 std::string host_secret = GenerateSupportHostSecret(); | 433 std::string host_secret = GenerateSupportHostSecret(); |
| 488 std::string access_code = support_id + host_secret; | 434 std::string access_code = support_id + host_secret; |
| 489 | 435 |
| 490 std::string local_certificate = host_key_pair_->GenerateCertificate(); | 436 std::string local_certificate = host_key_pair_->GenerateCertificate(); |
| 491 if (local_certificate.empty()) { | 437 if (local_certificate.empty()) { |
| 492 std::string error_message = "Failed to generate host certificate."; | 438 std::string error_message = "Failed to generate host certificate."; |
| 493 LOG(ERROR) << error_message; | 439 LOG(ERROR) << error_message; |
| 494 SetState(kError, error_message); | 440 SetState(kError, error_message); |
| 495 Disconnect(); | 441 Shutdown(); |
| 496 return; | 442 return; |
| 497 } | 443 } |
| 498 | 444 |
| 499 scoped_ptr<protocol::AuthenticatorFactory> factory( | 445 scoped_ptr<protocol::AuthenticatorFactory> factory( |
| 500 new protocol::It2MeHostAuthenticatorFactory( | 446 new protocol::It2MeHostAuthenticatorFactory( |
| 501 local_certificate, host_key_pair_, access_code)); | 447 local_certificate, host_key_pair_, access_code)); |
| 502 host_->SetAuthenticatorFactory(factory.Pass()); | 448 host_->SetAuthenticatorFactory(factory.Pass()); |
| 503 | 449 |
| 504 // Pass the Access Code to the script object before changing state. | 450 // Pass the Access Code to the script object before changing state. |
| 505 task_runner_->PostTask( | 451 task_runner_->PostTask( |
| (...skipping 25 matching lines...) Expand all Loading... |
| 531 scoped_ptr<It2MeConfirmationDialogFactory> confirmation_dialog_factory( | 477 scoped_ptr<It2MeConfirmationDialogFactory> confirmation_dialog_factory( |
| 532 new It2MeConfirmationDialogFactory()); | 478 new It2MeConfirmationDialogFactory()); |
| 533 scoped_ptr<PolicyWatcher> policy_watcher = | 479 scoped_ptr<PolicyWatcher> policy_watcher = |
| 534 PolicyWatcher::Create(policy_service_, context->file_task_runner()); | 480 PolicyWatcher::Create(policy_service_, context->file_task_runner()); |
| 535 return new It2MeHost(context.Pass(), policy_watcher.Pass(), | 481 return new It2MeHost(context.Pass(), policy_watcher.Pass(), |
| 536 confirmation_dialog_factory.Pass(), | 482 confirmation_dialog_factory.Pass(), |
| 537 observer, xmpp_server_config, directory_bot_jid); | 483 observer, xmpp_server_config, directory_bot_jid); |
| 538 } | 484 } |
| 539 | 485 |
| 540 } // namespace remoting | 486 } // namespace remoting |
| OLD | NEW |