| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/plugin/host_script_object.h" | 5 #include "remoting/host/plugin/host_script_object.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/threading/platform_thread.h" | 9 #include "base/threading/platform_thread.h" |
| 10 #include "remoting/base/auth_token_util.h" | 10 #include "remoting/base/auth_token_util.h" |
| 11 #include "remoting/base/util.h" | 11 #include "remoting/base/util.h" |
| 12 #include "remoting/host/chromoting_host.h" | 12 #include "remoting/host/chromoting_host.h" |
| 13 #include "remoting/host/chromoting_host_context.h" | 13 #include "remoting/host/chromoting_host_context.h" |
| 14 #include "remoting/host/desktop_environment.h" | 14 #include "remoting/host/desktop_environment.h" |
| 15 #include "remoting/host/host_config.h" | 15 #include "remoting/host/host_config.h" |
| 16 #include "remoting/host/host_key_pair.h" | 16 #include "remoting/host/host_key_pair.h" |
| 17 #include "remoting/host/in_memory_host_config.h" | 17 #include "remoting/host/in_memory_host_config.h" |
| 18 #include "remoting/host/plugin/host_plugin_utils.h" | 18 #include "remoting/host/plugin/host_plugin_utils.h" |
| 19 #include "remoting/host/plugin/policy_hack/nat_policy.h" |
| 19 #include "remoting/host/register_support_host_request.h" | 20 #include "remoting/host/register_support_host_request.h" |
| 20 #include "remoting/host/support_access_verifier.h" | 21 #include "remoting/host/support_access_verifier.h" |
| 21 | 22 |
| 22 namespace remoting { | 23 namespace remoting { |
| 23 | 24 |
| 24 // Supported Javascript interface: | 25 // Supported Javascript interface: |
| 25 // readonly attribute string accessCode; | 26 // readonly attribute string accessCode; |
| 26 // readonly attribute int accessCodeLifetime; | 27 // readonly attribute int accessCodeLifetime; |
| 27 // readonly attribute string client; | 28 // readonly attribute string client; |
| 28 // readonly attribute int state; | 29 // readonly attribute int state; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 76 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
| 76 | 77 |
| 77 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) | 78 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) |
| 78 : plugin_(plugin), | 79 : plugin_(plugin), |
| 79 parent_(parent), | 80 parent_(parent), |
| 80 state_(kDisconnected), | 81 state_(kDisconnected), |
| 81 log_debug_info_func_(NULL), | 82 log_debug_info_func_(NULL), |
| 82 on_state_changed_func_(NULL), | 83 on_state_changed_func_(NULL), |
| 83 np_thread_id_(base::PlatformThread::CurrentId()), | 84 np_thread_id_(base::PlatformThread::CurrentId()), |
| 84 failed_login_attempts_(0), | 85 failed_login_attempts_(0), |
| 85 disconnected_event_(true, false) { | 86 disconnected_event_(true, false), |
| 87 nat_traversal_enabled_(false), |
| 88 policy_received_(false) { |
| 86 // Set up log message handler. | 89 // Set up log message handler. |
| 87 // Note that this approach doesn't quite support having multiple instances | 90 // Note that this approach doesn't quite support having multiple instances |
| 88 // of Chromoting running. In that case, the most recently opened tab will | 91 // of Chromoting running. In that case, the most recently opened tab will |
| 89 // grab all the debug log messages, and when any Chromoting tab is closed | 92 // grab all the debug log messages, and when any Chromoting tab is closed |
| 90 // the logging handler will go away. | 93 // the logging handler will go away. |
| 91 // Since having multiple Chromoting tabs is not a primary use case, and this | 94 // Since having multiple Chromoting tabs is not a primary use case, and this |
| 92 // is just debug logging, we're punting improving debug log support for that | 95 // is just debug logging, we're punting improving debug log support for that |
| 93 // case. | 96 // case. |
| 94 if (g_logging_old_handler == NULL) | 97 if (g_logging_old_handler == NULL) |
| 95 g_logging_old_handler = logging::GetLogMessageHandler(); | 98 g_logging_old_handler = logging::GetLogMessageHandler(); |
| 96 logging::SetLogMessageHandler(&LogToUI); | 99 logging::SetLogMessageHandler(&LogToUI); |
| 97 g_logging_scriptable_object = this; | 100 g_logging_scriptable_object = this; |
| 98 | 101 |
| 99 VLOG(2) << "HostNPScriptObject"; | 102 VLOG(2) << "HostNPScriptObject"; |
| 100 host_context_.SetUITaskPostFunction(base::Bind( | 103 host_context_.SetUITaskPostFunction(base::Bind( |
| 101 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | 104 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); |
| 102 } | 105 } |
| 103 | 106 |
| 104 HostNPScriptObject::~HostNPScriptObject() { | 107 HostNPScriptObject::~HostNPScriptObject() { |
| 105 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 108 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
| 106 | 109 |
| 107 // Shutdown DesktopEnvironment first so that it doesn't try to post | 110 // Shutdown DesktopEnvironment first so that it doesn't try to post |
| 108 // tasks on the UI thread while we are stopping the host. | 111 // tasks on the UI thread while we are stopping the host. |
| 109 desktop_environment_->Shutdown(); | 112 desktop_environment_->Shutdown(); |
| 110 | 113 |
| 111 logging::SetLogMessageHandler(g_logging_old_handler); | 114 logging::SetLogMessageHandler(g_logging_old_handler); |
| 112 g_logging_old_handler = NULL; | 115 g_logging_old_handler = NULL; |
| 113 g_logging_scriptable_object = NULL; | 116 g_logging_scriptable_object = NULL; |
| 114 | 117 |
| 118 // Stop listening for policy updates. |
| 119 if (nat_policy_.get()) { |
| 120 base::WaitableEvent nat_policy_stopped_(true, false); |
| 121 nat_policy_->StopWatching(&nat_policy_stopped_); |
| 122 nat_policy_stopped_.Wait(); |
| 123 nat_policy_.reset(); |
| 124 } |
| 125 |
| 115 // Disconnect synchronously. We cannot disconnect asynchronously | 126 // Disconnect synchronously. We cannot disconnect asynchronously |
| 116 // here because |host_context_| needs to be stopped on the plugin | 127 // here because |host_context_| needs to be stopped on the plugin |
| 117 // thread, but the plugin thread may not exist after the instance | 128 // thread, but the plugin thread may not exist after the instance |
| 118 // is destroyed. | 129 // is destroyed. |
| 119 destructing_.Set(); | 130 destructing_.Set(); |
| 120 disconnected_event_.Reset(); | 131 disconnected_event_.Reset(); |
| 121 DisconnectInternal(); | 132 DisconnectInternal(); |
| 122 disconnected_event_.Wait(); | 133 disconnected_event_.Wait(); |
| 123 | 134 |
| 124 // Stop all threads. | 135 // Stop all threads. |
| 125 host_context_.Stop(); | 136 host_context_.Stop(); |
| 126 | 137 |
| 127 if (log_debug_info_func_) { | 138 if (log_debug_info_func_) { |
| 128 g_npnetscape_funcs->releaseobject(log_debug_info_func_); | 139 g_npnetscape_funcs->releaseobject(log_debug_info_func_); |
| 129 } | 140 } |
| 130 if (on_state_changed_func_) { | 141 if (on_state_changed_func_) { |
| 131 g_npnetscape_funcs->releaseobject(on_state_changed_func_); | 142 g_npnetscape_funcs->releaseobject(on_state_changed_func_); |
| 132 } | 143 } |
| 133 } | 144 } |
| 134 | 145 |
| 135 bool HostNPScriptObject::Init() { | 146 bool HostNPScriptObject::Init() { |
| 136 VLOG(2) << "Init"; | 147 VLOG(2) << "Init"; |
| 137 // TODO(wez): This starts a bunch of threads, which might fail. | 148 // TODO(wez): This starts a bunch of threads, which might fail. |
| 138 host_context_.Start(); | 149 host_context_.Start(); |
| 150 nat_policy_.reset(policy_hack::NatPolicy::Create( |
| 151 host_context_.network_message_loop(), |
| 152 base::Bind(&HostNPScriptObject::OnNatPolicyUpdate, |
| 153 base::Unretained(this)))); |
| 154 nat_policy_->StartWatching(); |
| 139 return true; | 155 return true; |
| 140 } | 156 } |
| 141 | 157 |
| 142 bool HostNPScriptObject::HasMethod(const std::string& method_name) { | 158 bool HostNPScriptObject::HasMethod(const std::string& method_name) { |
| 143 VLOG(2) << "HasMethod " << method_name; | 159 VLOG(2) << "HasMethod " << method_name; |
| 144 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 160 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
| 145 return (method_name == kFuncNameConnect || | 161 return (method_name == kFuncNameConnect || |
| 146 method_name == kFuncNameDisconnect); | 162 method_name == kFuncNameDisconnect); |
| 147 } | 163 } |
| 148 | 164 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 std::string auth_service_with_token = StringFromNPVariant(args[1]); | 386 std::string auth_service_with_token = StringFromNPVariant(args[1]); |
| 371 std::string auth_token; | 387 std::string auth_token; |
| 372 std::string auth_service; | 388 std::string auth_service; |
| 373 ParseAuthTokenWithService(auth_service_with_token, &auth_token, | 389 ParseAuthTokenWithService(auth_service_with_token, &auth_token, |
| 374 &auth_service); | 390 &auth_service); |
| 375 if (auth_token.empty()) { | 391 if (auth_token.empty()) { |
| 376 SetException("connect: auth_service_with_token argument has empty token"); | 392 SetException("connect: auth_service_with_token argument has empty token"); |
| 377 return false; | 393 return false; |
| 378 } | 394 } |
| 379 | 395 |
| 380 ConnectInternal(uid, auth_token, auth_service); | 396 ReadPolicyAndConnect(uid, auth_token, auth_service); |
| 381 | 397 |
| 382 return true; | 398 return true; |
| 383 } | 399 } |
| 384 | 400 |
| 401 void HostNPScriptObject::ReadPolicyAndConnect(const std::string& uid, |
| 402 const std::string& auth_token, |
| 403 const std::string& auth_service) { |
| 404 if (MessageLoop::current() != host_context_.main_message_loop()) { |
| 405 host_context_.main_message_loop()->PostTask( |
| 406 FROM_HERE, base::Bind( |
| 407 &HostNPScriptObject::ReadPolicyAndConnect, base::Unretained(this), |
| 408 uid, auth_token, auth_service)); |
| 409 return; |
| 410 } |
| 411 |
| 412 // Only proceed to ConnectInternal() if at least one policy update has been |
| 413 // received. |
| 414 if (policy_received_) { |
| 415 ConnectInternal(uid, auth_token, auth_service); |
| 416 } else { |
| 417 // Otherwise, create the policy watcher, and thunk the connect. |
| 418 pending_connect_ = |
| 419 base::Bind(&HostNPScriptObject::ConnectInternal, |
| 420 base::Unretained(this), uid, auth_token, auth_service); |
| 421 } |
| 422 } |
| 423 |
| 385 void HostNPScriptObject::ConnectInternal( | 424 void HostNPScriptObject::ConnectInternal( |
| 386 const std::string& uid, | 425 const std::string& uid, |
| 387 const std::string& auth_token, | 426 const std::string& auth_token, |
| 388 const std::string& auth_service) { | 427 const std::string& auth_service) { |
| 389 if (MessageLoop::current() != host_context_.main_message_loop()) { | 428 if (MessageLoop::current() != host_context_.main_message_loop()) { |
| 390 host_context_.main_message_loop()->PostTask( | 429 host_context_.main_message_loop()->PostTask( |
| 391 FROM_HERE, base::Bind( | 430 FROM_HERE, base::Bind( |
| 392 &HostNPScriptObject::ConnectInternal, base::Unretained(this), | 431 &HostNPScriptObject::ConnectInternal, base::Unretained(this), |
| 393 uid, auth_token, auth_service)); | 432 uid, auth_token, auth_service)); |
| 394 return; | 433 return; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 422 } | 461 } |
| 423 | 462 |
| 424 // Nothing went wrong, so lets save the host, config and request. | 463 // Nothing went wrong, so lets save the host, config and request. |
| 425 host_config_ = host_config; | 464 host_config_ = host_config; |
| 426 register_request_.reset(register_request.release()); | 465 register_request_.reset(register_request.release()); |
| 427 | 466 |
| 428 // Create DesktopEnvironment. | 467 // Create DesktopEnvironment. |
| 429 desktop_environment_.reset(DesktopEnvironment::Create(&host_context_)); | 468 desktop_environment_.reset(DesktopEnvironment::Create(&host_context_)); |
| 430 | 469 |
| 431 // Create the Host. | 470 // Create the Host. |
| 432 // TODO(sergeyu): Use firewall traversal policy settings here. | 471 LOG(INFO) << "Connecting with NAT state: " << nat_traversal_enabled_; |
| 433 host_ = ChromotingHost::Create( | 472 host_ = ChromotingHost::Create( |
| 434 &host_context_, host_config_, desktop_environment_.get(), | 473 &host_context_, host_config_, desktop_environment_.get(), |
| 435 access_verifier.release(), false); | 474 access_verifier.release(), nat_traversal_enabled_); |
| 436 host_->AddStatusObserver(this); | 475 host_->AddStatusObserver(this); |
| 437 host_->AddStatusObserver(register_request_.get()); | 476 host_->AddStatusObserver(register_request_.get()); |
| 438 host_->set_it2me(true); | 477 host_->set_it2me(true); |
| 439 | 478 |
| 440 // Start the Host. | 479 // Start the Host. |
| 441 host_->Start(); | 480 host_->Start(); |
| 442 | 481 |
| 443 OnStateChanged(kRequestedAccessCode); | 482 OnStateChanged(kRequestedAccessCode); |
| 444 return; | 483 return; |
| 445 } | 484 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 | 516 |
| 478 void HostNPScriptObject::OnShutdownFinished() { | 517 void HostNPScriptObject::OnShutdownFinished() { |
| 479 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop()); | 518 DCHECK_EQ(MessageLoop::current(), host_context_.main_message_loop()); |
| 480 | 519 |
| 481 host_ = NULL; | 520 host_ = NULL; |
| 482 register_request_.reset(); | 521 register_request_.reset(); |
| 483 host_config_ = NULL; | 522 host_config_ = NULL; |
| 484 disconnected_event_.Signal(); | 523 disconnected_event_.Signal(); |
| 485 } | 524 } |
| 486 | 525 |
| 526 void HostNPScriptObject::OnNatPolicyUpdate(bool nat_traversal_enabled) { |
| 527 if (MessageLoop::current() != host_context_.main_message_loop()) { |
| 528 host_context_.main_message_loop()->PostTask( |
| 529 FROM_HERE, |
| 530 base::Bind(&HostNPScriptObject::OnNatPolicyUpdate, |
| 531 base::Unretained(this), nat_traversal_enabled)); |
| 532 return; |
| 533 } |
| 534 |
| 535 VLOG(2) << "OnNatPolicyUpdate: " << nat_traversal_enabled; |
| 536 |
| 537 // When transitioning from true to false, force a disconnect. |
| 538 if (nat_traversal_enabled_ && !nat_traversal_enabled) { |
| 539 DisconnectInternal(); |
| 540 } |
| 541 |
| 542 policy_received_ = true; |
| 543 nat_traversal_enabled_ = nat_traversal_enabled; |
| 544 |
| 545 if (!pending_connect_.is_null()) { |
| 546 pending_connect_.Run(); |
| 547 pending_connect_.Reset(); |
| 548 } |
| 549 } |
| 550 |
| 487 void HostNPScriptObject::OnReceivedSupportID( | 551 void HostNPScriptObject::OnReceivedSupportID( |
| 488 SupportAccessVerifier* access_verifier, | 552 SupportAccessVerifier* access_verifier, |
| 489 bool success, | 553 bool success, |
| 490 const std::string& support_id, | 554 const std::string& support_id, |
| 491 const base::TimeDelta& lifetime) { | 555 const base::TimeDelta& lifetime) { |
| 492 CHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_); | 556 CHECK_NE(base::PlatformThread::CurrentId(), np_thread_id_); |
| 493 | 557 |
| 494 if (!success) { | 558 if (!success) { |
| 495 // TODO(wez): Replace the success/fail flag with full error reporting. | 559 // TODO(wez): Replace the success/fail flag with full error reporting. |
| 496 DisconnectInternal(); | 560 DisconnectInternal(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } | 665 } |
| 602 | 666 |
| 603 // static | 667 // static |
| 604 void HostNPScriptObject::NPTaskSpringboard(void* task) { | 668 void HostNPScriptObject::NPTaskSpringboard(void* task) { |
| 605 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); | 669 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); |
| 606 real_task->Run(); | 670 real_task->Run(); |
| 607 delete real_task; | 671 delete real_task; |
| 608 } | 672 } |
| 609 | 673 |
| 610 } // namespace remoting | 674 } // namespace remoting |
| OLD | NEW |