| 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/client/plugin/chromoting_instance.h" | 5 #include "remoting/client/plugin/chromoting_instance.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/json/json_reader.h" | |
| 12 #include "base/logging.h" | 11 #include "base/logging.h" |
| 13 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 14 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
| 15 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
| 16 #include "base/synchronization/waitable_event.h" | 15 #include "base/synchronization/waitable_event.h" |
| 17 #include "base/task.h" | 16 #include "base/task.h" |
| 18 #include "base/threading/thread.h" | 17 #include "base/threading/thread.h" |
| 19 #include "base/values.h" | |
| 20 #include "media/base/media.h" | 18 #include "media/base/media.h" |
| 21 #include "ppapi/c/dev/ppb_query_policy_dev.h" | |
| 22 #include "ppapi/cpp/completion_callback.h" | 19 #include "ppapi/cpp/completion_callback.h" |
| 23 #include "ppapi/cpp/input_event.h" | 20 #include "ppapi/cpp/input_event.h" |
| 24 #include "ppapi/cpp/rect.h" | 21 #include "ppapi/cpp/rect.h" |
| 25 // TODO(wez): Remove this when crbug.com/86353 is complete. | 22 // TODO(wez): Remove this when crbug.com/86353 is complete. |
| 26 #include "ppapi/cpp/private/var_private.h" | 23 #include "ppapi/cpp/private/var_private.h" |
| 27 #include "remoting/base/util.h" | 24 #include "remoting/base/util.h" |
| 28 #include "remoting/client/client_config.h" | 25 #include "remoting/client/client_config.h" |
| 29 #include "remoting/client/chromoting_client.h" | 26 #include "remoting/client/chromoting_client.h" |
| 30 #include "remoting/client/plugin/chromoting_scriptable_object.h" | 27 #include "remoting/client/plugin/chromoting_scriptable_object.h" |
| 31 #include "remoting/client/plugin/pepper_input_handler.h" | 28 #include "remoting/client/plugin/pepper_input_handler.h" |
| 32 #include "remoting/client/plugin/pepper_view.h" | 29 #include "remoting/client/plugin/pepper_view.h" |
| 33 #include "remoting/client/plugin/pepper_view_proxy.h" | 30 #include "remoting/client/plugin/pepper_view_proxy.h" |
| 34 #include "remoting/client/plugin/pepper_xmpp_proxy.h" | 31 #include "remoting/client/plugin/pepper_xmpp_proxy.h" |
| 35 #include "remoting/client/rectangle_update_decoder.h" | 32 #include "remoting/client/rectangle_update_decoder.h" |
| 36 #include "remoting/proto/auth.pb.h" | 33 #include "remoting/proto/auth.pb.h" |
| 37 #include "remoting/protocol/connection_to_host.h" | 34 #include "remoting/protocol/connection_to_host.h" |
| 38 #include "remoting/protocol/host_stub.h" | 35 #include "remoting/protocol/host_stub.h" |
| 39 | 36 |
| 40 namespace remoting { | 37 namespace remoting { |
| 41 | 38 |
| 42 namespace { | |
| 43 | |
| 44 const char kClientFirewallTraversalPolicyName[] = | |
| 45 "remote_access.client_firewall_traversal"; | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 PPP_PolicyUpdate_Dev ChromotingInstance::kPolicyUpdatedInterface = { | |
| 50 &ChromotingInstance::PolicyUpdatedThunk, | |
| 51 }; | |
| 52 | |
| 53 // This flag blocks LOGs to the UI if we're already in the middle of logging | 39 // This flag blocks LOGs to the UI if we're already in the middle of logging |
| 54 // to the UI. This prevents a potential infinite loop if we encounter an error | 40 // to the UI. This prevents a potential infinite loop if we encounter an error |
| 55 // while sending the log message to the UI. | 41 // while sending the log message to the UI. |
| 56 static bool g_logging_to_plugin = false; | 42 static bool g_logging_to_plugin = false; |
| 57 static bool g_has_logging_instance = false; | 43 static bool g_has_logging_instance = false; |
| 58 static base::Lock g_logging_lock; | 44 static base::Lock g_logging_lock; |
| 59 static ChromotingInstance* g_logging_instance = NULL; | 45 static ChromotingInstance* g_logging_instance = NULL; |
| 60 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 46 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
| 61 | 47 |
| 62 const char* ChromotingInstance::kMimeType = "pepper-application/x-chromoting"; | 48 const char* ChromotingInstance::kMimeType = "pepper-application/x-chromoting"; |
| 63 | 49 |
| 64 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) | 50 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
| 65 : pp::InstancePrivate(pp_instance), | 51 : pp::InstancePrivate(pp_instance), |
| 66 initialized_(false), | 52 initialized_(false), |
| 67 plugin_message_loop_( | 53 plugin_message_loop_( |
| 68 new PluginMessageLoopProxy(&plugin_thread_delegate_)), | 54 new PluginMessageLoopProxy(&plugin_thread_delegate_)), |
| 69 context_(plugin_message_loop_), | 55 context_(plugin_message_loop_), |
| 70 scale_to_fit_(false), | 56 scale_to_fit_(false), |
| 71 enable_client_nat_traversal_(false), | |
| 72 initial_policy_received_(false), | |
| 73 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { | 57 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { |
| 74 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); | 58 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
| 75 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 59 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
| 76 | 60 |
| 77 // Resister this instance to handle debug log messsages. | 61 // Resister this instance to handle debug log messsages. |
| 78 RegisterLoggingInstance(); | 62 RegisterLoggingInstance(); |
| 79 } | 63 } |
| 80 | 64 |
| 81 ChromotingInstance::~ChromotingInstance() { | 65 ChromotingInstance::~ChromotingInstance() { |
| 82 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 66 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 // Check to make sure the media library is initialized. | 106 // Check to make sure the media library is initialized. |
| 123 // http://crbug.com/91521. | 107 // http://crbug.com/91521. |
| 124 if (!media::IsMediaLibraryInitialized()) { | 108 if (!media::IsMediaLibraryInitialized()) { |
| 125 LOG(ERROR) << "Media library not initialized."; | 109 LOG(ERROR) << "Media library not initialized."; |
| 126 return false; | 110 return false; |
| 127 } | 111 } |
| 128 | 112 |
| 129 // Start all the threads. | 113 // Start all the threads. |
| 130 context_.Start(); | 114 context_.Start(); |
| 131 | 115 |
| 132 SubscribeToNatTraversalPolicy(); | |
| 133 | |
| 134 // Create the chromoting objects that don't depend on the network connection. | 116 // Create the chromoting objects that don't depend on the network connection. |
| 135 view_.reset(new PepperView(this, &context_)); | 117 view_.reset(new PepperView(this, &context_)); |
| 136 view_proxy_ = new PepperViewProxy(this, view_.get(), plugin_message_loop_); | 118 view_proxy_ = new PepperViewProxy(this, view_.get(), plugin_message_loop_); |
| 137 rectangle_decoder_ = new RectangleUpdateDecoder( | 119 rectangle_decoder_ = new RectangleUpdateDecoder( |
| 138 context_.decode_message_loop(), view_proxy_); | 120 context_.decode_message_loop(), view_proxy_); |
| 139 | 121 |
| 140 // Default to a medium grey. | 122 // Default to a medium grey. |
| 141 view_->SetSolidFill(0xFFCDCDCD); | 123 view_->SetSolidFill(0xFFCDCDCD); |
| 142 | 124 |
| 143 return true; | 125 return true; |
| 144 } | 126 } |
| 145 | 127 |
| 146 void ChromotingInstance::Connect(const ClientConfig& config) { | 128 void ChromotingInstance::Connect(const ClientConfig& config) { |
| 147 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 129 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
| 148 | 130 |
| 149 // This can only happen at initialization if the Javascript connect call | |
| 150 // occurs before the enterprise policy is read. We are guaranteed that the | |
| 151 // enterprise policy is pushed at least once, we we delay the connect call. | |
| 152 if (!initial_policy_received_) { | |
| 153 VLOG(1) << "Delaying connect until initial policy is read."; | |
| 154 // base::Unretained() is safe here because |delayed_connect_| is | |
| 155 // used only with |thread_proxy_|. | |
| 156 delayed_connect_ = base::Bind(&ChromotingInstance::Connect, | |
| 157 base::Unretained(this), config); | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 host_connection_.reset(new protocol::ConnectionToHost( | 131 host_connection_.reset(new protocol::ConnectionToHost( |
| 162 context_.network_message_loop(), this, enable_client_nat_traversal_)); | 132 context_.network_message_loop(), this, true)); |
| 163 | 133 |
| 164 input_handler_.reset(new PepperInputHandler(&context_, | 134 input_handler_.reset(new PepperInputHandler(&context_, |
| 165 host_connection_.get(), | 135 host_connection_.get(), |
| 166 view_proxy_)); | 136 view_proxy_)); |
| 167 | 137 |
| 168 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), | 138 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), |
| 169 view_proxy_, rectangle_decoder_.get(), | 139 view_proxy_, rectangle_decoder_.get(), |
| 170 input_handler_.get(), NULL)); | 140 input_handler_.get(), NULL)); |
| 171 | 141 |
| 172 LOG(INFO) << "Connecting to " << config.host_jid | 142 LOG(INFO) << "Connecting to " << config.host_jid |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 } | 419 } |
| 450 | 420 |
| 451 void ChromotingInstance::ReleaseAllKeys() { | 421 void ChromotingInstance::ReleaseAllKeys() { |
| 452 if (!input_handler_.get()) { | 422 if (!input_handler_.get()) { |
| 453 return; | 423 return; |
| 454 } | 424 } |
| 455 | 425 |
| 456 input_handler_->ReleaseAllKeys(); | 426 input_handler_->ReleaseAllKeys(); |
| 457 } | 427 } |
| 458 | 428 |
| 459 // static | |
| 460 void ChromotingInstance::PolicyUpdatedThunk(PP_Instance pp_instance, | |
| 461 PP_Var pp_policy_json) { | |
| 462 ChromotingInstance* instance = static_cast<ChromotingInstance*>( | |
| 463 pp::Module::Get()->InstanceForPPInstance(pp_instance)); | |
| 464 std::string policy_json = | |
| 465 pp::Var(pp::Var::DontManage(), pp_policy_json).AsString(); | |
| 466 instance->HandlePolicyUpdate(policy_json); | |
| 467 } | |
| 468 | |
| 469 void ChromotingInstance::SubscribeToNatTraversalPolicy() { | |
| 470 pp::Module::Get()->AddPluginInterface(PPP_POLICYUPDATE_DEV_INTERFACE, | |
| 471 &kPolicyUpdatedInterface); | |
| 472 const PPB_QueryPolicy_Dev* query_policy_interface = | |
| 473 static_cast<PPB_QueryPolicy_Dev const*>( | |
| 474 pp::Module::Get()->GetBrowserInterface( | |
| 475 PPB_QUERYPOLICY_DEV_INTERFACE)); | |
| 476 query_policy_interface->SubscribeToPolicyUpdates(pp_instance()); | |
| 477 } | |
| 478 | |
| 479 bool ChromotingInstance::IsNatTraversalAllowed( | |
| 480 const std::string& policy_json) { | |
| 481 int error_code = base::JSONReader::JSON_NO_ERROR; | |
| 482 std::string error_message; | |
| 483 scoped_ptr<base::Value> policy(base::JSONReader::ReadAndReturnError( | |
| 484 policy_json, true, &error_code, &error_message)); | |
| 485 | |
| 486 if (!policy.get()) { | |
| 487 LOG(ERROR) << "Error " << error_code << " parsing policy: " | |
| 488 << error_message << "."; | |
| 489 return false; | |
| 490 } | |
| 491 | |
| 492 if (!policy->IsType(base::Value::TYPE_DICTIONARY)) { | |
| 493 LOG(ERROR) << "Policy must be a dictionary"; | |
| 494 return false; | |
| 495 } | |
| 496 | |
| 497 base::DictionaryValue* dictionary = | |
| 498 static_cast<base::DictionaryValue*>(policy.get()); | |
| 499 bool traversal_policy = false; | |
| 500 if (!dictionary->GetBoolean(kClientFirewallTraversalPolicyName, | |
| 501 &traversal_policy)) { | |
| 502 // Disable NAT traversal on any failure of reading the policy. | |
| 503 return false; | |
| 504 } | |
| 505 | |
| 506 return traversal_policy; | |
| 507 } | |
| 508 | |
| 509 void ChromotingInstance::HandlePolicyUpdate(const std::string policy_json) { | |
| 510 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | |
| 511 bool traversal_policy = IsNatTraversalAllowed(policy_json); | |
| 512 | |
| 513 // If the policy changes from traversal allowed, to traversal denied, we | |
| 514 // need to immediately drop all connections and redo the conneciton | |
| 515 // preparation. | |
| 516 if (traversal_policy == false && | |
| 517 traversal_policy != enable_client_nat_traversal_) { | |
| 518 if (client_.get()) { | |
| 519 // This will delete the client and network related objects. | |
| 520 Disconnect(); | |
| 521 } | |
| 522 } | |
| 523 | |
| 524 initial_policy_received_ = true; | |
| 525 enable_client_nat_traversal_ = traversal_policy; | |
| 526 | |
| 527 if (!delayed_connect_.is_null()) { | |
| 528 thread_proxy_->PostTask(FROM_HERE, delayed_connect_); | |
| 529 delayed_connect_.Reset(); | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 } // namespace remoting | 429 } // namespace remoting |
| OLD | NEW |