Home | History | Annotate | Download | only in plugin
      1 /*
      2  * Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3  * Use of this source code is governed by a BSD-style license that can be
      4  * found in the LICENSE file.
      5  */
      6 
      7 #include "ppapi/native_client/src/trusted/plugin/srpc_client.h"
      8 
      9 #include <string.h>
     10 
     11 #include "native_client/src/shared/platform/nacl_log.h"
     12 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
     13 #include "ppapi/native_client/src/trusted/plugin/srpc_params.h"
     14 #include "ppapi/native_client/src/trusted/plugin/utility.h"
     15 
     16 namespace plugin {
     17 
     18 typedef bool (*RpcFunction)(void* obj, SrpcParams* params);
     19 
     20 // MethodInfo records the method names and type signatures of an SRPC server.
     21 class MethodInfo {
     22  public:
     23   // statically defined method - called through a pointer
     24   MethodInfo(const RpcFunction function_ptr,
     25              const char* name,
     26              const char* ins,
     27              const char* outs,
     28              // index is set to UINT_MAX for methods implemented by the plugin,
     29              // All methods implemented by nacl modules have indexes
     30              // that are lower than UINT_MAX.
     31              const uint32_t index = UINT_MAX) :
     32     function_ptr_(function_ptr),
     33     name_(STRDUP(name)),
     34     ins_(STRDUP(ins)),
     35     outs_(STRDUP(outs)),
     36     index_(index) { }
     37 
     38   ~MethodInfo() {
     39     free(reinterpret_cast<void*>(name_));
     40     free(reinterpret_cast<void*>(ins_));
     41     free(reinterpret_cast<void*>(outs_));
     42   }
     43 
     44   RpcFunction function_ptr() const { return function_ptr_; }
     45   char* name() const { return name_; }
     46   char* ins() const { return ins_; }
     47   char* outs() const { return outs_; }
     48   uint32_t index() const { return index_; }
     49 
     50  private:
     51   NACL_DISALLOW_COPY_AND_ASSIGN(MethodInfo);
     52   RpcFunction function_ptr_;
     53   char* name_;
     54   char* ins_;
     55   char* outs_;
     56   uint32_t index_;
     57 };
     58 
     59 SrpcClient::SrpcClient()
     60     : srpc_channel_initialised_(false) {
     61   PLUGIN_PRINTF(("SrpcClient::SrpcClient (this=%p)\n",
     62                  static_cast<void*>(this)));
     63   NaClSrpcChannelInitialize(&srpc_channel_);
     64 }
     65 
     66 SrpcClient* SrpcClient::New(nacl::DescWrapper* wrapper) {
     67   nacl::scoped_ptr<SrpcClient> srpc_client(new SrpcClient());
     68   if (!srpc_client->Init(wrapper)) {
     69     PLUGIN_PRINTF(("SrpcClient::New (SrpcClient::Init failed)\n"));
     70     return NULL;
     71   }
     72   return srpc_client.release();
     73 }
     74 
     75 bool SrpcClient::Init(nacl::DescWrapper* wrapper) {
     76   PLUGIN_PRINTF(("SrpcClient::Init (this=%p, wrapper=%p)\n",
     77                  static_cast<void*>(this),
     78                  static_cast<void*>(wrapper)));
     79   // Open the channel to pass RPC information back and forth
     80   if (!NaClSrpcClientCtor(&srpc_channel_, wrapper->desc())) {
     81     return false;
     82   }
     83   srpc_channel_initialised_ = true;
     84   PLUGIN_PRINTF(("SrpcClient::Init (Ctor worked)\n"));
     85   // Record the method names in a convenient way for later dispatches.
     86   GetMethods();
     87   PLUGIN_PRINTF(("SrpcClient::Init (GetMethods worked)\n"));
     88   return true;
     89 }
     90 
     91 SrpcClient::~SrpcClient() {
     92   PLUGIN_PRINTF(("SrpcClient::~SrpcClient (this=%p, has_srpc_channel=%d)\n",
     93                  static_cast<void*>(this), srpc_channel_initialised_));
     94   // And delete the connection.
     95   if (srpc_channel_initialised_) {
     96     PLUGIN_PRINTF(("SrpcClient::~SrpcClient (destroying srpc_channel)\n"));
     97     NaClSrpcDtor(&srpc_channel_);
     98   }
     99   for (Methods::iterator iter = methods_.begin();
    100        iter != methods_.end();
    101        ++iter) {
    102     delete iter->second;
    103   }
    104   PLUGIN_PRINTF(("SrpcClient::~SrpcClient (return)\n"));
    105 }
    106 
    107 void SrpcClient::GetMethods() {
    108   PLUGIN_PRINTF(("SrpcClient::GetMethods (this=%p)\n",
    109                  static_cast<void*>(this)));
    110   if (NULL == srpc_channel_.client) {
    111     return;
    112   }
    113   uint32_t method_count = NaClSrpcServiceMethodCount(srpc_channel_.client);
    114   // Intern the methods into a mapping from identifiers to MethodInfo.
    115   for (uint32_t i = 0; i < method_count; ++i) {
    116     int retval;
    117     const char* method_name;
    118     const char* input_types;
    119     const char* output_types;
    120 
    121     retval = NaClSrpcServiceMethodNameAndTypes(srpc_channel_.client,
    122                                                i,
    123                                                &method_name,
    124                                                &input_types,
    125                                                &output_types);
    126     if (!retval) {
    127       return;
    128     }
    129     if (!IsValidIdentifierString(method_name, NULL)) {
    130       // If name is not an ECMAScript identifier, do not enter it into the
    131       // methods_ table.
    132       continue;
    133     }
    134     MethodInfo* method_info =
    135         new MethodInfo(NULL, method_name, input_types, output_types, i);
    136     if (NULL == method_info) {
    137       return;
    138     }
    139     // Install in the map only if successfully read.
    140     methods_[method_name] = method_info;
    141   }
    142 }
    143 
    144 bool SrpcClient::HasMethod(const std::string& method_name) {
    145   bool has_method = (NULL != methods_[method_name]);
    146   PLUGIN_PRINTF((
    147       "SrpcClient::HasMethod (this=%p, method_name='%s', return %d)\n",
    148       static_cast<void*>(this), method_name.c_str(), has_method));
    149   return has_method;
    150 }
    151 
    152 bool SrpcClient::InitParams(const std::string& method_name,
    153                             SrpcParams* params) {
    154   MethodInfo* method_info = methods_[method_name];
    155   if (method_info) {
    156     return params->Init(method_info->ins(), method_info->outs());
    157   }
    158   return false;
    159 }
    160 
    161 bool SrpcClient::Invoke(const std::string& method_name, SrpcParams* params) {
    162   // It would be better if we could set the exception on each detailed failure
    163   // case.  However, there are calls to Invoke from within the plugin itself,
    164   // and these could leave residual exceptions pending.  This seems to be
    165   // happening specifically with hard_shutdowns.
    166   PLUGIN_PRINTF(("SrpcClient::Invoke (this=%p, method_name='%s', params=%p)\n",
    167                  static_cast<void*>(this),
    168                  method_name.c_str(),
    169                  static_cast<void*>(params)));
    170 
    171   // Ensure Invoke was called with a method name that has a binding.
    172   if (NULL == methods_[method_name]) {
    173     PLUGIN_PRINTF(("SrpcClient::Invoke (ident not in methods_)\n"));
    174     return false;
    175   }
    176 
    177   PLUGIN_PRINTF(("SrpcClient::Invoke (sending the rpc)\n"));
    178   // Call the method
    179   last_error_ = NaClSrpcInvokeV(&srpc_channel_,
    180                                 methods_[method_name]->index(),
    181                                 params->ins(),
    182                                 params->outs());
    183   PLUGIN_PRINTF(("SrpcClient::Invoke (response=%d)\n", last_error_));
    184   if (NACL_SRPC_RESULT_OK != last_error_) {
    185     PLUGIN_PRINTF(("SrpcClient::Invoke (err='%s', return 0)\n",
    186                    NaClSrpcErrorString(last_error_)));
    187     return false;
    188   }
    189 
    190   PLUGIN_PRINTF(("SrpcClient::Invoke (return 1)\n"));
    191   return true;
    192 }
    193 
    194 void SrpcClient::AttachService(NaClSrpcService* service, void* instance_data) {
    195   srpc_channel_.server = service;
    196   srpc_channel_.server_instance_data = instance_data;
    197 }
    198 
    199 }  // namespace plugin
    200