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 nacl::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 nacl::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 nacl::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