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