Assume the foo_test_run depends on everything needed to run the test.
[chromium-blink-merge.git] / content / renderer / pepper / pepper_broker.cc
blob0d23de13b8663772eb4a5230afdac8fc5d13a8b9
1 // Copyright (c) 2012 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.
5 #include "content/renderer/pepper/pepper_broker.h"
7 #include "build/build_config.h"
8 #include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h"
9 #include "content/renderer/pepper/plugin_module.h"
10 #include "content/renderer/pepper/ppb_broker_impl.h"
11 #include "content/renderer/pepper/renderer_restrict_dispatch_group.h"
12 #include "ipc/ipc_channel_handle.h"
13 #include "ppapi/proxy/broker_dispatcher.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/shared_impl/platform_file.h"
17 #if defined(OS_WIN)
18 #include <windows.h>
19 #endif
21 namespace content {
23 namespace {
25 base::SyncSocket::Handle DuplicateHandle(base::SyncSocket::Handle handle) {
26 base::SyncSocket::Handle out_handle = base::kInvalidPlatformFileValue;
27 #if defined(OS_WIN)
28 DWORD options = DUPLICATE_SAME_ACCESS;
29 if (!::DuplicateHandle(::GetCurrentProcess(),
30 handle,
31 ::GetCurrentProcess(),
32 &out_handle,
34 FALSE,
35 options)) {
36 out_handle = base::kInvalidPlatformFileValue;
38 #elif defined(OS_POSIX)
39 // If asked to close the source, we can simply re-use the source fd instead of
40 // dup()ing and close()ing.
41 out_handle = ::dup(handle);
42 #else
43 #error Not implemented.
44 #endif
45 return out_handle;
48 } // namespace
50 PepperBrokerDispatcherWrapper::PepperBrokerDispatcherWrapper() {}
52 PepperBrokerDispatcherWrapper::~PepperBrokerDispatcherWrapper() {}
54 bool PepperBrokerDispatcherWrapper::Init(
55 base::ProcessId broker_pid,
56 const IPC::ChannelHandle& channel_handle) {
57 if (channel_handle.name.empty())
58 return false;
60 #if defined(OS_POSIX)
61 DCHECK_NE(-1, channel_handle.socket.fd);
62 if (channel_handle.socket.fd == -1)
63 return false;
64 #endif
66 dispatcher_delegate_.reset(new PepperProxyChannelDelegateImpl);
67 dispatcher_.reset(new ppapi::proxy::BrokerHostDispatcher());
69 if (!dispatcher_->InitBrokerWithChannel(dispatcher_delegate_.get(),
70 broker_pid,
71 channel_handle,
72 true)) { // Client.
73 dispatcher_.reset();
74 dispatcher_delegate_.reset();
75 return false;
77 dispatcher_->channel()->SetRestrictDispatchChannelGroup(
78 kRendererRestrictDispatchGroup_Pepper);
79 return true;
82 // Does not take ownership of the local pipe.
83 int32_t PepperBrokerDispatcherWrapper::SendHandleToBroker(
84 PP_Instance instance,
85 base::SyncSocket::Handle handle) {
86 IPC::PlatformFileForTransit foreign_socket_handle =
87 dispatcher_->ShareHandleWithRemote(handle, false);
88 if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
89 return PP_ERROR_FAILED;
91 int32_t result;
92 if (!dispatcher_->Send(new PpapiMsg_ConnectToPlugin(
93 instance, foreign_socket_handle, &result))) {
94 // The plugin did not receive the handle, so it must be closed.
95 // The easiest way to clean it up is to just put it in an object
96 // and then close it. This failure case is not performance critical.
97 // The handle could still leak if Send succeeded but the IPC later failed.
98 base::SyncSocket temp_socket(
99 IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle));
100 return PP_ERROR_FAILED;
103 return result;
106 PepperBroker::PepperBroker(PluginModule* plugin_module)
107 : plugin_module_(plugin_module) {
108 DCHECK(plugin_module_);
110 plugin_module_->SetBroker(this);
113 PepperBroker::~PepperBroker() {
114 ReportFailureToClients(PP_ERROR_ABORTED);
115 plugin_module_->SetBroker(NULL);
116 plugin_module_ = NULL;
119 // If the channel is not ready, queue the connection.
120 void PepperBroker::AddPendingConnect(PPB_Broker_Impl* client) {
121 DCHECK(pending_connects_.find(client) == pending_connects_.end())
122 << "Connect was already called for this client";
124 // Ensure this object and the associated broker exist as long as the
125 // client exists. There is a corresponding Release() call in Disconnect(),
126 // which is called when the PPB_Broker_Impl is destroyed. The only other
127 // possible reference is in pending_connect_broker_, which only holds a
128 // transient reference. This ensures the broker is available as long as the
129 // plugin needs it and allows the plugin to release the broker when it is no
130 // longer using it.
131 AddRef();
133 pending_connects_[client].client = client->AsWeakPtr();
136 void PepperBroker::Disconnect(PPB_Broker_Impl* client) {
137 // Remove the pending connect if one exists. This class will not call client's
138 // callback.
139 pending_connects_.erase(client);
141 // TODO(ddorwin): Send message disconnect message using dispatcher_.
143 // Release the reference added in Connect().
144 // This must be the last statement because it may delete this object.
145 Release();
148 void PepperBroker::OnBrokerChannelConnected(
149 base::ProcessId broker_pid,
150 const IPC::ChannelHandle& channel_handle) {
151 scoped_ptr<PepperBrokerDispatcherWrapper> dispatcher(
152 new PepperBrokerDispatcherWrapper);
153 if (!dispatcher->Init(broker_pid, channel_handle)) {
154 ReportFailureToClients(PP_ERROR_FAILED);
155 return;
158 dispatcher_.reset(dispatcher.release());
160 // Process all pending channel requests from the plugins.
161 for (ClientMap::iterator i = pending_connects_.begin();
162 i != pending_connects_.end();) {
163 base::WeakPtr<PPB_Broker_Impl>& weak_ptr = i->second.client;
164 if (!i->second.is_authorized) {
165 ++i;
166 continue;
169 if (weak_ptr.get())
170 ConnectPluginToBroker(weak_ptr.get());
172 pending_connects_.erase(i++);
176 void PepperBroker::OnBrokerPermissionResult(PPB_Broker_Impl* client,
177 bool result) {
178 ClientMap::iterator entry = pending_connects_.find(client);
179 if (entry == pending_connects_.end())
180 return;
182 if (!entry->second.client.get()) {
183 // Client has gone away.
184 pending_connects_.erase(entry);
185 return;
188 if (!result) {
189 // Report failure.
190 client->BrokerConnected(
191 ppapi::PlatformFileToInt(base::kInvalidPlatformFileValue),
192 PP_ERROR_NOACCESS);
193 pending_connects_.erase(entry);
194 return;
197 if (dispatcher_) {
198 ConnectPluginToBroker(client);
199 pending_connects_.erase(entry);
200 return;
203 // Mark the request as authorized, continue waiting for the broker
204 // connection.
205 DCHECK(!entry->second.is_authorized);
206 entry->second.is_authorized = true;
209 PepperBroker::PendingConnection::PendingConnection() : is_authorized(false) {}
211 PepperBroker::PendingConnection::~PendingConnection() {}
213 void PepperBroker::ReportFailureToClients(int error_code) {
214 DCHECK_NE(PP_OK, error_code);
215 for (ClientMap::iterator i = pending_connects_.begin();
216 i != pending_connects_.end();
217 ++i) {
218 base::WeakPtr<PPB_Broker_Impl>& weak_ptr = i->second.client;
219 if (weak_ptr.get()) {
220 weak_ptr->BrokerConnected(
221 ppapi::PlatformFileToInt(base::kInvalidPlatformFileValue),
222 error_code);
225 pending_connects_.clear();
228 void PepperBroker::ConnectPluginToBroker(PPB_Broker_Impl* client) {
229 base::SyncSocket::Handle plugin_handle = base::kInvalidPlatformFileValue;
230 int32_t result = PP_OK;
232 // The socket objects will be deleted when this function exits, closing the
233 // handles. Any uses of the socket must duplicate them.
234 scoped_ptr<base::SyncSocket> broker_socket(new base::SyncSocket());
235 scoped_ptr<base::SyncSocket> plugin_socket(new base::SyncSocket());
236 if (base::SyncSocket::CreatePair(broker_socket.get(), plugin_socket.get())) {
237 result = dispatcher_->SendHandleToBroker(client->pp_instance(),
238 broker_socket->handle());
240 // If the broker has its pipe handle, duplicate the plugin's handle.
241 // Otherwise, the plugin's handle will be automatically closed.
242 if (result == PP_OK)
243 plugin_handle = DuplicateHandle(plugin_socket->handle());
244 } else {
245 result = PP_ERROR_FAILED;
248 // TOOD(ddorwin): Change the IPC to asynchronous: Queue an object containing
249 // client and plugin_socket.release(), then return.
250 // That message handler will then call client->BrokerConnected() with the
251 // saved pipe handle.
252 // Temporarily, just call back.
253 client->BrokerConnected(ppapi::PlatformFileToInt(plugin_handle), result);
256 } // namespace content