diff options
-rw-r--r-- | content/renderer/pepper_plugin_delegate_impl.cc | 13 | ||||
-rw-r--r-- | ppapi/tests/test_query_policy.cc | 2 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.cc | 150 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.h | 37 | ||||
-rw-r--r-- | remoting/protocol/connection_to_host.cc | 6 |
5 files changed, 171 insertions, 37 deletions
diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc index dbeddbd..2ce1076 100644 --- a/content/renderer/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper_plugin_delegate_impl.cc @@ -1324,16 +1324,9 @@ void PepperPluginDelegateImpl::SubscribeToPolicyUpdates( webkit::ppapi::PluginInstance* instance) { subscribed_to_policy_updates_.insert(instance); - // Call by the PPP interface via continuation to avoid reentry issues - // with being in the call chain that includes SubscribeToPolicyUpdates(). - // - // TODO(ajwong): Hook this up into something that gets a real policy. - MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PepperPluginDelegateImpl::PublishInitialPolicy, - AsWeakPtr(), - make_scoped_refptr(instance), - "{\"test_policy\": \"i like bananas\"}")); + // TODO(ajwong): Make this only send an update to the current instance, + // and not all subscribed plugin instances. + render_view_->RequestRemoteAccessClientFirewallTraversal(); } std::string PepperPluginDelegateImpl::ResolveProxy(const GURL& url) { diff --git a/ppapi/tests/test_query_policy.cc b/ppapi/tests/test_query_policy.cc index 269a57c..6e8b4cb 100644 --- a/ppapi/tests/test_query_policy.cc +++ b/ppapi/tests/test_query_policy.cc @@ -50,7 +50,7 @@ std::string TestQueryPolicy::TestSubscribeToPolicyUpdates() { // Wait for a response on PPP_PolicyUpdate_Dev. GetTestingInterface()->RunMessageLoop(instance_->pp_instance()); - ASSERT_TRUE(g_received_policy == "{\"test_policy\": \"i like bananas\"}"); + ASSERT_FALSE(g_received_policy.empty()); PASS(); } diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 7ec07a4..a9c1c1e 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -8,17 +8,20 @@ #include <vector> #include "base/bind.h" +#include "base/json/json_reader.h" #include "base/logging.h" #include "base/message_loop.h" #include "base/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/task.h" #include "base/threading/thread.h" +#include "base/values.h" // TODO(sergeyu): We should not depend on renderer here. Instead P2P // Pepper API should be used. Remove this dependency. // crbug.com/74951 #include "content/renderer/p2p/ipc_network_manager.h" #include "content/renderer/p2p/ipc_socket_factory.h" +#include "ppapi/c/dev/ppb_query_policy_dev.h" #include "ppapi/cpp/completion_callback.h" #include "ppapi/cpp/input_event.h" #include "ppapi/cpp/rect.h" @@ -49,13 +52,27 @@ namespace remoting { +namespace { + +const char kClientFirewallTraversalPolicyName[] = + "remote_access.client_firewall_traversal"; + +} // namespace + +PPP_PolicyUpdate_Dev ChromotingInstance::kPolicyUpdatedInterface = { + &ChromotingInstance::PolicyUpdatedThunk, +}; + const char* ChromotingInstance::kMimeType = "pepper-application/x-chromoting"; ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) : pp::InstancePrivate(pp_instance), initialized_(false), scale_to_fit_(false), - logger_(this) { + logger_(this), + enable_client_nat_traversal_(false), + initial_policy_received_(false), + task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); } @@ -88,11 +105,41 @@ bool ChromotingInstance::Init(uint32_t argc, // Start all the threads. context_.Start(); + SubscribeToNatTraversalPolicy(); + + // Create the chromoting objects that don't depend on the network connection. + view_.reset(new PepperView(this, &context_)); + view_proxy_ = new PepperViewProxy(this, view_.get()); + rectangle_decoder_ = new RectangleUpdateDecoder( + context_.decode_message_loop(), view_proxy_); + + // Default to a medium grey. + view_->SetSolidFill(0xFFCDCDCD); + + return true; +} + +void ChromotingInstance::Connect(const ClientConfig& config) { + DCHECK(CurrentlyOnPluginThread()); + + // This can only happen at initialization if the Javascript connect call + // occurs before the enterprise policy is read. We are guaranteed that the + // enterprise policy is pushed at least once, we we delay the connect call. + if (!initial_policy_received_) { + logger_.Log(logging::LOG_INFO, + "Delaying connect until initial policy is read."); + delayed_connect_.reset( + task_factory_.NewRunnableMethod(&ChromotingInstance::Connect, + config)); + return; + } + webkit::ppapi::PluginInstance* plugin_instance = webkit::ppapi::ResourceTracker::Get()->GetInstance(pp_instance()); P2PSocketDispatcher* socket_dispatcher = plugin_instance->delegate()->GetP2PSocketDispatcher(); + IpcNetworkManager* network_manager = NULL; IpcPacketSocketFactory* socket_factory = NULL; PortAllocatorSessionFactory* session_factory = @@ -106,28 +153,13 @@ bool ChromotingInstance::Init(uint32_t argc, socket_factory = new IpcPacketSocketFactory(socket_dispatcher); } - // Create the chromoting objects. - // TODO(sergeyu): Use firewall traversal policy settings here. host_connection_.reset(new protocol::ConnectionToHost( context_.network_message_loop(), network_manager, socket_factory, - session_factory, false)); - view_.reset(new PepperView(this, &context_)); - view_proxy_ = new PepperViewProxy(this, view_.get()); - rectangle_decoder_ = new RectangleUpdateDecoder( - context_.decode_message_loop(), view_proxy_); + session_factory, enable_client_nat_traversal_)); input_handler_.reset(new PepperInputHandler(&context_, host_connection_.get(), view_proxy_)); - // Default to a medium grey. - view_->SetSolidFill(0xFFCDCDCD); - - return true; -} - -void ChromotingInstance::Connect(const ClientConfig& config) { - DCHECK(CurrentlyOnPluginThread()); - client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), view_proxy_, rectangle_decoder_.get(), input_handler_.get(), &logger_, NULL)); @@ -159,8 +191,12 @@ void ChromotingInstance::Disconnect() { client_->Stop(base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event))); done_event.Wait(); + client_.reset(); } + input_handler_.reset(); + host_connection_.reset(); + GetScriptableObject()->SetConnectionInfo(STATUS_CLOSED, QUALITY_UNKNOWN); } @@ -189,6 +225,9 @@ void ChromotingInstance::DidChangeView(const pp::Rect& position, bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { DCHECK(CurrentlyOnPluginThread()); + if (!input_handler_.get()) { + return false; + } PepperInputHandler* pih = static_cast<PepperInputHandler*>(input_handler_.get()); @@ -326,7 +365,84 @@ ChromotingStats* ChromotingInstance::GetStats() { } void ChromotingInstance::ReleaseAllKeys() { + if (!input_handler_.get()) { + return; + } + input_handler_->ReleaseAllKeys(); } +// static +void ChromotingInstance::PolicyUpdatedThunk(PP_Instance pp_instance, + PP_Var pp_policy_json) { + ChromotingInstance* instance = static_cast<ChromotingInstance*>( + pp::Module::Get()->InstanceForPPInstance(pp_instance)); + std::string policy_json = + pp::Var(pp::Var::DontManage(), pp_policy_json).AsString(); + instance->HandlePolicyUpdate(policy_json); +} + +void ChromotingInstance::SubscribeToNatTraversalPolicy() { + pp::Module::Get()->AddPluginInterface(PPP_POLICY_UPDATE_DEV_INTERFACE, + &kPolicyUpdatedInterface); + const PPB_QueryPolicy_Dev* query_policy_interface = + static_cast<PPB_QueryPolicy_Dev const*>( + pp::Module::Get()->GetBrowserInterface( + PPB_QUERY_POLICY_DEV_INTERFACE)); + query_policy_interface->SubscribeToPolicyUpdates(pp_instance()); +} + +bool ChromotingInstance::IsNatTraversalAllowed( + const std::string& policy_json) { + int error_code = base::JSONReader::JSON_NO_ERROR; + std::string error_message; + scoped_ptr<base::Value> policy(base::JSONReader::ReadAndReturnError( + policy_json, true, &error_code, &error_message)); + + if (!policy.get()) { + logger_.Log(logging::LOG_ERROR, "Error %d parsing policy: %s.", + error_code, error_message.c_str()); + return false; + } + + if (!policy->IsType(base::Value::TYPE_DICTIONARY)) { + logger_.Log(logging::LOG_ERROR, "Policy must be a dictionary"); + return false; + } + + base::DictionaryValue* dictionary = + static_cast<base::DictionaryValue*>(policy.get()); + bool traversal_policy = false; + if (!dictionary->GetBoolean(kClientFirewallTraversalPolicyName, + &traversal_policy)) { + // Disable NAT traversal on any failure of reading the policy. + return false; + } + + return traversal_policy; +} + +void ChromotingInstance::HandlePolicyUpdate(const std::string policy_json) { + DCHECK(CurrentlyOnPluginThread()); + bool traversal_policy = IsNatTraversalAllowed(policy_json); + + // If the policy changes from traversal allowed, to traversal denied, we + // need to immediately drop all connections and redo the conneciton + // preparation. + if (traversal_policy == false && + traversal_policy != enable_client_nat_traversal_) { + if (client_.get()) { + // This will delete the client and network related objects. + Disconnect(); + } + } + + initial_policy_received_ = true; + enable_client_nat_traversal_ = traversal_policy; + + if (delayed_connect_.get()) { + RunTaskOnPluginThread(delayed_connect_.release()); + } +} + } // namespace remoting diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index 838f9e9..787713a 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -12,9 +12,11 @@ #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" +#include "ppapi/c/dev/ppp_policy_update_dev.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_rect.h" #include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/private/instance_private.h" #include "remoting/client/client_context.h" @@ -62,19 +64,23 @@ class ChromotingInstance : public pp::InstancePrivate { explicit ChromotingInstance(PP_Instance instance); virtual ~ChromotingInstance(); - virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); - virtual void Connect(const ClientConfig& config); - virtual bool HandleInputEvent(const pp::InputEvent& event); - virtual void Disconnect(); - virtual pp::Var GetInstanceObject(); - // pp::Instance interface. virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) OVERRIDE; + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) + OVERRIDE; + virtual bool HandleInputEvent(const pp::InputEvent& event) OVERRIDE; + + // pp::InstancePrivate interface. + virtual pp::Var GetInstanceObject() OVERRIDE; // Convenience wrapper to get the ChromotingScriptableObject. ChromotingScriptableObject* GetScriptableObject(); + // Initiates and cancels connections. + void Connect(const ClientConfig& config); + void Disconnect(); + // Called by ChromotingScriptableObject to provide username and password. void SubmitLoginInfo(const std::string& username, const std::string& password); @@ -96,6 +102,13 @@ class ChromotingInstance : public pp::InstancePrivate { private: FRIEND_TEST_ALL_PREFIXES(ChromotingInstanceTest, TestCaseSetup); + static PPP_PolicyUpdate_Dev kPolicyUpdatedInterface; + static void PolicyUpdatedThunk(PP_Instance pp_instance, + PP_Var pp_policy_json); + void SubscribeToNatTraversalPolicy(); + bool IsNatTraversalAllowed(const std::string& policy_json); + void HandlePolicyUpdate(const std::string policy_json); + bool initialized_; ClientContext context_; @@ -129,6 +142,18 @@ class ChromotingInstance : public pp::InstancePrivate { // This wraps a ChromotingScriptableObject in a pp::Var. pp::Var instance_object_; + // Controls if this instance of the plugin should attempt to bridge + // firewalls. + bool enable_client_nat_traversal_; + + // True when the initial policy is received. Used to avoid taking + // action before the browser has informed the plugin about its policy + // settings. + bool initial_policy_received_; + + ScopedRunnableMethodFactory<ChromotingInstance> task_factory_; + scoped_ptr<Task> delayed_connect_; + DISALLOW_COPY_AND_ASSIGN(ChromotingInstance); }; diff --git a/remoting/protocol/connection_to_host.cc b/remoting/protocol/connection_to_host.cc index fe75cfe..580f198 100644 --- a/remoting/protocol/connection_to_host.cc +++ b/remoting/protocol/connection_to_host.cc @@ -115,9 +115,6 @@ void ConnectionToHost::InitSession() { session_manager_.reset(session_manager); session_manager_->Init( local_jid_, signal_strategy_.get(), this, NULL, "", allow_nat_traversal_); - - // Set the shared-secret for securing SSL channels. - session_->set_shared_secret(access_code_); } const SessionConfig* ConnectionToHost::config() { @@ -154,6 +151,9 @@ void ConnectionToHost::OnSessionManagerInitialized() { session_.reset(session_manager_->Connect( host_jid_, host_public_key_, client_token, candidate_config, NewCallback(this, &ConnectionToHost::OnSessionStateChange))); + + // Set the shared-secret for securing SSL channels. + session_->set_shared_secret(access_code_); } void ConnectionToHost::OnIncomingSession( |