Load 57 into trunk.
[nativeclient.git] / npapi_plugin / srpc / plugin.cc
blob6f831fbcbdd4e721dd0fcb4da557f3d58f786ecf
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 #include <assert.h>
34 #include <new>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <string>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <string>
45 #include "native_client/nonnacl_util/sel_ldr_launcher.h"
46 #include "native_client/tools/npapi_runtime/nacl_npapi.h"
48 #include "native_client/npapi_plugin/origin.h"
49 #include "native_client/npapi_plugin/srpc/closure.h"
50 #include "native_client/npapi_plugin/srpc/npapi_native.h"
51 #include "native_client/npapi_plugin/srpc/plugin.h"
52 #include "native_client/npapi_plugin/srpc/srpc.h"
53 #include "native_client/npapi_plugin/srpc/connected_socket.h"
54 #include "native_client/npapi_plugin/srpc/service_runtime_interface.h"
55 #include "native_client/npapi_plugin/srpc/shared_memory.h"
56 #include "native_client/npapi_plugin/srpc/video.h"
57 #include "native_client/npapi_plugin/srpc/utility.h"
59 #include "native_client/service_runtime/include/sys/fcntl.h"
60 #include "native_client/service_runtime/nacl_desc_io.h"
61 #include "native_client/service_runtime/nacl_host_desc.h"
62 #include "native_client/service_runtime/nacl_log.h"
64 namespace nacl_srpc {
66 bool Plugin::identifiers_initialized = false;
67 NPIdentifier Plugin::kConnectIdent;
68 NPIdentifier Plugin::kHeightIdent;
69 NPIdentifier Plugin::kHrefIdent;
70 NPIdentifier Plugin::kLengthIdent;
71 NPIdentifier Plugin::kLocationIdent;
72 NPIdentifier Plugin::kMapIdent;
73 NPIdentifier Plugin::kModuleReadyIdent;
74 NPIdentifier Plugin::kNullNpapiMethodIdent;
75 NPIdentifier Plugin::kOnfailIdent;
76 NPIdentifier Plugin::kOnloadIdent;
77 NPIdentifier Plugin::kReadIdent;
78 NPIdentifier Plugin::kShmFactoryIdent;
79 NPIdentifier Plugin::kSignaturesIdent;
80 NPIdentifier Plugin::kSrcIdent;
81 NPIdentifier Plugin::kToStringIdent;
82 NPIdentifier Plugin::kUrlAsNaClDescIdent;
83 NPIdentifier Plugin::kValueOfIdent;
84 NPIdentifier Plugin::kVideoUpdateModeIdent;
85 NPIdentifier Plugin::kWidthIdent;
86 NPIdentifier Plugin::kWriteIdent;
89 class LoadNaClAppNotify : public Closure {
90 public:
91 LoadNaClAppNotify(Plugin *plugin);
92 virtual ~LoadNaClAppNotify();
93 virtual void Run(NPStream* stream, const char* fname);
94 private:
95 Plugin* plugin_;
98 LoadNaClAppNotify::LoadNaClAppNotify(Plugin* plugin)
99 : plugin_(plugin) {
100 dprintf(("LoadNaClAppNotify ctor\n"));
103 LoadNaClAppNotify::~LoadNaClAppNotify() {
104 dprintf(("LoadNaClAppNotify dtor\n"));
107 void LoadNaClAppNotify::Run(NPStream* stream, const char* fname) {
108 dprintf(("LoadNaClAppNotify Run %p, %p\n", stream, fname));
109 if (NULL != fname) {
110 plugin_->set_local_url(fname);
111 plugin_->Load();
115 char *MemAllocStrdup(const char *str) {
116 int lenz = strlen(str) + 1;
117 char *dup = static_cast<char *>(NPN_MemAlloc(lenz));
118 if (NULL != dup) {
119 strncpy(dup, str, lenz);
121 // else abort();
122 return dup;
125 class UrlAsNaClDescNotify : public Closure {
126 public:
127 UrlAsNaClDescNotify(Plugin *plugin, std::string url, NPObject *callback_obj);
128 virtual ~UrlAsNaClDescNotify();
129 virtual void Run(NPStream *stream, const char *fname);
130 private:
131 Plugin* plugin_;
132 std::string url_;
133 NPObject* np_callback_;
136 UrlAsNaClDescNotify::UrlAsNaClDescNotify(Plugin* plugin,
137 std::string url,
138 NPObject *callback_obj) :
139 plugin_(plugin),
140 url_(url),
141 np_callback_(callback_obj) {
142 dprintf(("UrlAsNaClDescNotify ctor\n"));
143 NPN_RetainObject(np_callback_);
146 UrlAsNaClDescNotify::~UrlAsNaClDescNotify() {
147 dprintf(("UrlAsNaClDescNotify dtor\n"));
148 NPN_ReleaseObject(np_callback_);
149 np_callback_ = NULL;
152 void UrlAsNaClDescNotify::Run(NPStream *stream, const char *fname) {
153 // open file as NaClHostDesc, create NaClDesc object, make available
154 // via np_callback_
155 bool success = false;
156 NPVariant retval;
157 NPVariant status;
158 NPObject *nacl_desc = NULL;
159 NPIdentifier callback_selector = Plugin::kOnfailIdent;
161 dprintf(("UrlAsNaClDescNotify::Run(%p, %s)\n", stream, fname));
163 VOID_TO_NPVARIANT(retval);
164 VOID_TO_NPVARIANT(status);
166 // execute body once; construct to use break statement to exit body early
167 do {
169 if (NULL == fname) {
170 dprintf(("fetch failed\n"));
171 ScalarToNPVariant("URL fetch failed", &status);
172 break;
175 dprintf(("fetched FQ URL %s\n", stream->url));
176 std::string url_origin = nacl::UrlToOrigin(stream->url);
177 if (url_origin != plugin_->origin()) {
178 dprintf(("same origin policy forbids access: "
179 " page from origin %s attempted to"
180 " fetch page with origin %s\n",
181 plugin_->origin().c_str(),
182 url_origin.c_str()));
184 ScalarToNPVariant("Same origin violation", &status);
185 break;
188 NaClHostDesc *nhd = static_cast<NaClHostDesc *>(malloc(sizeof *nhd));
189 if (NULL == nhd) {
190 dprintf(("no memory for nhd\n"));
191 // TODO failure callback
193 ScalarToNPVariant("No memory for NaClHostDesc object", &status);
194 break;
196 int oserr = NaClHostDescOpen(nhd, const_cast<char *>(fname),
197 NACL_ABI_O_RDONLY, 0);
198 if (0 != oserr) {
199 dprintf(("NaClHostDescOpen failed, NaCl error %d\n", oserr));
200 free(nhd);
202 ScalarToNPVariant("NaClHostDescOpen failed", &status);
203 break;
205 NaClDescIoDesc *ndiod = NaClDescIoDescMake(nhd); // takes ownership of nhd
206 if (NULL == ndiod) {
207 dprintf(("no memory for ndiod\n"));
208 NaClHostDescClose(nhd);
209 free(nhd);
211 ScalarToNPVariant("No memory for NaClDescIoDesc object", &status);
212 break;
214 dprintf(("created ndiod %p\n", ndiod));
215 nacl_desc = UnknownHandle::New(plugin_,
216 reinterpret_cast<NaClDesc *>(ndiod));
217 callback_selector = Plugin::kOnloadIdent;
219 ScalarToNPVariant(static_cast<NPObject*>(nacl_desc), &status);
220 // NPVariant takes ownership of NPObject nacl_desc
221 } while (0);
223 dprintf(("calling np_callback_ %p, nacl_desc %p, status %p\n",
224 np_callback_, nacl_desc, &status));
225 NPN_Invoke(plugin_->npp(), np_callback_,
226 callback_selector, &status, 1, &retval);
228 dprintf(("releasing status %p\n", &status));
229 NPN_ReleaseVariantValue(&status);
230 NPN_ReleaseVariantValue(&retval);
233 bool Plugin::HasMethod(NPObject* obj, NPIdentifier name) {
234 dprintf(("Plugin::HasMethod(%p, %s)\n", obj, IdentToString(name)));
236 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
238 // Methods may be defined on the plugin as intrinsics.
239 // Test for them first.
240 if ((kShmFactoryIdent == name) || (kUrlAsNaClDescIdent == name))
241 return true;
242 // Intrinsic properties are not methods.
243 if ((kHeightIdent == name) ||
244 (kModuleReadyIdent == name) ||
245 (kSrcIdent == name) ||
246 (kVideoUpdateModeIdent == name) ||
247 (kWidthIdent == name))
248 return false;
249 // If the method was not found as an intrinsic, try the loaded module, if any.
250 if (NULL != plugin->socket_) {
251 return plugin->socket_->HasMethod(plugin->socket_, name);
253 // Otherwise, the identifier specifies an invalid method.
254 return false;
257 bool Plugin::Invoke(NPObject* obj,
258 NPIdentifier name,
259 const NPVariant *args,
260 uint32_t arg_count,
261 NPVariant *result) {
262 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
264 dprintf(("Plugin::Invoke(%p, %s, %d)\n",
265 obj, IdentToString(name), arg_count));
267 VOID_TO_NPVARIANT(*result);
268 // Methods may be defined on the plugin as intrinsics.
269 // Test for them first.
270 if (kShmFactoryIdent == name) {
271 // Type signature:
272 // SharedMemory* __shmFactory(integer)
273 if (1 != arg_count) {
274 NPN_SetException(obj, "Bad argument count to __shmFactory");
275 return false;
277 uint32_t size;
278 if (!NPVariantToScalar(&args[0], &size)) {
279 NPN_SetException(obj, "incorrect type for argument");
280 return false;
282 SharedMemory* shared_memory =
283 SharedMemory::New(plugin, static_cast<size_t>(size));
284 if (NULL == shared_memory) {
285 NPN_SetException(obj, "out of memory");
286 return false;
288 ScalarToNPVariant(static_cast<NPObject*>(shared_memory), result);
289 return true;
290 } else if (kUrlAsNaClDescIdent == name) {
291 // Type signature:
292 // __UrlAsNaClDesc(string, Function)
293 if (2 != arg_count) {
294 NPN_SetException(obj, "Bad argument count to __urlAsNaClDesc");
295 return false;
297 char* url;
298 if (!NPVariantToScalar(&args[0], &url)) {
299 NPN_SetException(obj, "Bad first argument to __urlAsNaClDesc");
300 return false;
302 NPObject* callback_obj;
303 if (!NPVariantToScalar(&args[1], &callback_obj)) {
304 NPN_SetException(obj, "Bad second argument to __urlAsNaClDesc");
305 return false;
307 dprintf(("loading %s as file\n", url));
308 UrlAsNaClDescNotify* callback =
309 new(std::nothrow) UrlAsNaClDescNotify(plugin, url, callback_obj);
310 if (NULL == callback) {
311 delete[] url;
312 NPN_SetException(obj, "Out of memory in __urlAsNaClDesc");
313 return false;
315 NPError err = NPN_GetURLNotify(plugin->npp_, url, NULL, callback);
316 delete[] url;
317 if (NPERR_NO_ERROR != err) {
318 dprintf(("failed to load URL %s to local file. Error %d\n", url, err));
319 delete callback;
320 NPN_SetException(obj, "specified url could not be loaded");
321 return false;
323 return true;
325 // If the method was not found as an intrinsic, try the loaded module, if any.
326 if (NULL != plugin->socket_) {
327 // Socket/srpc client is responsible for setting exceptions.
328 bool rv = plugin->socket_->Invoke(plugin->socket_,
329 name,
330 args,
331 arg_count,
332 result);
333 if (!rv) {
334 NPN_SetException(plugin, "Method invocation failed");
336 return rv;
338 // Otherwise, the identifier specifies an invalid method.
339 NPN_SetException(obj, "Unrecognized method specified");
340 return false;
343 bool Plugin::InvokeDefault(NPObject* obj,
344 const NPVariant* args,
345 uint32_t arg_count,
346 NPVariant* result) {
347 dprintf(("Plugin::InvokeDefault(%p, %d)\n", obj, arg_count));
349 ScalarToNPVariant(1, result);
350 return true;
353 bool Plugin::HasProperty(NPObject* obj, NPIdentifier name) {
354 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
356 dprintf(("Plugin::HasProperty(%p, %s)\n", obj, IdentToString(name)));
358 // There are some intrinsic properties to the plugin. Check for them first.
359 if ((kHeightIdent == name) ||
360 (kModuleReadyIdent == name) ||
361 (kSrcIdent == name) ||
362 (kVideoUpdateModeIdent == name) ||
363 (kWidthIdent == name)) {
364 return true;
366 // If property was not found as an intrinsic, try the loaded module, if any.
367 if (plugin->socket_) {
368 return plugin->socket_->HasProperty(plugin->socket_, name);
370 // Otherwise, the identifier specifies an invalid property.
371 return false;
374 bool Plugin::GetProperty(NPObject* obj,
375 NPIdentifier name,
376 NPVariant* variant) {
377 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
379 dprintf(("Plugin::GetProperty(%p, %s)\n", obj, IdentToString(name)));
381 VOID_TO_NPVARIANT(*variant);
382 // There are some intrinsic properties to the plugin. Check for them first.
383 if (kHeightIdent == name) {
384 ScalarToNPVariant(plugin->height_, variant);
385 return true;
386 } else if (kModuleReadyIdent == name) {
387 ScalarToNPVariant((plugin->socket_ ? 1 : 0), variant);
388 return true;
389 } else if (kSrcIdent == name) {
390 ScalarToNPVariant(plugin->local_url_, variant);
391 return true;
392 } else if (kVideoUpdateModeIdent == name) {
393 ScalarToNPVariant(plugin->video_update_mode_, variant);
394 return true;
395 } else if (kWidthIdent == name) {
396 ScalarToNPVariant(plugin->width_, variant);
397 return true;
399 // If property was not found as an intrinsic, try the loaded module, if any.
400 if (plugin->socket_) {
401 return plugin->socket_->GetProperty(plugin->socket_, name, variant);
403 // Otherwise, the identifier specifies an invalid property.
404 return false;
407 bool Plugin::SetProperty(NPObject* obj,
408 NPIdentifier name,
409 const NPVariant* variant) {
410 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
412 dprintf(("Plugin::SetProperty(%p, %s, %p)\n",
413 obj, IdentToString(name), variant));
414 dprintf(("kSrcIdent = %s\n", IdentToString(kSrcIdent)));
416 // There are some intrinsic properties to the plugin. Check for them first.
417 if (kHeightIdent == name) {
418 int32_t height;
419 if (!NPVariantToScalar(variant, &height)) {
420 NPN_SetException(obj, "height must be an integer");
421 return false;
423 plugin->height_ = height;
424 return true;
425 } else if (kModuleReadyIdent == name) {
426 // Module ready is a read-only property.
427 NPN_SetException(obj, "__moduleReady is a read-only property");
428 return false;
429 } else if (kSrcIdent == name) {
430 char* url;
431 if (!NPVariantToScalar(variant, &url)) {
432 NPN_SetException(obj, "src must be a string");
433 return false;
435 if (NULL != plugin->service_runtime_interface_) {
436 dprintf(("Plugin::SetProperty: unloading previous\n"));
437 // Plugin owns socket_, so when we change to a new socket we need to
438 // give up ownership of the old one.
439 NPN_ReleaseObject(plugin->socket_);
440 plugin->socket_ = NULL;
441 plugin->service_runtime_interface_ = NULL;
443 // Load the new module if the origin of the page is valid.
444 dprintf(("Plugin::SetProperty src = '%s'\n", url));
445 LoadNaClAppNotify* callback =
446 new(std::nothrow) LoadNaClAppNotify(plugin);
447 if (NULL == callback) {
448 NPN_SetException(obj, "setting src failed to create callback");
449 return false;
451 NPError err = NPN_GetURLNotify(plugin->npp_, url, NULL, callback);
452 if (NPERR_NO_ERROR != err) {
453 dprintf(("Failed to load URL to local file. Error %d\n", err));
454 delete callback;
455 NPN_SetException(obj, "setting src failed to load url");
456 return false;
458 return true;
459 } else if (kVideoUpdateModeIdent == name) {
460 int32_t video_update_mode;
461 if (!NPVariantToScalar(variant, &video_update_mode)) {
462 NPN_SetException(obj, "videoUpdateMode must be an integer");
463 return false;
465 plugin->video_update_mode_ = video_update_mode;
466 return true;
467 } else if (kWidthIdent == name) {
468 int32_t width;
469 if (!NPVariantToScalar(variant, &width)) {
470 NPN_SetException(obj, "width must be an integer");
471 return false;
473 plugin->width_ = width;
474 return true;
476 // If property was not found as an intrinsic, try the loaded module, if any.
477 if (plugin->socket_) {
478 return plugin->socket_->SetProperty(plugin->socket_, name, variant);
480 // Otherwise, the identifier specifies an invalid property.
481 NPN_SetException(obj, "Attempted to set unrecognized property");
482 return false;
485 Plugin* Plugin::New(NPP instance, nacl::SRPC_Plugin* srpc_plugin) {
486 static NPClass pluginClass = {
487 NP_CLASS_STRUCT_VERSION,
488 Allocate,
489 Deallocate,
490 Invalidate,
491 HasMethod,
492 Invoke,
493 InvokeDefault,
494 HasProperty,
495 GetProperty,
496 SetProperty,
498 NPVariant loc_value;
499 NPVariant href_value;
501 dprintf(("Plugin::New()\n"));
503 Plugin* plugin =
504 reinterpret_cast<Plugin*>(NPN_CreateObject(instance, &pluginClass));
505 if (NULL == plugin) {
506 return NULL;
509 if (!plugin->Start()) {
510 NPN_ReleaseObject(plugin);
511 return NULL;
513 plugin->srpc_plugin_ = srpc_plugin;
515 VOID_TO_NPVARIANT(loc_value);
516 VOID_TO_NPVARIANT(href_value);
518 do {
519 NPObject *win_obj;
520 if (NPERR_NO_ERROR
521 != NPN_GetValue(instance, NPNVWindowNPObject, &win_obj)) {
522 dprintf(("Plugin::New: No window object\n"));
523 // no window; no URL as NaCl descriptors will be allowed
524 break;
527 if (!NPN_GetProperty(instance, win_obj, kLocationIdent, &loc_value)) {
528 dprintf(("Plugin::New no location property value\n"));
529 break;
531 NPObject *loc_obj;
532 if (!NPVariantToScalar(&loc_value, &loc_obj)) {
533 dprintf(("Plugin::New location property of wrong type\n"));
534 break;
537 if (!NPN_GetProperty(instance, loc_obj, kHrefIdent, &href_value)) {
538 dprintf(("Plugin::New no href property value\n"));
539 break;
541 char* str;
542 if (!NPVariantToScalar(&href_value, &str)) {
543 dprintf(("Plugin::New href property of wrong type\n"));
544 break;
546 std::string href(str);
547 dprintf(("Plugin::New: href %s\n", href.c_str()));
549 plugin->origin_ = nacl::UrlToOrigin(href);
550 dprintf(("Plugin::New: origin %s\n", plugin->origin_.c_str()));
551 // Check that origin is in the list of permitted origins.
552 plugin->origin_valid_ = nacl::OriginIsInWhitelist(plugin->origin_);
553 // this implementation of same-origin policy does not take
554 // document.domain element into account.
556 } while (0);
558 NPN_ReleaseVariantValue(&loc_value);
559 NPN_ReleaseVariantValue(&href_value);
560 return plugin;
563 NPObject *Plugin::Allocate(NPP npp, NPClass *theClass) {
564 dprintf(("Plugin::Allocate()\n"));
566 return new(std::nothrow) Plugin(npp);
569 Plugin::Plugin(NPP npp) :
570 npp_(npp),
571 socket_(NULL),
572 service_runtime_interface_(NULL),
573 local_url_(NULL),
574 height_(0),
575 video_update_mode_(nacl::kVideoUpdatePluginPaint),
576 width_(0),
577 effp_(NULL) {
579 dprintf(("Plugin::Plugin(%p)\n", this));
581 if (!identifiers_initialized) {
582 kConnectIdent = NPN_GetStringIdentifier("connect");
583 kHeightIdent = NPN_GetStringIdentifier("height");
584 kHrefIdent = NPN_GetStringIdentifier("href");
585 kLengthIdent = NPN_GetStringIdentifier("length");
586 kLocationIdent = NPN_GetStringIdentifier("location");
587 kMapIdent = NPN_GetStringIdentifier("map");
588 kModuleReadyIdent = NPN_GetStringIdentifier("__moduleReady");
589 kNullNpapiMethodIdent = NPN_GetStringIdentifier("__nullNpapiMethod");
590 kOnfailIdent = NPN_GetStringIdentifier("onfail");
591 kOnloadIdent = NPN_GetStringIdentifier("onload");
592 kReadIdent = NPN_GetStringIdentifier("read");
593 kShmFactoryIdent = NPN_GetStringIdentifier("__shmFactory");
594 kSignaturesIdent = NPN_GetStringIdentifier("__signatures");
595 kSrcIdent = NPN_GetStringIdentifier("src");
596 kToStringIdent = NPN_GetStringIdentifier("toString");
597 kUrlAsNaClDescIdent = NPN_GetStringIdentifier("__urlAsNaClDesc");
598 kValueOfIdent = NPN_GetStringIdentifier("valueOf");
599 kVideoUpdateModeIdent = NPN_GetStringIdentifier("videoUpdateMode");
600 kWidthIdent = NPN_GetStringIdentifier("width");
601 kWriteIdent = NPN_GetStringIdentifier("write");
603 identifiers_initialized = true;
607 bool Plugin::Start() {
608 struct NaClDesc* pair[2];
610 if (0 != NaClCommonDescMakeBoundSock(pair)) {
611 dprintf(("Plugin::Plugin: make bound sock failed.\n"));
612 return false;
614 if (!NaClNrdXferEffectorCtor(&eff_, pair[0])) {
615 dprintf(("Plugin::Plugin: EffectorCtor failed.\n"));
616 return false;
618 effp_ = (struct NaClDescEffector*) &eff_;
619 return true;
622 Plugin::~Plugin() {
623 dprintf(("Plugin::~Plugin(%p)\n", this));
625 if (NULL != local_url_)
626 NPN_MemFree(local_url_);
629 void Plugin::Deallocate(NPObject* obj) {
630 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
632 dprintf(("Plugin::Deallocate(%p)\n", plugin));
634 // hard shutdown
635 if (NULL != plugin->service_runtime_interface_) {
636 plugin->service_runtime_interface_->Shutdown();
638 // Free the connected socket for this plugin, if any.
639 if (NULL != plugin->socket_) {
640 dprintf(("Plugin::Deallocate: unloading\n"));
641 // Deallocating a plugin releases ownership of the socket.
642 NPN_ReleaseObject(plugin->socket_);
644 // Clear the pointers to the connected socket and service runtime interface.
645 plugin->socket_ = NULL;
646 plugin->service_runtime_interface_ = NULL;
647 // Delete this plugin instance.
648 delete plugin;
651 void Plugin::Invalidate(NPObject* obj) {
652 Plugin* plugin = reinterpret_cast<Plugin*>(obj);
654 dprintf(("Plugin::Invalidate(%p)\n", obj));
656 // perhaps change to do soft shutdown here?
657 if (NULL != plugin->service_runtime_interface_) {
658 plugin->service_runtime_interface_->Shutdown();
659 // TODO: this needs to free the interface and set it to NULL.
661 // After invalidation, the browser does not respect reference counting,
662 // so we shut down here what we can and prevent attempts to shut down
663 // other linked structures in Deallocate.
666 void Plugin::set_local_url(const char* name) {
667 dprintf(("Plugin::set_local_url(%s)\n", name));
668 local_url_ = MemAllocStrdup(name);
671 // Create a new service node from a downloaded service.
672 bool Plugin::Load() {
673 dprintf(("Plugin::Load(%s)\n", local_url_));
674 // If the origin is not in the whitelist, refuse to load.
675 if (!origin_valid_) {
676 printf("Load failed: NaCl module did not come from a whitelisted"
677 " source.\nSee npapi_plugin/origin.cc for the list.");
678 NPObject* window;
679 NPN_GetValue(npp(), NPNVWindowNPObject, &window);
680 NPString script;
681 script.utf8characters = "alert('Load failed: NaCl module did not"
682 " come from a whitelisted source.\\n"
683 "See npapi_plugin/origin.cc"
684 " for the list.');";
685 script.utf8length = strlen(script.utf8characters);
686 NPVariant result;
687 NPN_Evaluate(npp(), window, &script, &result);
688 return false;
690 // Catch any bad accesses, etc., while loading.
691 nacl_srpc::ScopedCatchSignals sigcatcher(
692 (nacl_srpc::ScopedCatchSignals::SigHandlerType) SignalHandler);
693 if (int signal_value = PLUGIN_SETJMP(loader_env, 1)) {
694 return false;
697 dprintf(("Load: NaCl module from '%s'\n", local_url_));
699 // check ABI version compatibility
700 NPError np = nacl::CheckExecutableVersion(npp(), local_url_);
701 if (NPERR_NO_ERROR != np) {
702 dprintf(("Load: FAILED due to possible ABI version mismatch\n"));
703 return false;
705 // Load a file via a forked sel_ldr process.
706 service_runtime_interface_ = new(std::nothrow) ServiceRuntimeInterface(this);
707 if (NULL == service_runtime_interface_) {
708 dprintf((" ServiceRuntimeInterface Ctor failed\n"));
709 return false;
711 if (!service_runtime_interface_->Start(local_url_)) {
712 dprintf((" Load: FAILED to start service runtime"));
713 return false;
715 dprintf((" Load: started sel_ldr\n"));
716 socket_ = service_runtime_interface_->default_socket();
717 dprintf((" Load: established socket %p\n", socket_));
718 // Plugin takes ownership of socket_ from service_runtime_interface_,
719 // so we do not need to call NPN_RetainObject.
720 return true;
723 void Plugin::SignalHandler(int value) {
724 dprintf(("Plugin::SignalHandler()\n"));
725 PLUGIN_LONGJMP(loader_env, value);
729 PLUGIN_JMPBUF Plugin::loader_env;
732 } // namespace nacl_srpc