// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ppapi/proxy/host_dispatcher.h" #include #include "base/logging.h" #include "ppapi/c/private/ppb_proxy_private.h" #include "ppapi/c/dev/ppb_var_deprecated.h" #include "ppapi/proxy/host_var_serialization_rules.h" #include "ppapi/proxy/ppapi_messages.h" namespace pp { namespace proxy { namespace { typedef std::map InstanceToDispatcherMap; InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; } // namespace HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, PP_Module module, GetInterfaceFunc local_get_interface) : Dispatcher(remote_process_handle, local_get_interface), pp_module_(module), ppb_proxy_(NULL) { const PPB_Var_Deprecated* var_interface = static_cast( local_get_interface(PPB_VAR_DEPRECATED_INTERFACE)); SetSerializationRules(new HostVarSerializationRules(var_interface, module)); memset(plugin_interface_support_, 0, sizeof(PluginInterfaceSupport) * INTERFACE_ID_COUNT); } HostDispatcher::~HostDispatcher() { } // static HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) { if (!g_instance_to_dispatcher) return NULL; InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( instance); if (found == g_instance_to_dispatcher->end()) return NULL; return found->second; } // static void HostDispatcher::SetForInstance(PP_Instance instance, HostDispatcher* dispatcher) { if (!g_instance_to_dispatcher) g_instance_to_dispatcher = new InstanceToDispatcherMap; (*g_instance_to_dispatcher)[instance] = dispatcher; } // static void HostDispatcher::RemoveForInstance(PP_Instance instance) { if (!g_instance_to_dispatcher) return; InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( instance); if (found != g_instance_to_dispatcher->end()) g_instance_to_dispatcher->erase(found); } bool HostDispatcher::IsPlugin() const { return false; } bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { // Handle common control messages. if (Dispatcher::OnMessageReceived(msg)) return true; if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) { NOTREACHED(); // TODO(brettw): kill the plugin if it starts sending invalid messages? return true; } InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); if (!proxy) { // Autocreate any proxy objects to handle requests from the plugin. Since // we always support all known PPB_* interfaces (modulo the trusted bit), // there's very little checking necessary. const InterfaceProxy::Info* info = GetPPBInterfaceInfo( static_cast(msg.routing_id())); if (!info || (info->is_trusted && disallow_trusted_interfaces())) return true; proxy = CreatePPBInterfaceProxy(info); } return proxy->OnMessageReceived(msg); } void HostDispatcher::OnChannelError() { Dispatcher::OnChannelError(); // Stop using the channel. // Tell the host about the crash so it can clean up. GetPPBProxy()->PluginCrashed(pp_module()); } const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { // First see if we even have a proxy for this interface. const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface); if (!info) return NULL; if (plugin_interface_support_[static_cast(info->id)] != INTERFACE_UNQUERIED) { // Already queried the plugin if it supports this interface. if (plugin_interface_support_[info->id] == INTERFACE_SUPPORTED) return info->interface; return NULL; } // Need to re-query. Cache the result so we only do this once. bool supported = false; Send(new PpapiMsg_SupportsInterface(interface, &supported)); plugin_interface_support_[static_cast(info->id)] = supported ? INTERFACE_SUPPORTED : INTERFACE_UNSUPPORTED; if (supported) return info->interface; return NULL; } InterfaceProxy* HostDispatcher::GetOrCreatePPBInterfaceProxy( InterfaceID id) { InterfaceProxy* proxy = target_proxies_[id].get(); if (!proxy) { const InterfaceProxy::Info* info = GetPPBInterfaceInfo(id); if (!info) return NULL; // Sanity check. This function won't normally be called for trusted // interfaces, but in case somebody does this, we don't want to then give // the plugin the ability to call that trusted interface (since the // checking occurs at proxy-creation time). if (info->is_trusted && disallow_trusted_interfaces()) return NULL; proxy = CreatePPBInterfaceProxy(info); } return proxy; } const PPB_Proxy_Private* HostDispatcher::GetPPBProxy() { if (!ppb_proxy_) { ppb_proxy_ = reinterpret_cast( GetLocalInterface(PPB_PROXY_PRIVATE_INTERFACE)); } return ppb_proxy_; } InterfaceProxy* HostDispatcher::CreatePPBInterfaceProxy( const InterfaceProxy::Info* info) { const void* local_interface = GetLocalInterface(info->name); if (!local_interface) { // This should always succeed since the browser should support the stuff // the proxy does. If this happens, something is out of sync. NOTREACHED(); return NULL; } InterfaceProxy* proxy = info->create_proxy(this, local_interface); target_proxies_[info->id].reset(proxy); return proxy; } } // namespace proxy } // namespace pp