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