OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |