- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / native_client / src / trusted / plugin / srpc_client.cc
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