| // Copyright (c) 2012 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 "native_client/src/shared/ppapi_proxy/browser_callback.h" |
| |
| #include <new> |
| |
| #include "native_client/src/include/nacl_macros.h" |
| #include "native_client/src/include/nacl_scoped_ptr.h" |
| #include "native_client/src/shared/platform/nacl_check.h" |
| #include "native_client/src/shared/ppapi_proxy/browser_globals.h" |
| #include "native_client/src/shared/ppapi_proxy/browser_ppp.h" |
| #include "native_client/src/shared/ppapi_proxy/object_serialize.h" |
| #include "native_client/src/shared/ppapi_proxy/utility.h" |
| #include "native_client/src/shared/srpc/nacl_srpc.h" |
| #include "ppapi/c/pp_completion_callback.h" |
| #include "native_client/src/trusted/plugin/plugin.h" |
| #include "srpcgen/ppp_rpc.h" |
| |
| namespace ppapi_proxy { |
| |
| namespace { |
| |
| bool BytesWereRead(int32_t num_bytes) { |
| return (num_bytes > 0); |
| } |
| |
| nacl_abi_size_t CastToNaClAbiSize(int32_t result) { |
| return static_cast<nacl_abi_size_t>(result); |
| } |
| |
| // Data structure used on the browser side to invoke a completion callback |
| // on the plugin side. |
| // |
| // A plugin-side callback is proxied over to the browser side using |
| // a |callback_id|. This id is then paired with an |srpc_channel| listened to |
| // by the nexe that supplied the callback. |
| // |
| // |read_buffer| is used with callbacks that are invoked on byte reads. |
| // |check_result_func| is a pointer to a function used to check the |
| // result of the operation. The semantics of the result value may be different |
| // depending on how the callback operation was initiated, and |
| // |check_result_func| provides an abstraction to the semantics. |
| // |get_size_read_func| is a pointer to a function used to get the |
| // number of bytes read. The way the number of bytes read |
| // retrieved/calculated may be different depending on how the callback was |
| // initiated, and |get_size_read_func| provides the indirection. |
| struct RemoteCallbackInfo { |
| NaClSrpcChannel* srpc_channel; |
| int32_t callback_id; |
| char* read_buffer; |
| PP_Var read_var; |
| CheckResultFunc check_result_func; |
| GetReadSizeFunc get_size_read_func; |
| }; |
| |
| // Calls the remote implementation of a callback on the plugin side. |
| // Implements a PP_CompletionCallback_Func type that can be used along with an |
| // instance of a RemoteCallbackInfo as |user_data| to provide a |
| // PP_CompletionCallback to browser functions. |
| // |
| // |remote_callback| is a pointer to a RemoteCallbackInfo, |
| // deleted after rpc via scoped_ptr. The associated |read_buffer| is also |
| // deleted. |
| // |result| is passed by the callback invoker to indicate success or error. |
| // It is passed as-is to the plugin side callback. |
| void RunRemoteCallback(void* user_data, int32_t result) { |
| CHECK(PPBCoreInterface()->IsMainThread()); |
| DebugPrintf("RunRemoteCallback: result=%"NACL_PRId32"\n", result); |
| nacl::scoped_ptr<RemoteCallbackInfo> remote_callback( |
| reinterpret_cast<RemoteCallbackInfo*>(user_data)); |
| nacl::scoped_array<char> read_buffer(remote_callback->read_buffer); |
| |
| // If the proxy is down, the channel is no longer usable for remote calls. |
| PP_Instance instance = |
| LookupInstanceIdForSrpcChannel(remote_callback->srpc_channel); |
| if (LookupBrowserPppForInstance(instance) == NULL) { |
| DebugPrintf("RunRemoteCallback: proxy=NULL\n", result); |
| return; |
| } |
| |
| nacl_abi_size_t read_buffer_size = 0; |
| CheckResultFunc check_result_func = remote_callback->check_result_func; |
| GetReadSizeFunc get_size_read_func = remote_callback->get_size_read_func; |
| if ((*check_result_func)(result) && remote_callback->read_buffer != NULL) |
| read_buffer_size = (*get_size_read_func)(result); |
| if (remote_callback->read_var.type != PP_VARTYPE_NULL) { |
| read_buffer_size = kMaxReturnVarSize; |
| read_buffer.reset( |
| Serialize(&remote_callback->read_var, 1, &read_buffer_size)); |
| PPBVarInterface()->Release(remote_callback->read_var); |
| } |
| |
| NaClSrpcError srpc_result = |
| CompletionCallbackRpcClient::RunCompletionCallback( |
| remote_callback->srpc_channel, |
| remote_callback->callback_id, |
| result, |
| read_buffer_size, |
| read_buffer.get()); |
| DebugPrintf("RunRemoteCallback: %s\n", |
| NaClSrpcErrorString(srpc_result)); |
| if (srpc_result == NACL_SRPC_RESULT_INTERNAL) |
| CleanUpAfterDeadNexe(instance); |
| } |
| |
| } // namespace |
| |
| // Builds a RemoteCallbackInfo and returns PP_CompletionCallback corresponding |
| // to RunRemoteCallback or NULL on failure. |
| struct PP_CompletionCallback MakeRemoteCompletionCallback( |
| NaClSrpcChannel* srpc_channel, |
| int32_t callback_id, |
| int32_t bytes_to_read, |
| char** buffer, |
| PP_Var** var, |
| CheckResultFunc check_result_func, |
| GetReadSizeFunc get_size_read_func) { |
| nacl::scoped_ptr<RemoteCallbackInfo> remote_callback( |
| new(std::nothrow) RemoteCallbackInfo); |
| if (remote_callback.get() == NULL) // new failed. |
| return PP_BlockUntilComplete(); |
| remote_callback->srpc_channel = srpc_channel; |
| remote_callback->callback_id = callback_id; |
| remote_callback->read_buffer = NULL; |
| remote_callback->read_var = PP_MakeNull(); |
| remote_callback->check_result_func = check_result_func; |
| remote_callback->get_size_read_func = get_size_read_func; |
| |
| if (bytes_to_read > 0 && buffer != NULL) { |
| *buffer = new(std::nothrow) char[bytes_to_read]; |
| if (*buffer == NULL) // new failed. |
| return PP_BlockUntilComplete(); |
| remote_callback->read_buffer = *buffer; |
| } |
| if (var) |
| *var = &remote_callback->read_var; |
| |
| return PP_MakeOptionalCompletionCallback( |
| RunRemoteCallback, remote_callback.release()); |
| } |
| |
| struct PP_CompletionCallback MakeRemoteCompletionCallback( |
| NaClSrpcChannel* srpc_channel, |
| int32_t callback_id, |
| int32_t bytes_to_read, |
| char** buffer, |
| CheckResultFunc check_result_func, |
| GetReadSizeFunc get_size_read_func) { |
| return MakeRemoteCompletionCallback(srpc_channel, callback_id, bytes_to_read, |
| buffer, NULL, check_result_func, |
| get_size_read_func); |
| } |
| |
| struct PP_CompletionCallback MakeRemoteCompletionCallback( |
| NaClSrpcChannel* srpc_channel, |
| int32_t callback_id, |
| int32_t bytes_to_read, |
| char** buffer) { |
| return MakeRemoteCompletionCallback(srpc_channel, callback_id, bytes_to_read, |
| buffer, BytesWereRead, CastToNaClAbiSize); |
| } |
| |
| struct PP_CompletionCallback MakeRemoteCompletionCallback( |
| NaClSrpcChannel* srpc_channel, |
| int32_t callback_id, |
| PP_Var** var) { |
| return MakeRemoteCompletionCallback(srpc_channel, callback_id, 0, NULL, var, |
| BytesWereRead, CastToNaClAbiSize); |
| } |
| |
| struct PP_CompletionCallback MakeRemoteCompletionCallback( |
| NaClSrpcChannel* srpc_channel, |
| int32_t callback_id) { |
| return MakeRemoteCompletionCallback(srpc_channel, callback_id, 0, NULL); |
| } |
| |
| void DeleteRemoteCallbackInfo(struct PP_CompletionCallback callback) { |
| nacl::scoped_ptr<RemoteCallbackInfo> remote_callback( |
| reinterpret_cast<RemoteCallbackInfo*>(callback.user_data)); |
| nacl::scoped_array<char> read_buffer(remote_callback->read_buffer); |
| } |
| |
| } // namespace ppapi_proxy |