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