15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/srpc_client.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "native_client/src/shared/platform/nacl_log.h"
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/plugin.h"
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/srpc_params.h"
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "ppapi/native_client/src/trusted/plugin/utility.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace plugin {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef bool (*RpcFunction)(void* obj, SrpcParams* params);
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MethodInfo records the method names and type signatures of an SRPC server.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MethodInfo {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // statically defined method - called through a pointer
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MethodInfo(const RpcFunction function_ptr,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const char* name,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const char* ins,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const char* outs,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             // index is set to UINT_MAX for methods implemented by the plugin,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             // All methods implemented by nacl modules have indexes
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             // that are lower than UINT_MAX.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const uint32_t index = UINT_MAX) :
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_ptr_(function_ptr),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name_(STRDUP(name)),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ins_(STRDUP(ins)),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outs_(STRDUP(outs)),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index_(index) { }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~MethodInfo() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(reinterpret_cast<void*>(name_));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(reinterpret_cast<void*>(ins_));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(reinterpret_cast<void*>(outs_));
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RpcFunction function_ptr() const { return function_ptr_; }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* name() const { return name_; }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* ins() const { return ins_; }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* outs() const { return outs_; }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t index() const { return index_; }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NACL_DISALLOW_COPY_AND_ASSIGN(MethodInfo);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RpcFunction function_ptr_;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* name_;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* ins_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* outs_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t index_;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SrpcClient::SrpcClient()
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : srpc_channel_initialised_(false) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::SrpcClient (this=%p)\n",
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(this)));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NaClSrpcChannelInitialize(&srpc_channel_);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SrpcClient* SrpcClient::New(nacl::DescWrapper* wrapper) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nacl::scoped_ptr<SrpcClient> srpc_client(new SrpcClient());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!srpc_client->Init(wrapper)) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLUGIN_PRINTF(("SrpcClient::New (SrpcClient::Init failed)\n"));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return srpc_client.release();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SrpcClient::Init(nacl::DescWrapper* wrapper) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Init (this=%p, wrapper=%p)\n",
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(this),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(wrapper)));
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the channel to pass RPC information back and forth
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!NaClSrpcClientCtor(&srpc_channel_, wrapper->desc())) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srpc_channel_initialised_ = true;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Init (Ctor worked)\n"));
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record the method names in a convenient way for later dispatches.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetMethods();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Init (GetMethods worked)\n"));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SrpcClient::~SrpcClient() {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::~SrpcClient (this=%p, has_srpc_channel=%d)\n",
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(this), srpc_channel_initialised_));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And delete the connection.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (srpc_channel_initialised_) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLUGIN_PRINTF(("SrpcClient::~SrpcClient (destroying srpc_channel)\n"));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NaClSrpcDtor(&srpc_channel_);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Methods::iterator iter = methods_.begin();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != methods_.end();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete iter->second;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::~SrpcClient (return)\n"));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SrpcClient::GetMethods() {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::GetMethods (this=%p)\n",
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(this)));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == srpc_channel_.client) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t method_count = NaClSrpcServiceMethodCount(srpc_channel_.client);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Intern the methods into a mapping from identifiers to MethodInfo.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (uint32_t i = 0; i < method_count; ++i) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int retval;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* method_name;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* input_types;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* output_types;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retval = NaClSrpcServiceMethodNameAndTypes(srpc_channel_.client,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               i,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &method_name,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &input_types,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &output_types);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!retval) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsValidIdentifierString(method_name, NULL)) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If name is not an ECMAScript identifier, do not enter it into the
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // methods_ table.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MethodInfo* method_info =
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new MethodInfo(NULL, method_name, input_types, output_types, i);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NULL == method_info) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Install in the map only if successfully read.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    methods_[method_name] = method_info;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool SrpcClient::HasMethod(const std::string& method_name) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_method = (NULL != methods_[method_name]);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF((
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SrpcClient::HasMethod (this=%p, method_name='%s', return %d)\n",
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<void*>(this), method_name.c_str(), has_method));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_method;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool SrpcClient::InitParams(const std::string& method_name,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            SrpcParams* params) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MethodInfo* method_info = methods_[method_name];
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (method_info) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return params->Init(method_info->ins(), method_info->outs());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool SrpcClient::Invoke(const std::string& method_name, SrpcParams* params) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It would be better if we could set the exception on each detailed failure
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case.  However, there are calls to Invoke from within the plugin itself,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and these could leave residual exceptions pending.  This seems to be
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happening specifically with hard_shutdowns.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Invoke (this=%p, method_name='%s', params=%p)\n",
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(this),
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 method_name.c_str(),
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<void*>(params)));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure Invoke was called with a method name that has a binding.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == methods_[method_name]) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLUGIN_PRINTF(("SrpcClient::Invoke (ident not in methods_)\n"));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Invoke (sending the rpc)\n"));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call the method
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_error_ = NaClSrpcInvokeV(&srpc_channel_,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                methods_[method_name]->index(),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                params->ins(),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                params->outs());
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Invoke (response=%d)\n", last_error_));
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NACL_SRPC_RESULT_OK != last_error_) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLUGIN_PRINTF(("SrpcClient::Invoke (err='%s', return 0)\n",
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   NaClSrpcErrorString(last_error_)));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLUGIN_PRINTF(("SrpcClient::Invoke (return 1)\n"));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SrpcClient::AttachService(NaClSrpcService* service, void* instance_data) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srpc_channel_.server = service;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srpc_channel_.server_instance_data = instance_data;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace plugin
200