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 |