diff options
Diffstat (limited to 'nacl/pepper_main.c')
-rw-r--r-- | nacl/pepper_main.c | 732 |
1 files changed, 0 insertions, 732 deletions
diff --git a/nacl/pepper_main.c b/nacl/pepper_main.c deleted file mode 100644 index 168e8f9fd4..0000000000 --- a/nacl/pepper_main.c +++ /dev/null @@ -1,732 +0,0 @@ -/****************************************************************************** - Copyright 2012 Google Inc. All Rights Reserved. - Author: yugui@google.com (Yugui Sonoda) - ******************************************************************************/ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <pthread.h> -#include <sys/stat.h> -#include <sys/mount.h> -#include <fcntl.h> -#include <pthread.h> -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/pp_module.h" -#include "ppapi/c/pp_var.h" -#include "ppapi/c/ppb.h" -#include "ppapi/c/ppb_core.h" -#include "ppapi/c/ppb_file_ref.h" -#include "ppapi/c/ppb_instance.h" -#include "ppapi/c/ppb_messaging.h" -#include "ppapi/c/ppb_url_loader.h" -#include "ppapi/c/ppb_url_request_info.h" -#include "ppapi/c/ppb_url_response_info.h" -#include "ppapi/c/ppb_var.h" -#include "ppapi/c/ppp.h" -#include "ppapi/c/ppp_instance.h" -#include "ppapi/c/ppp_messaging.h" -#include "nacl_io/nacl_io.h" - -#include "verconf.h" -#include "ruby/ruby.h" -#include "version.h" -#include "gc.h" - -#ifdef HAVE_STRUCT_PPB_CORE -typedef struct PPB_Core PPB_Core; -#endif -#ifdef HAVE_STRUCT_PPB_MESSAGING -typedef struct PPB_Messaging PPB_Messaging; -#endif -#ifdef HAVE_STRUCT_PPB_VAR -typedef struct PPB_Var PPB_Var; -#endif -#ifdef HAVE_STRUCT_PPB_URLLOADER -typedef struct PPB_URLLoader PPB_URLLoader; -#endif -#ifdef HAVE_STRUCT_PPB_URLREQUESTINFO -typedef struct PPB_URLRequestInfo PPB_URLRequestInfo; -#endif -#ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO -typedef struct PPB_URLResponseInfo PPB_URLResponseInfo; -#endif -#ifdef HAVE_STRUCT_PPP_INSTANCE -typedef struct PPP_Instance PPP_Instance; -#endif - -static PP_Module module_id = 0; -static PPB_GetInterface get_browser_interface = NULL; -static PPB_Core* core_interface = NULL; -static PPB_Messaging* messaging_interface = NULL; -static PPB_Var* var_interface = NULL; -static PPB_URLLoader* loader_interface = NULL; -static PPB_URLRequestInfo* request_interface = NULL; -static PPB_URLResponseInfo* response_interface = NULL; -static PPB_FileRef* fileref_interface = NULL; -static struct st_table* instance_data = NULL; - -static VALUE instance_table = Qundef; - -static PP_Instance current_instance = 0; - -/****************************************************************************** - * State of instance - ******************************************************************************/ - -static void inst_mark(void *const ptr); -static void inst_free(void *const ptr); -static size_t inst_memsize(void *const ptr); -static const rb_data_type_t pepper_instance_data_type = { - "PepperInstance", - { inst_mark, inst_free, inst_memsize } -}; - -struct PepperInstance { - PP_Instance instance; - PP_Resource url_loader; - VALUE self; - void* async_call_args; - union { - int32_t as_int; - const char* as_str; - VALUE as_value; - } async_call_result; - char buf[1000]; - - pthread_t th; - pthread_mutex_t mutex; - pthread_cond_t cond; -}; - -struct PepperInstance* -pruby_get_instance(PP_Instance instance) -{ - VALUE self = rb_hash_aref(instance_table, INT2FIX(instance)); - if (RTEST(self)) { - struct PepperInstance *inst; - TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst); - return inst; - } - else { - return NULL; - } -} - -#define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance)) - -struct PepperInstance* -pruby_register_instance(PP_Instance instance) -{ - VALUE obj; - struct PepperInstance *data; - obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data); - data->self = obj; - data->instance = instance; - data->url_loader = 0; - - pthread_mutex_init(&data->mutex, NULL); - pthread_cond_init(&data->cond, NULL); - - rb_hash_aset(instance_table, INT2FIX(instance), obj); - return data; -} - -int -pruby_unregister_instance(PP_Instance instance) -{ - VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance)); - return RTEST(inst); -} - -static void -inst_mark(void *const ptr) -{ - RUBY_MARK_ENTER("PepperInstance"0); - if (ptr) { - const struct PepperInstance* inst = (struct PepperInstance*)ptr; - RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value); - } - RUBY_MARK_LEAVE("PepperInstance"0); -} - -static void -inst_free(void *const ptr) -{ - ruby_xfree(ptr); -} - -static size_t -inst_memsize(void *const ptr) -{ - if (ptr) { - const struct PepperInstance* inst = (struct PepperInstance*)ptr; - return sizeof(*inst); - } else { - return 0; - } -} - -void -pruby_async_return_int(void* data, int32_t result) -{ - /* PPAPI main thread */ - struct PepperInstance* const instance = (struct PepperInstance*)data; - instance->async_call_result.as_int = result; - if (pthread_cond_signal(&instance->cond)) { - perror("pepper-ruby:pthread_cond_signal"); - } -} - -void -pruby_async_return_str(void* data, const char *result) -{ - /* PPAPI main thread */ - struct PepperInstance* const instance = (struct PepperInstance*)data; - instance->async_call_result.as_str = result; - if (pthread_cond_signal(&instance->cond)) { - perror("pepper-ruby:pthread_cond_signal"); - } -} - -void -pruby_async_return_value(void* data, VALUE value) -{ - /* PPAPI main thread */ - struct PepperInstance* const instance = (struct PepperInstance*)data; - instance->async_call_result.as_value = value; - if (pthread_cond_signal(&instance->cond)) { - perror("pepper-ruby:pthread_cond_signal"); - } -} -/****************************************************************************** - * Conversion between Ruby's VALUE, Pepper's Var and C string - ******************************************************************************/ - -/** - * Creates a new string PP_Var from C string. The resulting object will be a - * refcounted string object. It will be AddRef()ed for the caller. When the - * caller is done with it, it should be Release()d. - * @param[in] str C string to be converted to PP_Var - * @return PP_Var containing string. - */ -static struct PP_Var -pruby_cstr_to_var(const char* str) -{ -#ifndef PPB_VAR_INTERFACE_1_1 - if (var_interface != NULL) - return var_interface->VarFromUtf8(module_id, str, strlen(str)); - return PP_MakeUndefined(); -#else - return var_interface->VarFromUtf8(str, strlen(str)); -#endif -} - -/** - * Returns a mutable C string contained in the @a var or NULL if @a var is not - * string. This makes a copy of the string in the @a var and adds a NULL - * terminator. Note that VarToUtf8() does not guarantee the NULL terminator on - * the returned string. See the comments for VarToUtf8() in ppapi/c/ppb_var.h - * for more info. The caller is responsible for freeing the returned memory. - * @param[in] var PP_Var containing string. - * @return a mutable C string representation of @a var. - * @note The caller is responsible for freeing the returned string. - */ -static char* -pruby_var_to_cstr(struct PP_Var var) -{ - uint32_t len = 0; - if (var_interface != NULL) { - const char* var_c_str = var_interface->VarToUtf8(var, &len); - if (len > 0) { - char* c_str = (char*)malloc(len + 1); - memcpy(c_str, var_c_str, len); - c_str[len] = '\0'; - return c_str; - } - } - return NULL; -} - -static struct PP_Var -pruby_str_to_var(volatile VALUE str) -{ - if (!RB_TYPE_P(str, T_STRING)) { - fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str)); - exit(EXIT_FAILURE); - } -#ifndef PPB_VAR_INTERFACE_1_1 - if (var_interface != NULL) { - return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str)); - } -#else - return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str)); -#endif - return PP_MakeUndefined(); -} - -static struct PP_Var -pruby_obj_to_var(volatile VALUE obj) -{ - static const char* const error = - "throw 'Failed to convert the result to a JavaScript object';"; - int state; - obj = rb_protect(&rb_obj_as_string, obj, &state); - if (!state) { - return pruby_str_to_var(obj); - } - else { - return pruby_cstr_to_var(error); - } -} - -int -pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs) -{ - uint32_t len = 0; - if (var_interface == NULL) { - return 0; - } - else { - const char* const cstr = var_interface->VarToUtf8(lhs, &len); - return strncmp(cstr, rhs, len) == 0; - } -} - -int -pruby_var_prefixed_p(struct PP_Var var, const char* prefix) -{ - uint32_t len = 0; - if (var_interface == NULL) { - return 0; - } - else { - const char* const cstr = var_interface->VarToUtf8(var, &len); - const size_t prefix_len = strlen(prefix); - return len >= prefix_len && memcmp(cstr, prefix, len) == 0; - } -} - - -/****************************************************************************** - * Messaging - ******************************************************************************/ - -/* Posts the given C string as a message. - * @param data pointer to a NULL-terminated string */ -void -pruby_post_cstr(void* data) -{ - /* PPAPI main thread */ - struct PepperInstance* const instance = (struct PepperInstance*)data; - const char* const msg = (const char*)instance->async_call_args; - messaging_interface->PostMessage(instance->instance, - pruby_cstr_to_var(msg)); -} - -/* Posts the given Ruby VALUE as a message. - * @param data a VALUE casted to void* */ -void -pruby_post_value(void* data) -{ - /* PPAPI main thread */ - struct PepperInstance* const instance = (struct PepperInstance*)data; - volatile VALUE value = (VALUE)instance->async_call_args; - messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value)); -} - - - -/****************************************************************************** - * Ruby initialization - ******************************************************************************/ - -static void -init_loadpath(void) -{ - ruby_incpush("lib/ruby/"RUBY_LIB_VERSION); - ruby_incpush("lib/ruby/"RUBY_LIB_VERSION"/"RUBY_PLATFORM); - ruby_incpush("."); -} - -static VALUE -init_libraries_internal(VALUE unused) -{ - extern void Init_enc(); - extern void Init_ext(); - - init_loadpath(); - Init_enc(); - Init_ext(); - return Qnil; -} - -static void* -init_libraries(void* data) -{ - int state; - struct PepperInstance* const instance = (struct PepperInstance*)data; - current_instance = instance->instance; - - if (pthread_mutex_lock(&instance->mutex)) { - perror("pepper-ruby:pthread_mutex_lock"); - return 0; - } - rb_protect(&init_libraries_internal, Qnil, &state); - pthread_mutex_unlock(&instance->mutex); - - if (state) { - volatile VALUE err = rb_errinfo(); - err = rb_obj_as_string(err); - } else { - instance->async_call_args = (void*)"rubyReady"; - core_interface->CallOnMainThread( - 0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0); - } - return NULL; -} - -static int -init_libraries_if_necessary(void) -{ - static int initialized = 0; - if (!initialized) { - struct PepperInstance* const instance = GET_PEPPER_INSTANCE(); - int err; - initialized = 1; - err = pthread_create(&instance->th, NULL, &init_libraries, instance); - if (err) { - fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err)); - exit(EXIT_FAILURE); - } - pthread_detach(instance->th); - } - return 0; -} - -static int -reopen_fd(int fd, const char* path, int flags) { - int fd2 = open(path, flags); - if (fd2 < 0) { - perror("open fd"); - return -1; - } - if (dup2(fd2, fd) < 0) { - perror("dup2 fd"); - return -1; - } - if (close(fd2)) { - perror("close old fd"); - return -1; - } - return fd; -} - -static int -pruby_init(void) -{ - RUBY_INIT_STACK; - ruby_init(); - - instance_table = rb_hash_new(); - rb_gc_register_mark_object(instance_table); - - return 0; -} - - -/****************************************************************************** - * Ruby evaluation - ******************************************************************************/ - -static void* -pruby_eval(void* data) -{ - extern VALUE ruby_eval_string_from_file_protect(const char* src, const char* path, int* state); - struct PepperInstance* const instance = (struct PepperInstance*)data; - volatile VALUE src = (VALUE)instance->async_call_args; - volatile VALUE result = Qnil; - volatile int state; - - RUBY_INIT_STACK; - - if (pthread_mutex_lock(&instance->mutex)) { - perror("pepper-ruby:pthread_mutex_lock"); - return 0; - } - result = ruby_eval_string_from_file_protect( - RSTRING_PTR(src), "(pepper-ruby)", &state); - pthread_mutex_unlock(&instance->mutex); - - if (!state) { - instance->async_call_args = - rb_str_concat(rb_usascii_str_new_cstr("return:"), - rb_obj_as_string(result)); - core_interface->CallOnMainThread( - 0, PP_MakeCompletionCallback(pruby_post_value, instance), 0); - return NULL; - } - else { - rb_set_errinfo(Qnil); - instance->async_call_args = - rb_str_concat(rb_usascii_str_new_cstr("error:"), - rb_obj_as_string(result)); - core_interface->CallOnMainThread( - 0, PP_MakeCompletionCallback(pruby_post_value, instance), 0); - return NULL; - } -} - - -/****************************************************************************** - * Pepper Module callbacks - ******************************************************************************/ - -/** - * Called when the NaCl module is instantiated on the web page. The identifier - * of the new instance will be passed in as the first argument (this value is - * generated by the browser and is an opaque handle). This is called for each - * instantiation of the NaCl module, which is each time the <embed> tag for - * this module is encountered. - * - * If this function reports a failure (by returning @a PP_FALSE), the NaCl - * module will be deleted and DidDestroy will be called. - * @param[in] instance The identifier of the new instance representing this - * NaCl module. - * @param[in] argc The number of arguments contained in @a argn and @a argv. - * @param[in] argn An array of argument names. These argument names are - * supplied in the <embed> tag, for example: - * <embed id="nacl_module" dimensions="2"> - * will produce two arguments, one named "id" and one named "dimensions". - * @param[in] argv An array of argument values. These are the values of the - * arguments listed in the <embed> tag. In the above example, there will - * be two elements in this array, "nacl_module" and "2". The indices of - * these values match the indices of the corresponding names in @a argn. - * @return @a PP_TRUE on success. - */ -static PP_Bool -Instance_DidCreate(PP_Instance instance, - uint32_t argc, const char* argn[], const char* argv[]) -{ - struct PepperInstance* data = pruby_register_instance(instance); - current_instance = instance; - - nacl_io_init_ppapi(instance, get_browser_interface); - - if (mount("", "/dev2", "dev", 0, "")) { - perror("mount dev"); - return PP_FALSE; - } - if (reopen_fd(0, "/dev2/stdin", O_RDONLY) < 0) { - perror("reopen stdin"); - return PP_FALSE; - } - if (reopen_fd(1, "/dev2/stdout", O_WRONLY) < 0) { - perror("reopen stdout"); - return PP_FALSE; - } - if (reopen_fd(2, "/dev2/console1", O_WRONLY) < 0) { - perror("reopen stderr"); - return PP_FALSE; - } - - /* TODO(yugui) Unmount original /dev */ - - if (mount("/lib", "/lib", "httpfs", - 0, "allow_cross_origin_requests=false")) { - perror("mount httpfs"); - return PP_FALSE; - } - - return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE; -} - -/** - * Called when the NaCl module is destroyed. This will always be called, - * even if DidCreate returned failure. This routine should deallocate any data - * associated with the instance. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - */ -static void Instance_DidDestroy(PP_Instance instance) { - struct PepperInstance* data = pruby_get_instance(instance); - core_interface->ReleaseResource(data->url_loader); - pruby_unregister_instance(instance); -} - -/** - * Called when the position, the size, or the clip rect of the element in the - * browser that corresponds to this NaCl module has changed. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] position The location on the page of this NaCl module. This is - * relative to the top left corner of the viewport, which changes as the - * page is scrolled. - * @param[in] clip The visible region of the NaCl module. This is relative to - * the top left of the plugin's coordinate system (not the page). If the - * plugin is invisible, @a clip will be (0, 0, 0, 0). - */ -#ifndef PPP_INSTANCE_INTERFACE_1_1 -static void -Instance_DidChangeView(PP_Instance instance, - const struct PP_Rect* position, - const struct PP_Rect* clip) -{ -} -#else -static void -Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource) -{ -} -#endif - -/** - * Notification that the given NaCl module has gained or lost focus. - * Having focus means that keyboard events will be sent to the NaCl module - * represented by @a instance. A NaCl module's default condition is that it - * will not have focus. - * - * Note: clicks on NaCl modules will give focus only if you handle the - * click event. You signal if you handled it by returning @a true from - * HandleInputEvent. Otherwise the browser will bubble the event and give - * focus to the element on the page that actually did end up consuming it. - * If you're not getting focus, check to make sure you're returning true from - * the mouse click in HandleInputEvent. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] has_focus Indicates whether this NaCl module gained or lost - * event focus. - */ -static void -Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) -{ -} - -/** - * Handler that gets called after a full-frame module is instantiated based on - * registered MIME types. This function is not called on NaCl modules. This - * function is essentially a place-holder for the required function pointer in - * the PPP_Instance structure. - * @param[in] instance The identifier of the instance representing this NaCl - * module. - * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance. - * @return PP_FALSE. - */ -static PP_Bool -Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) -{ - /* NaCl modules do not need to handle the document load function. */ - return PP_FALSE; -} - - -/** - * Handler for messages coming in from the browser via postMessage. The - * @a var_message can contain anything: a JSON string; a string that encodes - * method names and arguments; etc. For example, you could use JSON.stringify - * in the browser to create a message that contains a method name and some - * parameters, something like this: - * var json_message = JSON.stringify({ "myMethod" : "3.14159" }); - * nacl_module.postMessage(json_message); - * On receipt of this message in @a var_message, you could parse the JSON to - * retrieve the method name, match it to a function call, and then call it with - * the parameter. - * @param[in] instance The instance ID. - * @param[in] message The contents, copied by value, of the message sent from - * browser via postMessage. - */ -void -Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message) -{ - char* const message = pruby_var_to_cstr(var_message); - size_t message_len = strlen(message); - current_instance = instance; - - if (strstr(message, "eval:") != NULL) { - volatile VALUE src; - struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE(); - int err; -#define EVAL_PREFIX_LEN 5 - src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN); - instance_data->async_call_args = (void*)src; - err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data); - if (err) { - fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err)); - exit(EXIT_FAILURE); - } - pthread_detach(instance_data->th); - } - free(message); -} - -/** - * Entry points for the module. - * Initialize instance interface and scriptable object class. - * @param[in] a_module_id Module ID - * @param[in] get_browser_interface Pointer to PPB_GetInterface - * @return PP_OK on success, any other value on failure. - */ -PP_EXPORT int32_t -PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface a_get_browser_interface) -{ - module_id = a_module_id; - get_browser_interface = a_get_browser_interface; - core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE)); - if (core_interface == NULL) return PP_ERROR_NOINTERFACE; - - var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE)); - if (var_interface == NULL) return PP_ERROR_NOINTERFACE; - - messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE)); - if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE; - - loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE)); - if (loader_interface == NULL) return PP_ERROR_NOINTERFACE; - - request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE)); - if (request_interface == NULL) return PP_ERROR_NOINTERFACE; - - response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE)); - if (response_interface == NULL) return PP_ERROR_NOINTERFACE; - - fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE)); - if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE; - - return pruby_init() ? PP_ERROR_FAILED : PP_OK; -} - -/** - * Returns an interface pointer for the interface of the given name, or NULL - * if the interface is not supported. - * @param[in] interface_name name of the interface - * @return pointer to the interface - */ -PP_EXPORT const void* -PPP_GetInterface(const char* interface_name) -{ - if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { - static PPP_Instance instance_interface = { - &Instance_DidCreate, - &Instance_DidDestroy, - &Instance_DidChangeView, - &Instance_DidChangeFocus, - &Instance_HandleDocumentLoad - }; - return &instance_interface; - } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) { - static PPP_Messaging messaging_interface = { - &Messaging_HandleMessage - }; - return &messaging_interface; - } - return NULL; -} - -/** - * Called before the plugin module is unloaded. - */ -PP_EXPORT void -PPP_ShutdownModule(void) -{ - ruby_cleanup(0); -} |