OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2008 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can | |
4 * be found in the LICENSE file. | |
5 */ | |
6 | |
7 #include "native_client/src/trusted/plugin/srpc/plugin.h" | |
8 | |
9 #include <assert.h> | |
10 #include <fcntl.h> | |
11 #include <stdarg.h> | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
14 #include <string.h> | |
15 | |
16 #include <sys/types.h> | |
17 #include <sys/stat.h> | |
18 | |
19 #include "native_client/src/include/nacl_string.h" | |
20 #include "native_client/src/include/portability_string.h" | |
21 #include "native_client/src/trusted/desc/nacl_desc_base.h" | |
22 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h" | |
23 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | |
24 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h" | |
25 #include "native_client/src/trusted/plugin/npapi/video.h" | |
26 #include "native_client/src/trusted/plugin/origin.h" | |
27 #include "native_client/src/trusted/plugin/srpc/browser_interface.h" | |
28 #include "native_client/src/trusted/plugin/srpc/connected_socket.h" | |
29 #include "native_client/src/trusted/plugin/srpc/nexe_arch.h" | |
30 #include "native_client/src/trusted/plugin/srpc/scriptable_handle.h" | |
31 #include "native_client/src/trusted/plugin/srpc/service_runtime.h" | |
32 #include "native_client/src/trusted/plugin/srpc/shared_memory.h" | |
33 #include "native_client/src/trusted/plugin/srpc/socket_address.h" | |
34 #include "native_client/src/trusted/plugin/srpc/stream_shm_buffer.h" | |
35 #include "native_client/src/trusted/plugin/srpc/string_encoding.h" | |
36 #include "native_client/src/trusted/plugin/srpc/utility.h" | |
37 | |
38 namespace { | |
39 | |
40 static int32_t stringToInt32(char* src) { | |
41 return strtol(src, // NOLINT(runtime/deprecated_fn) | |
42 static_cast<char**>(NULL), 0); | |
43 } | |
44 | |
45 // TODO(sehr): using a static jmpbuf here has several problems. Notably we | |
46 // cannot reliably handle errors when there are multiple plugins in the same | |
47 // process. Issue 605. | |
48 PLUGIN_JMPBUF g_LoaderEnv; | |
49 | |
50 bool ShmFactory(void* obj, plugin::SrpcParams* params) { | |
51 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
52 | |
53 plugin::SharedMemory* portable_shared_memory = | |
54 plugin::SharedMemory::New(plugin, params->ins()[0]->u.ival); | |
55 plugin::ScriptableHandle* shared_memory = | |
56 plugin->browser_interface()->NewScriptableHandle(portable_shared_memory); | |
57 if (NULL == shared_memory) { | |
58 params->set_exception_string("out of memory"); | |
59 portable_shared_memory->Delete(); | |
60 return false; | |
61 } | |
62 | |
63 params->outs()[0]->tag = NACL_SRPC_ARG_TYPE_OBJECT; | |
64 params->outs()[0]->u.oval = shared_memory; | |
65 return true; | |
66 } | |
67 | |
68 bool DefaultSocketAddress(void* obj, plugin::SrpcParams* params) { | |
69 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
70 if (NULL == plugin->socket_address()) { | |
71 params->set_exception_string("no socket address"); | |
72 return false; | |
73 } | |
74 plugin->socket_address()->AddRef(); | |
75 // Plug the scriptable object into the return values. | |
76 params->outs()[0]->tag = NACL_SRPC_ARG_TYPE_OBJECT; | |
77 params->outs()[0]->u.oval = plugin->socket_address(); | |
78 return true; | |
79 } | |
80 | |
81 // A method to test the cost of invoking a method in a plugin without | |
82 // making an RPC to the service runtime. Used for performance evaluation. | |
83 bool NullPluginMethod(void* obj, plugin::SrpcParams* params) { | |
84 UNREFERENCED_PARAMETER(obj); | |
85 params->outs()[0]->tag = NACL_SRPC_ARG_TYPE_INT; | |
86 params->outs()[0]->u.ival = 0; | |
87 return true; | |
88 } | |
89 | |
90 bool GetModuleReadyProperty(void* obj, plugin::SrpcParams* params) { | |
91 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
92 if (plugin->socket()) { | |
93 params->outs()[0]->u.ival = 1; | |
94 } else { | |
95 params->outs()[0]->u.ival = 0; | |
96 } | |
97 return true; | |
98 } | |
99 | |
100 bool SetModuleReadyProperty(void* obj, plugin::SrpcParams* params) { | |
101 UNREFERENCED_PARAMETER(obj); | |
102 params->set_exception_string("__moduleReady is a read-only property"); | |
103 return false; | |
104 } | |
105 | |
106 bool GetNexesProperty(void* obj, plugin::SrpcParams* params) { | |
107 UNREFERENCED_PARAMETER(obj); | |
108 UNREFERENCED_PARAMETER(params); | |
109 // Note, "get" must be present in the method map for "set" to work. | |
110 PLUGIN_PRINTF(("GetNexesProperty not yet implemented.\n")); | |
111 return false; | |
112 } | |
113 | |
114 // Update "nexes", a write-only property that computes a value to | |
115 // assign to the "src" property based on the supported sandbox. | |
116 bool SetNexesProperty(void* obj, plugin::SrpcParams* params) { | |
117 return reinterpret_cast<plugin::Plugin*>(obj)-> | |
118 SetNexesPropertyImpl(params->ins()[0]->u.sval); | |
119 } | |
120 | |
121 bool GetSrcProperty(void* obj, plugin::SrpcParams* params) { | |
122 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
123 if (plugin->logical_url() != NULL) { | |
124 params->outs()[0]->u.sval = strdup(plugin->logical_url()); | |
125 PLUGIN_PRINTF(("GetSrcProperty 'src' = %s\n", plugin->logical_url())); | |
126 return true; | |
127 } else { | |
128 // (NULL is not an acceptable SRPC result.) | |
129 PLUGIN_PRINTF(("GetSrcProperty 'src' failed\n")); | |
130 return false; | |
131 } | |
132 } | |
133 | |
134 bool SetSrcProperty(void* obj, plugin::SrpcParams* params) { | |
135 PLUGIN_PRINTF(("SetSrcProperty\n")); | |
136 return reinterpret_cast<plugin::Plugin*>(obj)-> | |
137 SetSrcPropertyImpl(params->ins()[0]->u.sval); | |
138 } | |
139 | |
140 bool GetHeightProperty(void* obj, plugin::SrpcParams* params) { | |
141 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
142 params->outs()[0]->u.ival = plugin->height(); | |
143 return true; | |
144 } | |
145 | |
146 bool SetHeightProperty(void* obj, plugin::SrpcParams* params) { | |
147 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
148 plugin->set_height(params->ins()[0]->u.ival); | |
149 return true; | |
150 } | |
151 | |
152 bool GetWidthProperty(void* obj, plugin::SrpcParams* params) { | |
153 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
154 params->outs()[0]->u.ival = plugin->width(); | |
155 return true; | |
156 } | |
157 | |
158 bool SetWidthProperty(void* obj, plugin::SrpcParams* params) { | |
159 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
160 plugin->set_width(params->ins()[0]->u.ival); | |
161 return true; | |
162 } | |
163 | |
164 bool GetVideoUpdateModeProperty(void* obj, plugin::SrpcParams* params) { | |
165 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
166 params->outs()[0]->u.ival = plugin->video_update_mode(); | |
167 return true; | |
168 } | |
169 | |
170 bool SetVideoUpdateModeProperty(void* obj, plugin::SrpcParams* params) { | |
171 plugin::Plugin* plugin = reinterpret_cast<plugin::Plugin*>(obj); | |
172 plugin->set_video_update_mode(params->ins()[0]->u.ival); | |
173 return true; | |
174 } | |
175 | |
176 void SignalHandler(int value) { | |
177 PLUGIN_PRINTF(("Plugin::SignalHandler()\n")); | |
178 PLUGIN_LONGJMP(g_LoaderEnv, value); | |
179 } | |
180 | |
181 } // namespace | |
182 | |
183 namespace plugin { | |
184 | |
185 // TODO(mseaborn): Although this will usually not block, it will | |
186 // block if the socket's buffer fills up. | |
187 bool Plugin::SendAsyncMessage(void* obj, SrpcParams* params, | |
188 nacl::DescWrapper** fds, int fds_count) { | |
189 Plugin* plugin = reinterpret_cast<Plugin*>(obj); | |
190 if (plugin->service_runtime_ == NULL) { | |
191 params->set_exception_string("No subprocess running"); | |
192 return false; | |
193 } | |
194 | |
195 // TODO(mseaborn): Handle strings containing NULLs. This might | |
196 // involve using a different SRPC type. | |
197 char* utf8string = params->ins()[0]->u.sval; | |
198 char* data; | |
199 size_t data_size; | |
200 if (!ByteStringFromUTF8(utf8string, strlen(utf8string), &data, &data_size)) { | |
201 params->set_exception_string("Invalid string"); | |
202 return false; | |
203 } | |
204 nacl::DescWrapper::MsgIoVec iov; | |
205 nacl::DescWrapper::MsgHeader message; | |
206 iov.base = data; | |
207 iov.length = static_cast<nacl_abi_size_t>(data_size); | |
208 message.iov = &iov; | |
209 message.iov_length = 1; | |
210 message.ndescv = fds; | |
211 message.ndescv_length = fds_count; | |
212 message.flags = 0; | |
213 nacl::DescWrapper* socket = plugin->service_runtime_->async_send_desc; | |
214 ssize_t sent = socket->SendMsg(&message, 0); | |
215 free(data); | |
216 if (sent < 0) { | |
217 params->set_exception_string("Error sending message"); | |
218 return false; | |
219 } | |
220 return true; | |
221 } | |
222 | |
223 // TODO(mseaborn): Combine __sendAsyncMessage0 and __sendAsyncMessage1 | |
224 // into a single method that takes an array of FDs. SRPC does not | |
225 // provide a handle array type so there is not a simple way to do | |
226 // this. | |
227 bool Plugin::SendAsyncMessage0(void* obj, SrpcParams* params) { | |
228 return SendAsyncMessage(obj, params, NULL, 0); | |
229 } | |
230 | |
231 bool Plugin::SendAsyncMessage1(void* obj, SrpcParams* params) { | |
232 Plugin* plugin = reinterpret_cast<Plugin*>(obj); | |
233 nacl::DescWrapper* fd_to_send = | |
234 plugin->wrapper_factory()->MakeGeneric(params->ins()[1]->u.hval); | |
235 return SendAsyncMessage(obj, params, &fd_to_send, 1); | |
236 } | |
237 | |
238 static int const kAbiHeaderBuffer = 256; // must be at least EI_ABIVERSION + 1 | |
239 | |
240 void Plugin::LoadMethods() { | |
241 // Methods supported by Plugin. | |
242 AddMethodCall(ShmFactory, "__shmFactory", "i", "h"); | |
243 AddMethodCall(DefaultSocketAddress, "__defaultSocketAddress", "", "h"); | |
244 AddMethodCall(NullPluginMethod, "__nullPluginMethod", "s", "i"); | |
245 AddMethodCall(SendAsyncMessage0, "__sendAsyncMessage0", "s", ""); | |
246 AddMethodCall(SendAsyncMessage1, "__sendAsyncMessage1", "sh", ""); | |
247 // Properties implemented by Plugin. | |
248 AddPropertyGet(GetHeightProperty, "height", "i"); | |
249 AddPropertySet(SetHeightProperty, "height", "i"); | |
250 AddPropertyGet(GetModuleReadyProperty, "__moduleReady", "i"); | |
251 AddPropertySet(SetModuleReadyProperty, "__moduleReady", "i"); | |
252 AddPropertyGet(GetNexesProperty, "nexes", "s"); | |
253 AddPropertySet(SetNexesProperty, "nexes", "s"); | |
254 AddPropertyGet(GetSrcProperty, "src", "s"); | |
255 AddPropertySet(SetSrcProperty, "src", "s"); | |
256 AddPropertyGet(GetVideoUpdateModeProperty, "videoUpdateMode", "i"); | |
257 AddPropertySet(SetVideoUpdateModeProperty, "videoUpdateMode", "i"); | |
258 AddPropertyGet(GetWidthProperty, "width", "i"); | |
259 AddPropertySet(SetWidthProperty, "width", "i"); | |
260 } | |
261 | |
262 bool Plugin::HasMethodEx(uintptr_t method_id, CallType call_type) { | |
263 if (NULL == socket_) { | |
264 return false; | |
265 } | |
266 return socket_->handle()->HasMethod(method_id, call_type); | |
267 } | |
268 | |
269 bool Plugin::InvokeEx(uintptr_t method_id, | |
270 CallType call_type, | |
271 SrpcParams* params) { | |
272 if (NULL == socket_) { | |
273 return false; | |
274 } | |
275 return socket_->handle()->Invoke(method_id, call_type, params); | |
276 } | |
277 | |
278 bool Plugin::InitParamsEx(uintptr_t method_id, | |
279 CallType call_type, | |
280 SrpcParams* params) { | |
281 if (NULL == socket_) { | |
282 return false; | |
283 } | |
284 return socket_->handle()->InitParams(method_id, call_type, params); | |
285 } | |
286 | |
287 | |
288 bool Plugin::SetNexesPropertyImpl(const char* nexes_attr) { | |
289 PLUGIN_PRINTF(("Plugin::SetNexesPropertyImpl: %s\n", nexes_attr)); | |
290 nacl::string result; | |
291 if (!GetNexeURL(nexes_attr, &result)) { | |
292 // TODO(adonovan): Ideally we would print to the browser's | |
293 // JavaScript console: alert popups are annoying, and no-one can | |
294 // be expected to read stderr. | |
295 PLUGIN_PRINTF(("%s\n", result.c_str())); | |
296 browser_interface()->Alert(instance_id(), result); | |
297 return false; | |
298 } else { | |
299 return SetSrcPropertyImpl(result); | |
300 } | |
301 } | |
302 | |
303 bool Plugin::SetSrcPropertyImpl(const nacl::string& url) { | |
304 if (NULL != service_runtime_) { | |
305 PLUGIN_PRINTF(("Plugin::SetProperty: unloading previous\n")); | |
306 // Plugin owns socket_address_ and socket_, so when we change to a new | |
307 // socket we need to give up ownership of the old one. | |
308 socket_address_->Unref(); | |
309 socket_address_ = NULL; | |
310 socket_->Unref(); | |
311 socket_ = NULL; | |
312 service_runtime_->Shutdown(); | |
313 delete service_runtime_; | |
314 service_runtime_ = NULL; | |
315 ShutDownReceiveThread(); | |
316 } | |
317 return RequestNaClModule(url); | |
318 } | |
319 | |
320 bool Plugin::Init(BrowserInterface* browser_interface, | |
321 InstanceIdentifier instance_id, | |
322 int argc, | |
323 char* argn[], | |
324 char* argv[]) { | |
325 PLUGIN_PRINTF(("Plugin::Init: instance_id=%p\n", | |
326 reinterpret_cast<void*>(instance_id))); | |
327 | |
328 browser_interface_ = browser_interface; | |
329 instance_id_ = instance_id; | |
330 // Remember the embed/object argn/argv pairs. | |
331 argn_ = new(std::nothrow) char*[argc]; | |
332 argv_ = new(std::nothrow) char*[argc]; | |
333 argc_ = 0; | |
334 // Set up the height and width attributes if passed (for Opera) | |
335 for (int i = 0; i < argc; ++i) { | |
336 if (!strncmp(argn[i], "height", 7)) { | |
337 set_height(stringToInt32(argv[i])); | |
338 } else if (!strncmp(argn[i], "width", 6)) { | |
339 set_width(stringToInt32(argv[i])); | |
340 } else if (!strncmp(argn[i], "update", 7)) { | |
341 set_video_update_mode(stringToInt32(argv[i])); | |
342 } else { | |
343 if (NULL != argn_ && NULL != argv_) { | |
344 argn_[argc_] = strdup(argn[i]); | |
345 argv_[argc_] = strdup(argv[i]); | |
346 if (NULL == argn_[argc_] || | |
347 NULL == argv_[argc_]) { | |
348 // Give up on passing arguments. | |
349 free(argn_[argc_]); | |
350 free(argv_[argc_]); | |
351 continue; | |
352 } | |
353 ++argc_; | |
354 } | |
355 } | |
356 } | |
357 // TODO(sehr): this leaks strings if there is a subsequent failure. | |
358 | |
359 // Set up the factory used to produce DescWrappers. | |
360 wrapper_factory_ = new nacl::DescWrapperFactory(); | |
361 if (NULL == wrapper_factory_) { | |
362 return false; | |
363 } | |
364 PLUGIN_PRINTF(("Plugin::Init: wrapper_factory=%p\n", | |
365 reinterpret_cast<void*>(wrapper_factory_))); | |
366 | |
367 // Check that the origin is allowed. | |
368 nacl::string href = ""; | |
369 if (browser_interface_->GetOrigin(instance_id_, &href)) { | |
370 origin_ = nacl::UrlToOrigin(href); | |
371 PLUGIN_PRINTF(("Plugin::Init: origin=%s\n", origin_.c_str())); | |
372 // Check that origin is in the list of permitted origins. | |
373 origin_valid_ = nacl::OriginIsInWhitelist(origin_); | |
374 // This implementation of same-origin policy does not take | |
375 // document.domain element into account. | |
376 } | |
377 | |
378 // Set up the scriptable methods for the plugin. | |
379 LoadMethods(); | |
380 | |
381 // If the <embed src='...'> attr was defined, the browser would have | |
382 // implicitly called GET on it, which calls Load() and set_logical_url(). | |
383 // In the absence of this attr, we use the "nexes" attribute if present. | |
384 if (logical_url() == NULL) { | |
385 const char* nexes_attr = LookupArgument("nexes"); | |
386 if (nexes_attr != NULL) { | |
387 SetNexesPropertyImpl(nexes_attr); | |
388 } | |
389 } | |
390 | |
391 PLUGIN_PRINTF(("Plugin::Init: done\n")); | |
392 // Return success. | |
393 return true; | |
394 } | |
395 | |
396 Plugin::Plugin() | |
397 : service_runtime_(NULL), | |
398 receive_thread_running_(false), | |
399 argc_(-1), | |
400 argn_(NULL), | |
401 argv_(NULL), | |
402 socket_address_(NULL), | |
403 socket_(NULL), | |
404 local_url_(NULL), | |
405 logical_url_(NULL), | |
406 origin_valid_(false), | |
407 height_(0), | |
408 width_(0), | |
409 video_update_mode_(kVideoUpdatePluginPaint), | |
410 wrapper_factory_(NULL) { | |
411 PLUGIN_PRINTF(("Plugin::Plugin(%p)\n", static_cast<void*>(this))); | |
412 } | |
413 | |
414 void Plugin::Invalidate() { | |
415 socket_address_ = NULL; | |
416 socket_ = NULL; | |
417 } | |
418 | |
419 void Plugin::ShutDownReceiveThread() { | |
420 if (receive_thread_running_) { | |
421 NaClThreadJoin(&receive_thread_); | |
422 receive_thread_running_ = false; | |
423 } | |
424 } | |
425 | |
426 Plugin::~Plugin() { | |
427 PLUGIN_PRINTF(("Plugin::~Plugin(%p)\n", static_cast<void*>(this))); | |
428 | |
429 // After invalidation, the browser does not respect reference counting, | |
430 // so we shut down here what we can and prevent attempts to shut down | |
431 // other linked structures in Deallocate. | |
432 | |
433 // Free the socket address for this plugin, if any. | |
434 if (NULL != socket_address_) { | |
435 PLUGIN_PRINTF(("Plugin::~Plugin: unloading\n")); | |
436 // Deallocating a plugin releases ownership of the socket address. | |
437 socket_address_->Unref(); | |
438 } | |
439 // Free the connected socket for this plugin, if any. | |
440 if (NULL != socket_) { | |
441 PLUGIN_PRINTF(("Plugin::~Plugin: unloading\n")); | |
442 // Deallocating a plugin releases ownership of the socket. | |
443 socket_->Unref(); | |
444 } | |
445 // Clear the pointers to the connected socket and service runtime interface. | |
446 socket_address_ = NULL; | |
447 socket_ = NULL; | |
448 delete service_runtime_; | |
449 service_runtime_ = NULL; | |
450 ShutDownReceiveThread(); | |
451 PLUGIN_PRINTF(("Plugin::~Plugin(%p)\n", static_cast<void*>(this))); | |
452 free(local_url_); | |
453 free(logical_url_); | |
454 } | |
455 | |
456 void Plugin::set_local_url(const char* url) { | |
457 PLUGIN_PRINTF(("Plugin::set_local_url(%s)\n", url)); | |
458 if (local_url_ != NULL) free(local_url_); | |
459 local_url_ = strdup(url); | |
460 } | |
461 | |
462 void Plugin::set_logical_url(const char* url) { | |
463 PLUGIN_PRINTF(("Plugin::set_logical_url(%s)\n", url)); | |
464 if (logical_url_ != NULL) free(logical_url_); | |
465 logical_url_ = strdup(url); | |
466 } | |
467 | |
468 // Create a new service node from a downloaded service. | |
469 bool Plugin::Load(nacl::string logical_url, const char* local_url) { | |
470 return Load(logical_url, local_url, static_cast<StreamShmBuffer*>(NULL)); | |
471 } | |
472 | |
473 bool Plugin::Load(nacl::string logical_url, | |
474 const char* local_url, | |
475 StreamShmBuffer* shmbufp) { | |
476 BrowserInterface* browser_interface = this->browser_interface(); | |
477 | |
478 if (NULL == shmbufp) { | |
479 PLUGIN_PRINTF(("Plugin::Load(%s)\n", local_url)); | |
480 } else { | |
481 PLUGIN_PRINTF(("Plugin::Load(%p)\n", reinterpret_cast<void*>(shmbufp))); | |
482 } | |
483 | |
484 // Save the origin and local_url. | |
485 set_nacl_module_origin(nacl::UrlToOrigin(logical_url)); | |
486 set_logical_url(logical_url.c_str()); | |
487 set_local_url(local_url); | |
488 // If the page origin where the EMBED/OBJECT tag occurs is not in | |
489 // the whitelist, refuse to load. If the NaCl module's origin is | |
490 // not in the whitelist, also refuse to load. | |
491 // TODO(adonovan): JavaScript permits cross-origin loading, and so | |
492 // does Chrome ; why don't we? | |
493 if (!origin_valid_ || !nacl::OriginIsInWhitelist(nacl_module_origin())) { | |
494 nacl::string message = nacl::string("Load failed: NaCl module ") + | |
495 logical_url + " does not come ""from a whitelisted source. " | |
496 "See native_client/src/trusted/plugin/origin.cc for the list."; | |
497 browser_interface->Alert(instance_id(), message.c_str()); | |
498 return false; | |
499 } | |
500 // Catch any bad accesses, etc., while loading. | |
501 ScopedCatchSignals sigcatcher( | |
502 (ScopedCatchSignals::SigHandlerType) SignalHandler); | |
503 if (PLUGIN_SETJMP(g_LoaderEnv, 1)) { | |
504 return false; | |
505 } | |
506 | |
507 PLUGIN_PRINTF(("Load: NaCl module from '%s'\n", local_url_)); | |
508 | |
509 // Check ELF magic and ABI version compatibility. | |
510 bool success = false; | |
511 nacl::string error_string; | |
512 if (NULL == shmbufp) { | |
513 success = browser_interface->MightBeElfExecutable(local_url_, | |
514 &error_string); | |
515 } else { | |
516 // Read out first chunk for MightBeElfExecutable; this suffices for | |
517 // ELF headers etc. | |
518 char elf_hdr_buf[kAbiHeaderBuffer]; | |
519 ssize_t result; | |
520 result = shmbufp->read(0, sizeof elf_hdr_buf, elf_hdr_buf); | |
521 if (sizeof elf_hdr_buf == result) { // (const char*)(elf_hdr_buf) | |
522 success = browser_interface->MightBeElfExecutable(elf_hdr_buf, | |
523 sizeof elf_hdr_buf, | |
524 &error_string); | |
525 } | |
526 } | |
527 if (!success) { | |
528 browser_interface->Alert(instance_id(), error_string); | |
529 return false; | |
530 } | |
531 // Load a file via a forked sel_ldr process. | |
532 service_runtime_ = new(std::nothrow) ServiceRuntime(browser_interface, this); | |
533 if (NULL == service_runtime_) { | |
534 PLUGIN_PRINTF((" ServiceRuntime Ctor failed\n")); | |
535 browser_interface->Alert(instance_id(), | |
536 "ServiceRuntime Ctor failed"); | |
537 return false; | |
538 } | |
539 bool service_runtime_started = false; | |
540 if (NULL == shmbufp) { | |
541 service_runtime_started = service_runtime_->Start(local_url_); | |
542 } else { | |
543 int32_t size; | |
544 NaClDesc* raw_desc = shmbufp->shm(&size); | |
545 if (NULL == raw_desc) { | |
546 PLUGIN_PRINTF((" extracting shm failed\n")); | |
547 return false; | |
548 } | |
549 nacl::DescWrapper* wrapped_shm = | |
550 wrapper_factory_->MakeGeneric(NaClDescRef(raw_desc)); | |
551 service_runtime_started = service_runtime_->Start(local_url_, wrapped_shm); | |
552 // Start consumes the wrapped_shm. | |
553 } | |
554 if (!service_runtime_started) { | |
555 PLUGIN_PRINTF((" Load: FAILED to start service runtime")); | |
556 browser_interface->Alert(instance_id(), | |
557 "Load: FAILED to start service runtime"); | |
558 return false; | |
559 } | |
560 | |
561 PLUGIN_PRINTF((" Load: started sel_ldr\n")); | |
562 socket_address_ = service_runtime_->default_socket_address(); | |
563 PLUGIN_PRINTF((" Load: established socket address %p\n", | |
564 static_cast<void*>(socket_address_))); | |
565 socket_ = service_runtime_->default_socket(); | |
566 PLUGIN_PRINTF((" Load: established socket %p\n", | |
567 static_cast<void*>(socket_))); | |
568 // Plugin takes ownership of socket_ from service_runtime_, | |
569 // so we do not need to call NPN_RetainObject. | |
570 // Invoke the onload handler, if any. | |
571 RunOnloadHandler(); | |
572 return true; | |
573 } | |
574 | |
575 bool Plugin::LogAtServiceRuntime(int severity, nacl::string msg) { | |
576 return service_runtime_->Log(severity, msg); | |
577 } | |
578 | |
579 char* Plugin::LookupArgument(const char* key) { | |
580 char** keys = argn(); | |
581 for (int ii = 0, len = argc(); ii < len; ++ii) { | |
582 if (!strcmp(keys[ii], key)) { | |
583 return argv()[ii]; | |
584 } | |
585 } | |
586 return NULL; | |
587 } | |
588 | |
589 bool Plugin::RunOnloadHandler() { | |
590 BrowserInterface* browser = browser_interface(); | |
591 const char* onload_handler = LookupArgument("onload"); | |
592 if (onload_handler == NULL) { | |
593 return true; | |
594 } | |
595 return browser->EvalString(instance_id(), onload_handler); | |
596 } | |
597 | |
598 bool Plugin::RunOnfailHandler() { | |
599 BrowserInterface* browser = browser_interface(); | |
600 const char* onfail_handler = LookupArgument("onfail"); | |
601 if (onfail_handler == NULL) { | |
602 return true; | |
603 } | |
604 return browser->EvalString(instance_id(), onfail_handler); | |
605 } | |
606 | |
607 // The NaCl audio/video interface uses a global mutex to protect observed | |
608 // timing-sensitive accesses to the plugin's window when starting up and | |
609 // shutting down. Because there is a relatively complex relationship between | |
610 // ConnectedSocket and Plugin to synchronize accesses, this code is built in | |
611 // both the NPAPI and PPAPI plugins. This is unfortunate, because only | |
612 // the NPAPI plugin (when not used as part of the Chrome integration) actually | |
613 // needs the locking. | |
614 // TODO(sehr): move this code to somewhere in the npapi directory. | |
615 class GlobalVideoMutex { | |
616 public: | |
617 GlobalVideoMutex() { NaClMutexCtor(&mutex_); } | |
618 ~GlobalVideoMutex() { NaClMutexDtor(&mutex_); } | |
619 void Lock() { NaClMutexLock(&mutex_); } | |
620 void Unlock() { NaClMutexUnlock(&mutex_); } | |
621 | |
622 private: | |
623 NaClMutex mutex_; | |
624 }; | |
625 | |
626 static GlobalVideoMutex g_VideoMutex; | |
627 | |
628 void VideoGlobalLock() { | |
629 g_VideoMutex.Lock(); | |
630 } | |
631 | |
632 void VideoGlobalUnlock() { | |
633 g_VideoMutex.Unlock(); | |
634 } | |
635 | |
636 } // namespace plugin | |
OLD | NEW |