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