blob: 81aa015342d6fcba33aae56891d6c851d97b1326 [file] [log] [blame]
// 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 <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <ppapi/cpp/completion_callback.h>
#include <ppapi/cpp/instance.h>
#include <ppapi/cpp/module.h>
#include <ppapi/cpp/var.h>
#include "eightball.h"
#include "nacl_io/nacl_io.h"
#include "reverse.h"
#if defined(NACL_SDK_DEBUG)
#define CONFIG_NAME "Debug"
#else
#define CONFIG_NAME "Release"
#endif
#if defined __arm__
#define NACL_ARCH "arm"
#elif defined __i686__
#define NACL_ARCH "x86_32"
#elif defined __x86_64__
#define NACL_ARCH "x86_64"
#else
#error "Unknown arch"
#endif
class DlOpenInstance : public pp::Instance {
public:
explicit DlOpenInstance(PP_Instance instance)
: pp::Instance(instance),
eightball_so_(NULL),
reverse_so_(NULL),
eightball_(NULL),
reverse_(NULL),
tid_(NULL) {}
virtual ~DlOpenInstance() {}
// Helper function to post a message back to the JS and stdout functions.
void logmsg(const char* pStr) {
PostMessage(pp::Var(std::string("log:") + pStr));
fprintf(stdout, pStr);
fprintf(stdout, "\n");
}
// Initialize the module, staring a worker thread to load the shared object.
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
nacl_io_init_ppapi(pp_instance(),
pp::Module::Get()->get_browser_interface());
// Mount a HTTP mount at /http. All reads from /http/* will read from the
// server.
mount("", "/http", "httpfs", 0, "");
logmsg("Spawning thread to cache .so files...");
if (pthread_create(&tid_, NULL, LoadLibrariesOnWorker, this)) {
logmsg("ERROR; pthread_create() failed.");
return false;
}
return true;
}
// This function is called on a worker thread, and will call dlopen to load
// the shared object. In addition, note that this function does NOT call
// dlclose, which would close the shared object and unload it from memory.
void LoadLibrary() {
eightball_so_ = dlopen("libeightball.so", RTLD_LAZY);
if (eightball_so_ != NULL) {
intptr_t offset = (intptr_t) dlsym(eightball_so_, "Magic8Ball");
eightball_ = (TYPE_eightball) offset;
if (NULL == eightball_) {
std::string message = "dlsym() returned NULL: ";
message += dlerror();
logmsg(message.c_str());
return;
}
logmsg("Loaded libeightball.so");
} else {
logmsg("libeightball.so did not load");
}
const char reverse_so_path[] =
"/http/glibc/" CONFIG_NAME "/libreverse_" NACL_ARCH ".so";
reverse_so_ = dlopen(reverse_so_path, RTLD_LAZY);
if (reverse_so_ != NULL) {
intptr_t offset = (intptr_t) dlsym(reverse_so_, "Reverse");
reverse_ = (TYPE_reverse) offset;
if (NULL == reverse_) {
std::string message = "dlsym() returned NULL: ";
message += dlerror();
logmsg(message.c_str());
return;
}
logmsg("Loaded libreverse.so");
} else {
logmsg("libreverse.so did not load");
}
}
// Called by the browser to handle the postMessage() call in Javascript.
virtual void HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string()) {
logmsg("Message is not a string.");
return;
}
std::string message = var_message.AsString();
if (message == "eightball") {
if (NULL == eightball_) {
logmsg("Eightball library not loaded");
return;
}
std::string ballmessage = "The Magic 8-Ball says: ";
ballmessage += eightball_();
ballmessage += "!";
logmsg(ballmessage.c_str());
} else if (message.find("reverse:") == 0) {
if (NULL == reverse_) {
logmsg("Reverse library not loaded");
return;
}
std::string s = message.substr(strlen("reverse:"));
char* result = reverse_(s.c_str());
std::string message = "Your string reversed: \"";
message += result;
message += "\"";
free(result);
logmsg(message.c_str());
} else {
std::string errormsg = "Unexpected message: ";
errormsg += message;
logmsg(errormsg.c_str());
}
}
static void* LoadLibrariesOnWorker(void* pInst) {
DlOpenInstance* inst = static_cast<DlOpenInstance*>(pInst);
inst->LoadLibrary();
return NULL;
}
private:
void* eightball_so_;
void* reverse_so_;
TYPE_eightball eightball_;
TYPE_reverse reverse_;
pthread_t tid_;
};
class DlOpenModule : public pp::Module {
public:
DlOpenModule() : pp::Module() {}
virtual ~DlOpenModule() {}
// Create and return a DlOpenInstance object.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new DlOpenInstance(instance);
}
};
namespace pp {
Module* CreateModule() { return new DlOpenModule(); }
} // namespace pp