summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/host_dispatcher.cc
blob: fce2b13ce55307c498a374fa71bdd14276b1867a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 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/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) {
  set_pp_module(module);
  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;

    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 true;
    }

    proxy = info->create_proxy(this, local_interface);
    target_proxies_[info->id].reset(proxy);
  }

  return proxy->OnMessageReceived(msg);
}

void HostDispatcher::OnChannelError() {
  // TODO(brettw) plugin has crashed, handle this.
}

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;
}

}  // namespace proxy
}  // namespace pp