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