blob: aa972b59623c8382ef58d9d3aad0340965634751 [file] [log] [blame]
// 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 <map>
#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<PP_Instance, HostDispatcher*> 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<const PPB_Var_Deprecated*>(
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<InterfaceID>(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<int>(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<int>(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<const PPB_Proxy_Private*>(
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