OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ppapi/proxy/dispatcher.h" |
| 6 |
| 7 #include <string.h> // For memset. |
| 8 |
| 9 #include <map> |
| 10 |
| 11 #include "base/logging.h" |
| 12 #include "ipc/ipc_message.h" |
| 13 #include "ipc/ipc_sync_channel.h" |
| 14 #include "ppapi/proxy/interface_proxy.h" |
| 15 #include "ppapi/proxy/ppapi_messages.h" |
| 16 #include "ppapi/c/dev/ppb_var_deprecated.h" |
| 17 #include "ppapi/c/pp_errors.h" |
| 18 #include "ppapi/c/ppb_core.h" |
| 19 #include "ppapi/c/ppb_graphics_2d.h" |
| 20 #include "ppapi/c/ppb_image_data.h" |
| 21 #include "ppapi/c/ppb_instance.h" |
| 22 #include "ppapi/c/ppp_instance.h" |
| 23 #include "ppapi/proxy/browser_var_serialization.h" |
| 24 #include "ppapi/proxy/plugin_var_serialization.h" |
| 25 #include "ppapi/proxy/ppb_core_proxy.h" |
| 26 #include "ppapi/proxy/ppb_graphics_2d_proxy.h" |
| 27 #include "ppapi/proxy/ppb_image_data_proxy.h" |
| 28 #include "ppapi/proxy/ppb_instance_proxy.h" |
| 29 #include "ppapi/proxy/ppb_var_deprecated_proxy.h" |
| 30 #include "ppapi/proxy/ppp_class_proxy.h" |
| 31 #include "ppapi/proxy/ppp_instance_proxy.h" |
| 32 |
| 33 namespace pp { |
| 34 namespace proxy { |
| 35 |
| 36 Dispatcher::Dispatcher(GetInterfaceFunc local_get_interface) |
| 37 : pp_module_(0), |
| 38 disallow_trusted_interfaces_(true), |
| 39 local_get_interface_(local_get_interface), |
| 40 declared_supported_remote_interfaces_(false), |
| 41 callback_tracker_(this) { |
| 42 memset(id_to_proxy_, 0, |
| 43 static_cast<int>(INTERFACE_ID_COUNT) * sizeof(InterfaceProxy*)); |
| 44 } |
| 45 |
| 46 Dispatcher::~Dispatcher() { |
| 47 } |
| 48 |
| 49 bool Dispatcher::InitWithChannel(MessageLoop* ipc_message_loop, |
| 50 const std::string& channel_name, |
| 51 bool is_client, |
| 52 base::WaitableEvent* shutdown_event) { |
| 53 IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT |
| 54 : IPC::Channel::MODE_SERVER; |
| 55 channel_.reset(new IPC::SyncChannel(channel_name, mode, this, NULL, |
| 56 ipc_message_loop, false, shutdown_event)); |
| 57 return true; |
| 58 } |
| 59 |
| 60 void Dispatcher::OnMessageReceived(const IPC::Message& msg) { |
| 61 // Control messages. |
| 62 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 63 IPC_BEGIN_MESSAGE_MAP(Dispatcher, msg) |
| 64 IPC_MESSAGE_HANDLER(PpapiMsg_DeclareInterfaces, |
| 65 OnMsgDeclareInterfaces) |
| 66 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) |
| 67 IPC_MESSAGE_FORWARD(PpapiMsg_ExecuteCallback, &callback_tracker_, |
| 68 CallbackTracker::ReceiveExecuteSerializedCallback) |
| 69 IPC_END_MESSAGE_MAP() |
| 70 return; |
| 71 } |
| 72 |
| 73 // Interface-specific messages. |
| 74 if (msg.routing_id() > 0 && msg.routing_id() < INTERFACE_ID_COUNT) { |
| 75 InterfaceProxy* proxy = id_to_proxy_[msg.routing_id()]; |
| 76 if (proxy) |
| 77 proxy->OnMessageReceived(msg); |
| 78 else |
| 79 NOTREACHED(); |
| 80 // TODO(brettw): kill the plugin if it starts sending invalid messages? |
| 81 } |
| 82 } |
| 83 |
| 84 void Dispatcher::SetSerialization(VarSerialization* var_serialization) { |
| 85 serialization_.reset(var_serialization); |
| 86 } |
| 87 |
| 88 void Dispatcher::InjectProxy(InterfaceID id, |
| 89 const std::string& name, |
| 90 InterfaceProxy* proxy) { |
| 91 proxies_[name] = linked_ptr<InterfaceProxy>(proxy); |
| 92 id_to_proxy_[id] = proxy; |
| 93 } |
| 94 |
| 95 const void* Dispatcher::GetLocalInterface(const char* interface) { |
| 96 return local_get_interface_(interface); |
| 97 } |
| 98 |
| 99 const void* Dispatcher::GetProxiedInterface(const std::string& interface) { |
| 100 // See if we already know about this interface and have created a host. |
| 101 ProxyMap::const_iterator found = proxies_.find(interface); |
| 102 if (found != proxies_.end()) |
| 103 return found->second->GetSourceInterface(); |
| 104 |
| 105 // When the remote side has sent us a declared list of all interfaces it |
| 106 // supports and we don't have it in our list, we know the requested interface |
| 107 // doesn't exist and we can return failure. |
| 108 if (declared_supported_remote_interfaces_) |
| 109 return NULL; |
| 110 |
| 111 if (!RemoteSupportsTargetInterface(interface)) |
| 112 return NULL; |
| 113 |
| 114 linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interface, NULL)); |
| 115 if (!proxy.get()) |
| 116 return NULL; // Don't know how to proxy this interface. |
| 117 |
| 118 // Save our proxy. |
| 119 proxies_[interface] = proxy; |
| 120 id_to_proxy_[proxy->GetInterfaceId()] = proxy.get(); |
| 121 return proxy->GetSourceInterface(); |
| 122 } |
| 123 |
| 124 bool Dispatcher::Send(IPC::Message* msg) { |
| 125 return channel_->Send(msg); |
| 126 } |
| 127 |
| 128 bool Dispatcher::RemoteSupportsTargetInterface(const std::string& interface) { |
| 129 bool result = false; |
| 130 Send(new PpapiMsg_SupportsInterface(interface, &result)); |
| 131 return result; |
| 132 } |
| 133 |
| 134 bool Dispatcher::IsInterfaceTrusted(const std::string& interface) { |
| 135 // FIXME(brettw) |
| 136 (void)interface; |
| 137 return false; |
| 138 } |
| 139 |
| 140 bool Dispatcher::SetupProxyForTargetInterface(const std::string& interface) { |
| 141 // If we already have a proxy that knows about the locally-implemented |
| 142 // interface, we know it's supported and don't need to re-query. |
| 143 ProxyMap::const_iterator found = proxies_.find(interface); |
| 144 if (found != proxies_.end()) |
| 145 return true; |
| 146 |
| 147 if (disallow_trusted_interfaces_ && IsInterfaceTrusted(interface)) |
| 148 return false; |
| 149 |
| 150 // Create the proxy if it doesn't exist and set the local interface on it. |
| 151 // This also handles the case where possibly an interface could be supported |
| 152 // by both the local and remote side. |
| 153 const void* interface_functions = local_get_interface_(interface.c_str()); |
| 154 if (!interface_functions) |
| 155 return false; |
| 156 InterfaceProxy* proxy = CreateProxyForInterface(interface, |
| 157 interface_functions); |
| 158 if (!proxy) |
| 159 return false; |
| 160 |
| 161 proxies_[interface] = linked_ptr<InterfaceProxy>(proxy); |
| 162 id_to_proxy_[proxy->GetInterfaceId()] = proxy; |
| 163 return true; |
| 164 } |
| 165 |
| 166 void Dispatcher::OnMsgSupportsInterface(const std::string& interface_name, |
| 167 bool* result) { |
| 168 *result = SetupProxyForTargetInterface(interface_name); |
| 169 } |
| 170 |
| 171 void Dispatcher::OnMsgDeclareInterfaces( |
| 172 const std::vector<std::string>& interfaces) { |
| 173 // Make proxies for all the interfaces it supports that we also support. |
| 174 for (size_t i = 0; i < interfaces.size(); i++) { |
| 175 // Possibly the plugin could request an interface before the "declare" |
| 176 // message is received, so we could already have an entry for this |
| 177 // interface. In this case, we can just skip to the next one. |
| 178 if (proxies_.find(interfaces[i]) != proxies_.end()) |
| 179 continue; |
| 180 |
| 181 linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interfaces[i], |
| 182 NULL)); |
| 183 if (!proxy.get()) { |
| 184 // Since only the browser declares supported interfaces, we should never |
| 185 // get one we don't support. |
| 186 //NOTREACHED() << "Remote side declaring an unsupported proxy."; |
| 187 continue; |
| 188 } |
| 189 proxies_[interfaces[i]] = proxy; |
| 190 id_to_proxy_[proxy->GetInterfaceId()] = proxy.get(); |
| 191 } |
| 192 } |
| 193 |
| 194 InterfaceProxy* Dispatcher::CreateProxyForInterface( |
| 195 const std::string& interface_name, |
| 196 const void* interface_functions) { |
| 197 if (interface_name == PPB_CORE_INTERFACE) |
| 198 return new PPB_Core_Proxy(this, interface_functions); |
| 199 if (interface_name == PPB_GRAPHICS_2D_INTERFACE) |
| 200 return new PPB_Graphics2D_Proxy(this, interface_functions); |
| 201 if (interface_name == PPB_IMAGEDATA_INTERFACE) |
| 202 return new PPB_ImageData_Proxy(this, interface_functions); |
| 203 if (interface_name == PPB_INSTANCE_INTERFACE) |
| 204 return new PPB_Instance_Proxy(this, interface_functions); |
| 205 if (interface_name == PPB_VAR_DEPRECATED_INTERFACE) |
| 206 return new PPB_Var_Deprecated_Proxy(this, interface_functions); |
| 207 if (interface_name == PPP_INSTANCE_INTERFACE) |
| 208 return new PPP_Instance_Proxy(this, interface_functions); |
| 209 |
| 210 return NULL; |
| 211 } |
| 212 |
| 213 } // namespace proxy |
| 214 } // namespace pp |
| 215 |
OLD | NEW |