From 84647abdd09e96b6c76076ad04c19c2324439058 Mon Sep 17 00:00:00 2001 From: Mark Seaborn Date: Tue, 17 Mar 2009 20:07:45 +0000 Subject: [PATCH] imcplugin: Allow receiving messages from the NaCl process --- imcplugin/imcplugin.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++--- imcplugin/imcread.c | 23 +++++++++- imcplugin/imctest.html | 5 ++- imcplugin/make.sh | 3 +- 4 files changed, 136 insertions(+), 10 deletions(-) diff --git a/imcplugin/imcplugin.c b/imcplugin/imcplugin.c index fb385982..710828a4 100644 --- a/imcplugin/imcplugin.c +++ b/imcplugin/imcplugin.c @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ static NPIdentifier ident_send; #define NPN_UTF8FromIdentifier (g_funcs.utf8fromidentifier) #define NPN_GetStringIdentifier (g_funcs.getstringidentifier) #define NPN_GetURLNotify (g_funcs.geturlnotify) +#define NPN_PluginThreadAsyncCall (g_funcs.pluginthreadasynccall) static void PrintIdentifier(NPIdentifier ident) @@ -97,7 +99,7 @@ FileObj_Deallocate(NPObject *npobj) { struct FileObj *obj = (struct FileObj *) npobj; free(obj->filename); - print(("Obj_Deallocate\n")); + print(("FileObj_Deallocate\n")); } static NPClass FileObj_Vtable = { @@ -133,7 +135,7 @@ SendObj_Deallocate(NPObject *npobj) { struct SendObj *obj = (struct SendObj *) npobj; NaClDescUnref(obj->desc); - print(("Obj_Deallocate\n")); + print(("SendObj_Deallocate\n")); } static bool @@ -214,8 +216,85 @@ LauncherObj_HasMethod(NPObject* obj, NPIdentifier methodName) methodName == ident_get_file); } +struct ReceiveCallbackArgs { + NPP plugin; + NPObject *callback; + char buffer[1024]; + int size; +}; + +static void +DoReceiveCallback(void *handle) +{ + struct ReceiveCallbackArgs *call = handle; + NPVariant args[1]; + NPVariant result; + /* TODO: don't assume this data is UTF-8 */ + STRINGN_TO_NPVARIANT(call->buffer, call->size, args[0]); + NPN_InvokeDefault(call->plugin, call->callback, args, 1, &result); + NPN_ReleaseVariantValue(&result); + free(call); + /* We don't do NPN_ReleaseObject() on the callback here because we + couldn't do NPN_RetainObject() earlier. */ +} + +struct ReceiveThreadArgs { + NPP plugin; + NPObject *callback; + struct NaClDesc *desc; +}; + +static void * +ReceiveThread(void *handle) +{ + /* We create one thread for every socket we listen on. It would be + more efficient to have one thread using poll(). NPAPI doesn't + provide a way for us to share the browser's event loop. */ + struct ReceiveThreadArgs *args = handle; + struct NaClNrdXferEffector effector; + if(!NaClNrdXferEffectorCtor(&effector, args->desc)) + return NULL; + while(true) { + struct ReceiveCallbackArgs *call = + malloc(sizeof(struct ReceiveCallbackArgs)); + if(call == NULL) + break; + struct NaClImcMsgIoVec iovec; + struct NaClImcTypedMsgHdr header; + iovec.base = call->buffer; + iovec.length = sizeof(call->buffer); + header.iov = &iovec; + header.iov_length = 1; + header.ndescv = NULL; + header.ndesc_length = 0; + header.flags = 0; + int got_bytes = + NaClImcRecvTypedMessage(args->desc, (struct NaClDescEffector *) &effector, + &header, 0); + printf("ReceiveThread %i\n", got_bytes); + if(got_bytes < 0) { + free(call); + break; + } + /* We can't call NPN_RetainObject() here because it is not safe to + call it from this thread. We assume that + NPN_PluginThreadAsyncCall() schedules functions to be called in + order, so that the function is not freed until later. */ + call->plugin = args->plugin; + call->callback = args->callback; + call->size = got_bytes; + NPN_PluginThreadAsyncCall(args->plugin, DoReceiveCallback, call); + } + effector.base.vtbl->Dtor(&effector.base); + NaClDescUnref(args->desc); /* Supposed to be thread safe */ + NPN_PluginThreadAsyncCall(args->plugin, (void (*)(void *)) NPN_ReleaseObject, + args->callback); + free(args); + return NULL; +} + static struct NaClDesc * -LaunchProcess(const char *executable) +LaunchProcess(NPP plugin, const char *executable, NPObject *receive_callback) { int socks[2]; if(NaClSocketPair(socks) < 0) { @@ -258,6 +337,22 @@ LaunchProcess(const char *executable) struct NaClDesc *desc = malloc(sizeof(struct NaClDescImcDesc)); if(!NaClDescImcDescCtor((struct NaClDescImcDesc *) desc, socks[1])) return NULL; + + struct ReceiveThreadArgs *args = malloc(sizeof(struct ReceiveThreadArgs)); + if(args == NULL) + return NULL; + NaClDescRef(desc); + NPN_RetainObject(receive_callback); + args->plugin = plugin; + args->desc = desc; + args->callback = receive_callback; + pthread_t thread_id; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if(pthread_create(&thread_id, &attr, ReceiveThread, args) != 0) + return NULL; + return desc; } @@ -269,13 +364,16 @@ LauncherObj_Invoke(NPObject *npobj, NPIdentifier methodName, print(("Obj_Invoke %i\n", argCount)); PrintIdentifier(methodName); if(methodName == ident_launch) { - if(argCount == 1 && - NPVARIANT_IS_OBJECT(args[0])) { + if(argCount == 2 && + NPVARIANT_IS_OBJECT(args[0]) && + NPVARIANT_IS_OBJECT(args[1])) { NPObject *file_npobj = NPVARIANT_TO_OBJECT(args[0]); + NPObject *receive_callback = NPVARIANT_TO_OBJECT(args[1]); if(IsType(file_npobj, &FileObj_Vtable)) { struct FileObj *file_obj = (struct FileObj *) file_npobj; printf("launch %s\n", file_obj->filename); - struct NaClDesc *desc = LaunchProcess(file_obj->filename); + struct NaClDesc *desc = LaunchProcess(obj->plugin, file_obj->filename, + receive_callback); if(desc != NULL) { NPObject *send_npobj = NPN_CreateObject(obj->plugin, &SendObj_Vtable); struct SendObj *send_obj = (struct SendObj *) send_npobj; @@ -296,6 +394,8 @@ LauncherObj_Invoke(NPObject *npobj, NPIdentifier methodName, NPString url = NPVARIANT_TO_STRING(args[0]); NPObject *callback = NPVARIANT_TO_OBJECT(args[1]); NPN_RetainObject(callback); + /* TODO: I don't think utf8characters is guaranteed to be + NULL-terminated. */ NPError err = NPN_GetURLNotify(obj->plugin, url.utf8characters, NULL, callback); print(("NPN_GetUrlNotify = %i\n", err)); @@ -332,7 +432,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, NPError NPP_Destroy(NPP instance, NPSavedData **save) { - /* TODO: kill sel_ldr subprocesses */ + /* TODO: kill sel_ldr subprocesses, and do waitpid() to avoid a zombie */ print(("NPP_Destroy\n")); return NPERR_NO_ERROR; } @@ -380,6 +480,7 @@ NPP_StreamAsFile(NPP instance, NPStream *stream, const char *filename) print(("NPN_InvokeDefault %i\n", success)); NPN_ReleaseVariantValue(&result); NPN_ReleaseObject(callback); + NPN_ReleaseObject(file_npobj); } void diff --git a/imcplugin/imcread.c b/imcplugin/imcread.c index 09f63c41..adc3721c 100644 --- a/imcplugin/imcread.c +++ b/imcplugin/imcread.c @@ -1,5 +1,7 @@ #include +#include + #include #include @@ -20,6 +22,23 @@ void print_string(const char *msg, int size) printf("\"\n"); } +void send_message(int desc, char *data) +{ + struct NaClImcMsgIoVec iov; + struct NaClImcMsgHdr msg; + iov.base = data; + iov.length = strlen(data); + msg.iov = &iov; + msg.iov_length = 1; + msg.descv = NULL; + msg.desc_length = 0; + + int result = imc_sendmsg(desc, &msg, 0); + if(result < 0) { + perror("sendmsg"); + } +} + void read_message(int desc) { char buf[2000]; @@ -38,13 +57,15 @@ void read_message(int desc) perror("recvmsg"); } else { - printf("got message: "); + printf("NaCl got message: "); print_string(buf, result); } } int main(int argc, char* argv[]) { printf("NaCl module started\n"); + send_message(3, "Hello from NaCl to Javascript!"); + send_message(3, "Hello from NaCl to Javascript (message 2)"); read_message(3); return 0; } diff --git a/imcplugin/imctest.html b/imcplugin/imctest.html index 71c63840..07a5c314 100644 --- a/imcplugin/imctest.html +++ b/imcplugin/imctest.html @@ -7,9 +7,12 @@ Testing plugin... function onload() { try { var plugin = document.getElementById("plugin"); + function receive(msg) { + dump("Javascript got message: \"" + msg + "\"\n"); + } plugin.get_file("imcread", function(file) { dump("got file: " + file + "\n"); - var proc = plugin.launch(file); + var proc = plugin.launch(file, receive); dump("proc = " + proc + "\n"); proc.send("Hello from Javascript to NaCl!"); }); diff --git a/imcplugin/make.sh b/imcplugin/make.sh index 28c2ec18..4ae807e8 100755 --- a/imcplugin/make.sh +++ b/imcplugin/make.sh @@ -7,7 +7,8 @@ libdir=scons-out/dbg-linux/lib ./tools_bin/linux/sdk/nacl-sdk/bin/nacl-gcc \ -static -Wall imcplugin/imcread.c -o imcplugin/imcread -gcc $(pkg-config xulrunner-plugin --cflags --libs) \ +# Needs xulrunner-1.9-dev rather than libxul-dev on hardy +gcc $(pkg-config mozilla-plugin --cflags --libs) \ -DNACL_LINUX -I.. \ -Wall -Wl,-z,defs -shared -fPIC imcplugin/imcplugin.c \ -o imcplugin/plugin.so \ -- 2.11.4.GIT