| 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/sys_string_conversions.h" | 10 #include "base/sys_string_conversions.h" |
| 11 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "remoting/base/auth_token_util.h" | 13 #include "remoting/base/auth_token_util.h" |
| 14 #include "remoting/base/util.h" | |
| 15 #include "remoting/host/chromoting_host.h" | 14 #include "remoting/host/chromoting_host.h" |
| 16 #include "remoting/host/chromoting_host_context.h" | 15 #include "remoting/host/chromoting_host_context.h" |
| 17 #include "remoting/host/desktop_environment.h" | 16 #include "remoting/host/desktop_environment.h" |
| 18 #include "remoting/host/host_config.h" | 17 #include "remoting/host/host_config.h" |
| 19 #include "remoting/host/host_key_pair.h" | 18 #include "remoting/host/host_key_pair.h" |
| 20 #include "remoting/host/in_memory_host_config.h" | 19 #include "remoting/host/in_memory_host_config.h" |
| 20 #include "remoting/host/plugin/host_log_handler.h" |
| 21 #include "remoting/host/plugin/policy_hack/nat_policy.h" | 21 #include "remoting/host/plugin/policy_hack/nat_policy.h" |
| 22 #include "remoting/host/register_support_host_request.h" | 22 #include "remoting/host/register_support_host_request.h" |
| 23 #include "remoting/host/support_access_verifier.h" | 23 #include "remoting/host/support_access_verifier.h" |
| 24 | 24 |
| 25 namespace remoting { | 25 namespace remoting { |
| 26 | 26 |
| 27 // Supported Javascript interface: | 27 // Supported Javascript interface: |
| 28 // readonly attribute string accessCode; | 28 // readonly attribute string accessCode; |
| 29 // readonly attribute int accessCodeLifetime; | 29 // readonly attribute int accessCodeLifetime; |
| 30 // readonly attribute string client; | 30 // readonly attribute string client; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE"; | 65 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE"; |
| 66 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE"; | 66 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE"; |
| 67 const char* kAttrNameConnected = "CONNECTED"; | 67 const char* kAttrNameConnected = "CONNECTED"; |
| 68 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION"; | 68 const char* kAttrNameAffirmingConnection = "AFFIRMING_CONNECTION"; |
| 69 const char* kAttrNameError = "ERROR"; | 69 const char* kAttrNameError = "ERROR"; |
| 70 | 70 |
| 71 const int kMaxLoginAttempts = 5; | 71 const int kMaxLoginAttempts = 5; |
| 72 | 72 |
| 73 } // namespace | 73 } // namespace |
| 74 | 74 |
| 75 // This flag blocks LOGs to the UI if we're already in the middle of logging | |
| 76 // to the UI. This prevents a potential infinite loop if we encounter an error | |
| 77 // while sending the log message to the UI. | |
| 78 static bool g_logging_to_plugin = false; | |
| 79 static HostNPScriptObject* g_logging_scriptable_object = NULL; | |
| 80 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | |
| 81 | |
| 82 HostNPScriptObject::HostNPScriptObject( | 75 HostNPScriptObject::HostNPScriptObject( |
| 83 NPP plugin, | 76 NPP plugin, |
| 84 NPObject* parent, | 77 NPObject* parent, |
| 85 PluginMessageLoopProxy::Delegate* plugin_thread_delegate) | 78 PluginMessageLoopProxy::Delegate* plugin_thread_delegate) |
| 86 : plugin_(plugin), | 79 : plugin_(plugin), |
| 87 parent_(parent), | 80 parent_(parent), |
| 88 state_(kDisconnected), | 81 state_(kDisconnected), |
| 89 np_thread_id_(base::PlatformThread::CurrentId()), | 82 np_thread_id_(base::PlatformThread::CurrentId()), |
| 90 plugin_message_loop_proxy_( | 83 plugin_message_loop_proxy_( |
| 91 new PluginMessageLoopProxy(plugin_thread_delegate)), | 84 new PluginMessageLoopProxy(plugin_thread_delegate)), |
| 92 host_context_(plugin_message_loop_proxy_), | 85 host_context_(plugin_message_loop_proxy_), |
| 93 failed_login_attempts_(0), | 86 failed_login_attempts_(0), |
| 94 disconnected_event_(true, false), | 87 disconnected_event_(true, false), |
| 88 am_currently_logging_(false), |
| 95 nat_traversal_enabled_(false), | 89 nat_traversal_enabled_(false), |
| 96 policy_received_(false) { | 90 policy_received_(false) { |
| 97 // Set up log message handler. | |
| 98 // Note that this approach doesn't quite support having multiple instances | |
| 99 // of Chromoting running. In that case, the most recently opened tab will | |
| 100 // grab all the debug log messages, and when any Chromoting tab is closed | |
| 101 // the logging handler will go away. | |
| 102 // Since having multiple Chromoting tabs is not a primary use case, and this | |
| 103 // is just debug logging, we're punting improving debug log support for that | |
| 104 // case. | |
| 105 if (g_logging_old_handler == NULL) | |
| 106 g_logging_old_handler = logging::GetLogMessageHandler(); | |
| 107 logging::SetLogMessageHandler(&LogToUI); | |
| 108 g_logging_scriptable_object = this; | |
| 109 } | 91 } |
| 110 | 92 |
| 111 HostNPScriptObject::~HostNPScriptObject() { | 93 HostNPScriptObject::~HostNPScriptObject() { |
| 112 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 94 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
| 113 | 95 |
| 114 // Shutdown DesktopEnvironment first so that it doesn't try to post | 96 // Shutdown DesktopEnvironment first so that it doesn't try to post |
| 115 // tasks on the UI thread while we are stopping the host. | 97 // tasks on the UI thread while we are stopping the host. |
| 116 desktop_environment_->Shutdown(); | 98 desktop_environment_->Shutdown(); |
| 117 | 99 |
| 118 logging::SetLogMessageHandler(g_logging_old_handler); | 100 HostLogHandler::UnregisterLoggingScriptObject(this); |
| 119 g_logging_old_handler = NULL; | |
| 120 g_logging_scriptable_object = NULL; | |
| 121 | 101 |
| 122 plugin_message_loop_proxy_->Detach(); | 102 plugin_message_loop_proxy_->Detach(); |
| 123 | 103 |
| 124 // Stop listening for policy updates. | 104 // Stop listening for policy updates. |
| 125 if (nat_policy_.get()) { | 105 if (nat_policy_.get()) { |
| 126 base::WaitableEvent nat_policy_stopped_(true, false); | 106 base::WaitableEvent nat_policy_stopped_(true, false); |
| 127 nat_policy_->StopWatching(&nat_policy_stopped_); | 107 nat_policy_->StopWatching(&nat_policy_stopped_); |
| 128 nat_policy_stopped_.Wait(); | 108 nat_policy_stopped_.Wait(); |
| 129 nat_policy_.reset(); | 109 nat_policy_.reset(); |
| 130 } | 110 } |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 } else { | 248 } else { |
| 269 SetException("SetProperty: unexpected type for property " + | 249 SetException("SetProperty: unexpected type for property " + |
| 270 property_name); | 250 property_name); |
| 271 } | 251 } |
| 272 return false; | 252 return false; |
| 273 } | 253 } |
| 274 | 254 |
| 275 if (property_name == kAttrNameLogDebugInfo) { | 255 if (property_name == kAttrNameLogDebugInfo) { |
| 276 if (NPVARIANT_IS_OBJECT(*value)) { | 256 if (NPVARIANT_IS_OBJECT(*value)) { |
| 277 log_debug_info_func_ = NPVARIANT_TO_OBJECT(*value); | 257 log_debug_info_func_ = NPVARIANT_TO_OBJECT(*value); |
| 258 HostLogHandler::RegisterLoggingScriptObject(this); |
| 278 return true; | 259 return true; |
| 279 } else { | 260 } else { |
| 280 SetException("SetProperty: unexpected type for property " + | 261 SetException("SetProperty: unexpected type for property " + |
| 281 property_name); | 262 property_name); |
| 282 } | 263 } |
| 283 return false; | 264 return false; |
| 284 } | 265 } |
| 285 | 266 |
| 286 return false; | 267 return false; |
| 287 } | 268 } |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 return; | 585 return; |
| 605 } | 586 } |
| 606 state_ = state; | 587 state_ = state; |
| 607 if (on_state_changed_func_.get()) { | 588 if (on_state_changed_func_.get()) { |
| 608 VLOG(2) << "Calling state changed " << state; | 589 VLOG(2) << "Calling state changed " << state; |
| 609 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_.get(), NULL, 0); | 590 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_.get(), NULL, 0); |
| 610 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; | 591 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
| 611 } | 592 } |
| 612 } | 593 } |
| 613 | 594 |
| 614 // static | 595 void HostNPScriptObject::PostLogDebugInfo(const std::string& message) { |
| 615 bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, | 596 if (plugin_message_loop_proxy_->BelongsToCurrentThread()) { |
| 616 size_t message_start, | 597 // Make sure we're not currently processing a log message. |
| 617 const std::string& str) { | 598 // We only need to check this if we're on the plugin thread. |
| 618 // The |g_logging_to_plugin| check is to prevent logging to the scriptable | 599 if (am_currently_logging_) |
| 619 // object if we're already in the middle of logging. | 600 return; |
| 620 // This can occur if we try to log an error while we're in the scriptable | |
| 621 // object logging code. | |
| 622 if (g_logging_scriptable_object && !g_logging_to_plugin) { | |
| 623 g_logging_to_plugin = true; | |
| 624 std::string message = remoting::GetTimestampString(); | |
| 625 message += (str.c_str() + message_start); | |
| 626 g_logging_scriptable_object->LogDebugInfo(message); | |
| 627 g_logging_to_plugin = false; | |
| 628 } | 601 } |
| 629 if (g_logging_old_handler) | 602 |
| 630 return (g_logging_old_handler)(severity, file, line, message_start, str); | 603 // Always post (even if we're already on the correct thread) so that debug |
| 631 return false; | 604 // log messages are shown in the correct order. |
| 605 plugin_message_loop_proxy_->PostTask( |
| 606 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, |
| 607 base::Unretained(this), message)); |
| 632 } | 608 } |
| 633 | 609 |
| 634 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | 610 void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
| 635 if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { | |
| 636 plugin_message_loop_proxy_->PostTask( | |
| 637 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, | |
| 638 base::Unretained(this), message)); | |
| 639 return; | |
| 640 } | |
| 641 | |
| 642 if (log_debug_info_func_.get()) { | 611 if (log_debug_info_func_.get()) { |
| 612 am_currently_logging_ = true; |
| 643 NPVariant log_message; | 613 NPVariant log_message; |
| 644 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); | 614 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); |
| 645 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), | 615 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), |
| 646 &log_message, 1); | 616 &log_message, 1); |
| 647 LOG_IF(ERROR, !is_good) << "LogDebugInfo failed"; | 617 if (!is_good) { |
| 618 LOG(ERROR) << "ERROR - LogDebugInfo failed\n"; |
| 619 } |
| 620 am_currently_logging_ = false; |
| 648 } | 621 } |
| 649 } | 622 } |
| 650 | 623 |
| 651 void HostNPScriptObject::SetException(const std::string& exception_string) { | 624 void HostNPScriptObject::SetException(const std::string& exception_string) { |
| 652 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 625 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
| 653 g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); | 626 g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); |
| 654 LOG(INFO) << exception_string; | 627 LOG(INFO) << exception_string; |
| 655 } | 628 } |
| 656 | 629 |
| 657 void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) { | 630 void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 uint32_t argCount) { | 687 uint32_t argCount) { |
| 715 NPVariant np_result; | 688 NPVariant np_result; |
| 716 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, | 689 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, |
| 717 argCount, &np_result); | 690 argCount, &np_result); |
| 718 if (is_good) | 691 if (is_good) |
| 719 g_npnetscape_funcs->releasevariantvalue(&np_result); | 692 g_npnetscape_funcs->releasevariantvalue(&np_result); |
| 720 return is_good; | 693 return is_good; |
| 721 } | 694 } |
| 722 | 695 |
| 723 } // namespace remoting | 696 } // namespace remoting |
| OLD | NEW |