Merge branch 'upstream'
[nativeclient.git] / tools / npapi_runtime / npbridge.cc
blob24182e951705526de9fcdc6595fafd0fdc6aa412
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // NaCl-NPAPI Interface
35 #include "native_client/tools/npapi_runtime/npbridge.h"
37 #include <assert.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
43 #include "native_client/tools/npapi_runtime/nacl_npapi.h"
44 #include "native_client/tools/npapi_runtime/nacl_util.h"
46 namespace nacl {
48 NPBridge::NPBridge(NPP npp)
49 : npp_(npp),
50 peer_pid_(-1),
51 peer_npvariant_size_(0), // Must be set later
52 channel_(kInvalidHtpHandle),
53 waiting_since_(0),
54 tag_(0),
55 handle_count_(0),
56 is_webkit_(false) { // TBD
57 Init();
60 NPBridge::~NPBridge() {
61 while (!stub_map_.empty()) {
62 std::map<NPObject*, NPObjectStub*>::iterator i = stub_map_.begin();
63 NPObjectStub* stub = (*i).second;
64 delete stub;
67 Close(channel_);
69 // Note proxy objects are deleted by Navigator.
70 for (std::map<const NPCapability, NPObjectProxy*>::iterator i =
71 proxy_map_.begin();
72 i != proxy_map_.end();
73 ++i) {
74 NPObjectProxy* proxy = (*i).second;
75 proxy->Detach();
79 NPObjectStub* NPBridge::LookupStub(NPObject* object) {
80 assert(object);
81 std::map<NPObject*, NPObjectStub*>::iterator i;
82 i = stub_map_.find(object);
83 if (i != stub_map_.end()) {
84 return (*i).second;
86 return NULL;
89 NPObjectProxy* NPBridge::LookupProxy(const NPCapability& capability) {
90 if (capability.object == NULL) {
91 return NULL;
93 if (capability.pid == GetPID()) {
94 return NULL;
96 std::map<const NPCapability, NPObjectProxy*>::iterator i;
97 i = proxy_map_.find(capability);
98 if (i != proxy_map_.end()) {
99 return (*i).second;
101 return NULL;
104 int NPBridge::CreateStub(NPObject* object, NPCapability* cap) {
105 NPObjectStub* stub = NULL;
106 if (object != NULL) {
107 if (NPObjectProxy::IsInstance(object)) { // object can be a proxy
108 NPObjectProxy* proxy = static_cast<NPObjectProxy*>(object);
109 if (proxy->capability().pid == peer_pid()) {
110 *cap = proxy->capability();
111 return 0;
114 stub = LookupStub(object);
115 if (stub) {
116 cap->pid = GetPID();
117 cap->object = object;
118 return 1;
120 stub = new(std::nothrow) NPObjectStub(this, object);
122 cap->pid = GetPID();
123 if (!stub) {
124 cap->object = NULL;
125 return 0;
127 stub_map_[object] = stub;
128 cap->object = object;
129 return 1;
132 NPObject* NPBridge::CreateProxy(const NPCapability& capability) {
133 if (capability.object == NULL) {
134 return NULL;
136 if (capability.pid == GetPID()) { // capability can be of my process
137 std::map<NPObject*, NPObjectStub*>::iterator i;
138 i = stub_map_.find(capability.object);
139 if (i == stub_map_.end()) {
140 return NULL;
142 NPN_RetainObject(capability.object);
143 return capability.object;
146 std::map<const NPCapability, NPObjectProxy*>::iterator i;
147 i = proxy_map_.find(capability);
148 if (i != proxy_map_.end()) {
149 NPObjectProxy* proxy = (*i).second;
150 NPN_RetainObject(proxy);
151 return proxy;
153 NPObjectProxy* proxy = new(std::nothrow) NPObjectProxy(this, capability);
154 if (!proxy) {
155 return NULL;
157 AddProxy(proxy);
158 return proxy;
161 void NPBridge::AddProxy(NPObjectProxy* proxy) {
162 proxy_map_[proxy->capability()] = proxy;
165 void NPBridge::RemoveProxy(NPObjectProxy* proxy) {
166 proxy_map_.erase(proxy->capability());
169 NPObjectStub* NPBridge::GetStub(const NPCapability& capability) {
170 if (capability.pid != GetPID()) {
171 return NULL;
173 std::map<NPObject*, NPObjectStub*>::iterator i;
174 i = stub_map_.find(capability.object);
175 if (i == stub_map_.end()) {
176 return NULL;
178 return (*i).second;
181 void NPBridge::RemoveStub(NPObjectStub* stub) {
182 stub_map_.erase(stub->object());
185 RpcHeader* NPBridge::Request(RpcHeader* request, IOVec* iov, size_t iov_length,
186 int* length) {
187 if (channel_ == kInvalidHtpHandle) {
188 return NULL;
190 assert(iov[0].base == request);
191 request->tag = ++tag_;
192 request->pid = GetPID();
194 HtpHeader message;
195 message.iov = iov;
196 message.iov_length = iov_length;
197 message.handles = handles_;
198 message.handle_count = handle_count_;
199 if (SendDatagram(channel_, &message, 0) <
200 static_cast<int>(sizeof(RpcHeader))) {
201 clear_handle_count();
202 return NULL;
204 return Wait(request, length);
207 RpcHeader* NPBridge::Wait(const RpcHeader* request, int* length) {
208 RpcHeader* header = static_cast<RpcHeader*>(top());
209 for (;;) {
210 HtpHeader message;
211 IOVec vec;
212 vec.base = top();
213 vec.length = GetFreeSize();
214 message.iov = &vec;
215 message.iov_length = 1;
216 message.handles = handles_;
217 message.handle_count = kHandleCountMax;
218 clear_handle_count();
220 waiting_since_ = time(NULL);
221 int result = ReceiveDatagram(channel_, &message, 0);
222 waiting_since_ = 0;
223 if (result == -1) {
224 Close(channel_);
225 channel_ = kInvalidHtpHandle;
226 return NULL;
228 if (result < static_cast<int>(sizeof(RpcHeader))) {
229 for (size_t i = 0; i < message.handle_count; ++i) {
230 Close(handles_[i]);
232 Close(channel_);
233 channel_ = kInvalidHtpHandle;
234 return NULL;
236 handle_count_ = message.handle_count;
237 if (request && header->Equals(*request)) {
238 // Received the response for the request.
239 if (length != 0) {
240 *length = result;
242 return header;
244 RpcStack stack(this);
245 stack.Alloc(result);
246 result = Dispatch(header, result);
247 if (result == -1) {
248 // Send back a truncated header to indicate failure.
249 clear_handle_count();
250 IOVec iov = {
251 const_cast<RpcHeader*>(request),
252 offsetof(RpcHeader, error_code)
254 Respond(request, &iov, 1);
256 if (header->type == RPC_DESTROY) {
257 return NULL;
262 int NPBridge::Dispatch(RpcHeader* request, int len) {
263 RpcArg arg(this, request, len);
264 if (len < static_cast<int>(sizeof(RpcHeader) + sizeof(NPCapability))) {
265 return -1;
267 arg.Step(sizeof(RpcHeader));
268 const NPCapability* capability = arg.GetCapability();
269 assert(capability);
271 switch (request->type) {
272 case RPC_SET_EXCEPTION: {
273 NPObjectStub* stub = GetStub(*capability);
274 if (stub != NULL) {
275 return stub->Dispatch(request, len);
277 NPObjectProxy* proxy = LookupProxy(*capability);
278 if (proxy != NULL) {
279 return proxy->SetException(request, len);
281 break;
283 case RPC_DEALLOCATE:
284 case RPC_INVALIDATE:
285 case RPC_HAS_METHOD:
286 case RPC_INVOKE:
287 case RPC_INVOKE_DEFAULT:
288 case RPC_HAS_PROPERTY:
289 case RPC_GET_PROPERTY:
290 case RPC_SET_PROPERTY:
291 case RPC_REMOVE_PROPERTY:
292 case RPC_ENUMERATION:
293 case RPC_CONSTRUCT: {
294 NPObjectStub* stub = GetStub(*capability);
295 if (stub != NULL) {
296 return stub->Dispatch(request, len);
298 break;
300 default:
301 break;
303 return -1;
306 int NPBridge::Respond(const RpcHeader* reply, IOVec* iov, size_t iov_length) {
307 assert(1 <= iov_length);
308 assert(channel_ != kInvalidHtpHandle);
309 assert(iov[0].base == reply);
311 HtpHeader message;
312 message.iov = iov;
313 message.iov_length = iov_length;
314 message.handles = handles_;
315 message.handle_count = handle_count_;
316 return SendDatagram(channel_, &message, 0);
319 } // namespace nacl