 Chromium Code Reviews
 Chromium Code Reviews Issue 6833002:
  Implemented PPB_Broker_Proxy.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 6833002:
  Implemented PPB_Broker_Proxy.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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/ppb_broker_proxy.h" | |
| 6 | |
| 7 #include "ppapi/c/pp_errors.h" | |
| 8 #include "ppapi/c/trusted/ppb_broker_trusted.h" | |
| 9 #include "ppapi/proxy/plugin_dispatcher.h" | |
| 10 #include "ppapi/proxy/plugin_resource.h" | |
| 11 #include "ppapi/proxy/ppapi_messages.h" | |
| 12 | |
| 13 namespace pp { | |
| 14 namespace proxy { | |
| 15 | |
| 16 class Broker : public PluginResource { | |
| 17 public: | |
| 18 explicit Broker(const HostResource& resource); | |
| 19 virtual ~Broker(); | |
| 20 | |
| 21 // Resource overrides. | |
| 22 virtual Broker* AsBroker() { return this; } | |
| 23 | |
| 24 bool called_connect_; | |
| 25 PP_CompletionCallback current_connect_callback_; | |
| 26 base::SyncSocket::Handle socket_handle_; | |
| 27 | |
| 28 private: | |
| 29 DISALLOW_COPY_AND_ASSIGN(Broker); | |
| 30 }; | |
| 31 | |
| 32 Broker::Broker(const HostResource& resource) | |
| 33 : PluginResource(resource), | |
| 34 called_connect_(false), | |
| 35 current_connect_callback_(PP_MakeCompletionCallback(NULL, NULL)), | |
| 36 socket_handle_(base::kInvalidPlatformFileValue) { | |
| 37 | |
| 38 // The plugin owns the handle. | |
| 39 socket_handle_ = base::kInvalidPlatformFileValue; | |
| 
brettw
2011/04/15 16:09:25
You set this above. I don't see where this handle
 
ddorwin
2011/04/15 18:41:32
This was supposed to be in the destructor. Moved.
 | |
| 40 } | |
| 41 | |
| 42 Broker::~Broker() { | |
| 43 // Ensure the callback is always fired. | |
| 44 if (current_connect_callback_.func) { | |
| 45 // TODO(brettw) the callbacks at this level should be refactored with a | |
| 46 // more automatic tracking system like we have in the renderer. | |
| 47 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( | |
| 48 current_connect_callback_.func, current_connect_callback_.user_data, | |
| 49 static_cast<int32_t>(PP_ERROR_ABORTED))); | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 namespace { | |
| 54 | |
| 55 PP_Resource CreateTrusted(PP_Instance instance) { | |
| 56 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | |
| 57 if (!dispatcher) | |
| 58 return 0; | |
| 59 | |
| 60 HostResource result; | |
| 61 dispatcher->Send(new PpapiHostMsg_PPBBroker_Create( | |
| 62 INTERFACE_ID_PPB_BROKER, instance, &result)); | |
| 63 if (result.is_null()) | |
| 64 return 0; | |
| 65 | |
| 66 linked_ptr<Broker> object(new Broker(result)); | |
| 67 return PluginResourceTracker::GetInstance()->AddResource(object); | |
| 68 } | |
| 69 | |
| 70 PP_Bool IsBrokerTrusted(PP_Resource resource) { | |
| 71 Broker* object = PluginResource::GetAs<Broker>(resource); | |
| 72 return BoolToPPBool(!!object); | |
| 73 } | |
| 74 | |
| 75 int32_t Connect(PP_Resource resource, | |
| 76 PP_CompletionCallback connect_callback) { | |
| 77 Broker* object = PluginResource::GetAs<Broker>(resource); | |
| 78 if (!object) | |
| 79 return PP_ERROR_BADRESOURCE; | |
| 80 | |
| 81 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); | |
| 82 if (!dispatcher) | |
| 83 return PP_ERROR_BADRESOURCE; | |
| 84 | |
| 85 if (!connect_callback.func) { | |
| 86 // Synchronous calls are not supported. | |
| 87 return PP_ERROR_BADARGUMENT; | |
| 88 } | |
| 89 | |
| 90 if (object->current_connect_callback_.func) | |
| 91 return PP_ERROR_INPROGRESS; | |
| 92 else if (object->called_connect_) | |
| 93 return PP_ERROR_FAILED; | |
| 94 | |
| 95 object->current_connect_callback_ = connect_callback; | |
| 96 object->called_connect_ = true; | |
| 97 | |
| 98 bool success = dispatcher->Send(new PpapiHostMsg_PPBBroker_Connect( | |
| 99 INTERFACE_ID_PPB_BROKER, | |
| 100 object->host_resource())); | |
| 101 return success ? PP_ERROR_WOULDBLOCK/*after merge: PP_OK_COMPLETIONPENDING*/ : PP_ERROR_FAILED; | |
| 
brettw
2011/04/15 16:09:25
Did you mean to update this?
 
ddorwin
2011/04/15 18:41:32
Yes. Once I get an LGTM, I'll sync and change this
 | |
| 102 } | |
| 103 | |
| 104 int32_t GetHandle(PP_Resource resource, int32_t* handle) { | |
| 105 Broker* object = PluginResource::GetAs<Broker>(resource); | |
| 106 if (!object) | |
| 107 return PP_ERROR_BADRESOURCE; | |
| 108 *handle = object->socket_handle_; | |
| 109 return PP_OK; | |
| 110 } | |
| 111 | |
| 112 const PPB_BrokerTrusted broker_interface = { | |
| 113 &CreateTrusted, | |
| 114 &IsBrokerTrusted, | |
| 115 &Connect, | |
| 116 &GetHandle, | |
| 117 }; | |
| 118 | |
| 119 InterfaceProxy* CreateBrokerProxy(Dispatcher* dispatcher, | |
| 120 const void* target_interface) { | |
| 121 return new PPB_Broker_Proxy(dispatcher, target_interface); | |
| 122 } | |
| 123 | |
| 124 base::PlatformFile IntToPlatformFile(int32_t handle) { | |
| 125 #if defined(OS_WIN) | |
| 126 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); | |
| 127 #elif defined(OS_POSIX) | |
| 128 return handle; | |
| 129 #else | |
| 130 #error Not implemented. | |
| 131 #endif | |
| 132 } | |
| 133 | |
| 134 } // namespace | |
| 135 | |
| 136 PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher, | |
| 137 const void* target_interface) | |
| 138 : InterfaceProxy(dispatcher, target_interface) , | |
| 139 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)){ | |
| 140 } | |
| 141 | |
| 142 PPB_Broker_Proxy::~PPB_Broker_Proxy() { | |
| 143 } | |
| 144 | |
| 145 // static | |
| 146 const InterfaceProxy::Info* PPB_Broker_Proxy::GetInfo() { | |
| 147 static const Info info = { | |
| 148 &broker_interface, | |
| 149 PPB_BROKER_TRUSTED_INTERFACE, | |
| 150 INTERFACE_ID_PPB_BROKER, | |
| 151 true, | |
| 152 &CreateBrokerProxy, | |
| 153 }; | |
| 154 return &info; | |
| 155 } | |
| 156 | |
| 157 bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) { | |
| 158 bool handled = true; | |
| 159 IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg) | |
| 160 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate) | |
| 161 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect) | |
| 162 IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete, | |
| 163 OnMsgConnectComplete) | |
| 164 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 165 IPC_END_MESSAGE_MAP() | |
| 166 return handled; | |
| 167 } | |
| 168 | |
| 169 void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance, | |
| 170 HostResource* result_resource) { | |
| 171 result_resource->SetHostResource( | |
| 172 instance, | |
| 173 ppb_broker_target()->CreateTrusted(instance)); | |
| 174 } | |
| 175 | |
| 176 void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) { | |
| 177 CompletionCallback callback = callback_factory_.NewCallback( | |
| 178 &PPB_Broker_Proxy::ConnectCompleteInHost, broker); | |
| 179 | |
| 180 int32_t result = ppb_broker_target()->Connect( | |
| 181 broker.host_resource(), | |
| 182 callback.pp_completion_callback()); | |
| 183 if (result != PP_ERROR_WOULDBLOCK/*after merge: PP_OK_COMPLETIONPENDING*/) | |
| 184 callback.Run(result); | |
| 185 } | |
| 186 | |
| 187 // Called in the plugin to handle the connect callback. | |
| 188 // The proxy owns the handle and transfers it to the Broker. At that point, | |
| 189 // the plugin owns the handle and is responsible for closing it. | |
| 190 // The caller guarantees that socket_handle is not valid if result is not PP_OK. | |
| 191 void PPB_Broker_Proxy::OnMsgConnectComplete( | |
| 192 const HostResource& broker, | |
| 193 IPC::PlatformFileForTransit socket_handle, | |
| 194 int32_t result) { | |
| 195 DCHECK(result == PP_OK || | |
| 196 socket_handle == IPC::InvalidPlatformFileForTransit()); | |
| 197 | |
| 198 Broker* object = NULL; | |
| 199 if (result == PP_OK) { | |
| 200 object = PluginResource::GetAs<Broker>( | |
| 201 PluginResourceTracker::GetInstance()->PluginResourceForHostResource( | |
| 202 broker)); | |
| 203 if (!object) | |
| 204 result = PP_ERROR_BADRESOURCE; | |
| 205 } | |
| 206 | |
| 207 if (result == PP_OK) { | |
| 208 object->socket_handle_ = | |
| 209 IPC::PlatformFileForTransitToPlatformFile(socket_handle); | |
| 210 } else { | |
| 211 // The caller may still have given us a handle in the failure case. | |
| 212 // The easiest way to clean it up is to just put it in an object | |
| 213 // and then close them. This failure case is not performance critical. | |
| 214 base::SyncSocket temp_socket( | |
| 215 IPC::PlatformFileForTransitToPlatformFile(socket_handle)); | |
| 216 } | |
| 217 | |
| 218 if (!object->current_connect_callback_.func) { | |
| 219 // The handle might leak if the plugin never calls GetHandle(). | |
| 220 return; | |
| 221 } | |
| 222 | |
| 223 PP_CompletionCallback callback = object->current_connect_callback_; | |
| 224 object->current_connect_callback_ = PP_MakeCompletionCallback(NULL, NULL); | |
| 225 PP_RunCompletionCallback(&callback, result); | |
| 226 } | |
| 227 | |
| 228 // Callback on the host side. | |
| 229 // Transfers ownership of the handle to the plugin side. This function must | |
| 230 // either successfully call the callback or close the handle. | |
| 231 void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result, | |
| 232 const HostResource& broker) { | |
| 233 IPC::PlatformFileForTransit foreign_socket_handle = | |
| 234 IPC::InvalidPlatformFileForTransit(); | |
| 235 if (result == PP_OK) { | |
| 236 int32_t socket_handle = base::kInvalidPlatformFileValue; | |
| 237 result = ppb_broker_target()->GetHandle(broker.host_resource(), | |
| 238 &socket_handle); | |
| 239 DCHECK(result == PP_OK || | |
| 240 socket_handle == base::kInvalidPlatformFileValue); | |
| 241 | |
| 242 if (result == PP_OK) { | |
| 243 foreign_socket_handle = | |
| 244 dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle), | |
| 245 true); | |
| 
brettw
2011/04/15 16:09:25
I'm unclear on the ownership of this handle also.
 
ddorwin
2011/04/15 18:41:32
As I mentioned above, PPB_Broker_Impl never owns t
 | |
| 246 if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) { | |
| 247 result = PP_ERROR_FAILED; | |
| 248 // Assume the local handle was closed even if the foreign handle could | |
| 249 // not be created. | |
| 250 } | |
| 251 } | |
| 252 } | |
| 253 DCHECK(result == PP_OK || | |
| 254 foreign_socket_handle == IPC::InvalidPlatformFileForTransit()); | |
| 255 | |
| 256 bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete( | |
| 257 INTERFACE_ID_PPB_FILE_SYSTEM, broker, foreign_socket_handle, result)); | |
| 258 | |
| 259 if (!success || result == PP_OK) { | |
| 260 // The plugin did not receive the handle, so it must be closed. | |
| 261 // The easiest way to clean it up is to just put it in an object | |
| 262 // and then close it. This failure case is not performance critical. | |
| 263 // The handle could still leak if Send succeeded but the IPC later failed. | |
| 264 base::SyncSocket temp_socket( | |
| 265 IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle)); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 } // namespace proxy | |
| 270 } // namespace pp | |
| OLD | NEW |