/* * npw-rpc.c - Remote Procedure Calls (NPAPI specialisation) * * nspluginwrapper (C) 2005-2007 Gwenole Beauchesne * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdeps.h" #include #include "rpc.h" #include "npw-rpc.h" #include "utils.h" #define XP_UNIX 1 #define MOZ_X11 1 #include #include #include "npruntime-impl.h" #define DEBUG 1 #include "debug.h" /* * RPC types of NPP/NPN variables */ int rpc_type_of_NPNVariable(int variable) { int type; switch (variable) { case NPNVjavascriptEnabledBool: case NPNVasdEnabledBool: case NPNVisOfflineBool: case NPNVSupportsXEmbedBool: type = RPC_TYPE_BOOLEAN; break; case NPNVWindowNPObject: case NPNVPluginElementNPObject: type = RPC_TYPE_NP_OBJECT; break; default: type = RPC_ERROR_GENERIC; break; } return type; } int rpc_type_of_NPPVariable(int variable) { int type; switch (variable) { case NPPVpluginNameString: case NPPVpluginDescriptionString: case NPPVformValue: // byte values of 0 does not appear in the UTF-8 encoding but for U+0000 type = RPC_TYPE_STRING; break; case NPPVpluginWindowBool: case NPPVpluginTransparentBool: case NPPVpluginWindowSize: case NPPVpluginTimerInterval: type = RPC_TYPE_INT32; break; case NPPVpluginNeedsXEmbed: type = RPC_TYPE_BOOLEAN; break; case NPPVpluginScriptableNPObject: type = RPC_TYPE_NP_OBJECT; break; default: type = RPC_ERROR_GENERIC; break; } return type; } /* * Process NPP objects */ typedef struct { NPP instance; uint32_t instance_id; } PluginInstance; #ifdef BUILD_WRAPPER #define PLUGIN_INSTANCE(instance) ((instance)->pdata) #endif #ifdef BUILD_VIEWER #define PLUGIN_INSTANCE(instance) ((instance)->ndata) #endif static int do_send_NPP(rpc_message_t *message, void *p_value) { uint32_t instance_id = 0; NPP instance = (NPP)p_value; if (instance) { PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin) instance_id = plugin->instance_id; } return rpc_message_send_uint32(message, instance_id); } static int do_recv_NPP(rpc_message_t *message, void *p_value) { int error; uint32_t instance_id; if ((error = rpc_message_recv_uint32(message, &instance_id)) < 0) return error; PluginInstance *plugin = id_lookup(instance_id); if (instance_id && plugin == NULL) npw_printf("ERROR: passing an unknown instance\n"); if (plugin && plugin->instance == NULL) npw_printf("ERROR: passing a NULL instance through plugin instance id\n"); *((NPP *)p_value) = plugin ? plugin->instance : NULL; return RPC_ERROR_NO_ERROR; } /* * Process NPStream objects */ typedef struct { NPStream *stream; uint32_t stream_id; } StreamInstance; #ifdef BUILD_WRAPPER #define STREAM_INSTANCE(instance) ((instance)->pdata) #endif #ifdef BUILD_VIEWER #define STREAM_INSTANCE(instance) ((instance)->ndata) #endif static int do_send_NPStream(rpc_message_t *message, void *p_value) { uint32_t stream_id = 0; NPStream *stream = (NPStream *)p_value; if (stream) { StreamInstance *sip = STREAM_INSTANCE(stream); if (sip) stream_id = sip->stream_id; } return rpc_message_send_uint32(message, stream_id); } static int do_recv_NPStream(rpc_message_t *message, void *p_value) { int error; uint32_t stream_id; if ((error = rpc_message_recv_uint32(message, &stream_id)) < 0) return error; StreamInstance *stream = id_lookup(stream_id); *((NPStream **)p_value) = stream ? stream->stream : NULL; return RPC_ERROR_NO_ERROR; } /* * Process NPByteRange objects */ static int do_send_NPByteRange(rpc_message_t *message, void *p_value) { NPByteRange *range = (NPByteRange *)p_value; while (range) { int error; if ((error = rpc_message_send_uint32(message, 1)) < 0) return error; if ((error = rpc_message_send_int32(message, range->offset)) < 0) return error; if ((error = rpc_message_send_uint32(message, range->length)) < 0) return error; range = range->next; } return rpc_message_send_uint32(message, 0); } static int do_recv_NPByteRange(rpc_message_t *message, void *p_value) { NPByteRange **rangeListPtr = (NPByteRange **)p_value; if (rangeListPtr == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; *rangeListPtr = NULL; for (;;) { int error; uint32_t cont; if ((error = rpc_message_recv_uint32(message, &cont)) < 0) return error; if (!cont) break; NPByteRange *range = malloc(sizeof(*range)); if (range == NULL) return RPC_ERROR_NO_MEMORY; range->next = NULL; if ((error = rpc_message_recv_int32(message, &range->offset)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &range->length)) < 0) return error; *rangeListPtr = range; rangeListPtr = &range->next; } return RPC_ERROR_NO_ERROR; } /* * Process NPSavedData objects */ static int do_send_NPSavedData(rpc_message_t *message, void *p_value) { NPSavedData *save_area = (NPSavedData *)p_value; int error; if (save_area == NULL) { if ((error = rpc_message_send_int32(message, 0)) < 0) return error; } else { if ((error = rpc_message_send_int32(message, save_area->len)) < 0) return error; if ((error = rpc_message_send_bytes(message, save_area->buf, save_area->len)) < 0) return error; } return RPC_ERROR_NO_ERROR; } static int do_recv_NPSavedData(rpc_message_t *message, void *p_value) { NPSavedData *save_area; int error; int32_t len; unsigned char *buf; if ((error = rpc_message_recv_int32(message, &len)) < 0) return error; if (len == 0) save_area = NULL; else { if ((save_area = malloc(sizeof(*save_area))) == NULL) return RPC_ERROR_NO_MEMORY; if ((buf = malloc(len)) == NULL) return RPC_ERROR_NO_MEMORY; if ((error = rpc_message_recv_bytes(message, buf, len)) < 0) return error; save_area->len = len; save_area->buf = buf; } if (p_value) *((NPSavedData **)p_value) = save_area; else if (save_area) { free(save_area->buf); free(save_area); } return RPC_ERROR_NO_ERROR; } /* * Process NotifyData objects */ // Rationale: NotifyData objects are allocated on the plugin side // only. IDs are passed through to the browser, and they have no // meaning on that side as they are only used to get passed back to // the plugin side // // XXX 64-bit viewers in 32-bit wrappers are not supported static int do_send_NotifyData(rpc_message_t *message, void *p_value) { void *notifyData = (void *)p_value; return rpc_message_send_uint64(message, (uintptr_t)notifyData); } static int do_recv_NotifyData(rpc_message_t *message, void *p_value) { int error; uint64_t id; if ((error = rpc_message_recv_uint64(message, &id)) < 0) return error; if (sizeof(void *) == 4 && ((uint32_t)(id >> 32)) != 0) { npw_printf("ERROR: 64-bit viewers in 32-bit wrappers are not supported\n"); abort(); } *((void **)p_value) = (void *)(uintptr_t)id; return RPC_ERROR_NO_ERROR; } /* * Process NPRect objects */ static int do_send_NPRect(rpc_message_t *message, void *p_value) { NPRect *rect = (NPRect *)p_value; int error; if ((error = rpc_message_send_uint32(message, rect->top)) < 0) return error; if ((error = rpc_message_send_uint32(message, rect->left)) < 0) return error; if ((error = rpc_message_send_uint32(message, rect->bottom)) < 0) return error; if ((error = rpc_message_send_uint32(message, rect->right)) < 0) return error; return RPC_ERROR_NO_ERROR; } static int do_recv_NPRect(rpc_message_t *message, void *p_value) { NPRect *rect = (NPRect *)p_value; uint32_t top, left, bottom, right; int error; if ((error = rpc_message_recv_uint32(message, &top)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &left)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &bottom)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &right)) < 0) return error; rect->top = top; rect->left = left; rect->bottom = bottom; rect->right = right; return RPC_ERROR_NO_ERROR; } /* * Process NPWindow objects */ static int do_send_NPWindowData(rpc_message_t *message, void *p_value) { NPWindow *window = (NPWindow *)p_value; int error; if (window == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; if ((error = rpc_message_send_uint32(message, (Window)window->window)) < 0) return error; if ((error = rpc_message_send_int32(message, window->x)) < 0) return error; if ((error = rpc_message_send_int32(message, window->y)) < 0) return error; if ((error = rpc_message_send_uint32(message, window->width)) < 0) return error; if ((error = rpc_message_send_uint32(message, window->height)) < 0) return error; if ((error = do_send_NPRect(message, &window->clipRect)) < 0) return error; if ((error = rpc_message_send_int32(message, window->type)) < 0) return error; return RPC_ERROR_NO_ERROR; } static int do_recv_NPWindowData(rpc_message_t *message, void *p_value) { NPWindow *window = (NPWindow *)p_value; uint32_t window_id; int32_t window_type; int error; if (window == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; if ((error = rpc_message_recv_uint32(message, &window_id)) < 0) return error; if ((error = rpc_message_recv_int32(message, &window->x)) < 0) return error; if ((error = rpc_message_recv_int32(message, &window->y)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &window->width)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &window->height)) < 0) return error; if ((error = do_recv_NPRect(message, &window->clipRect)) < 0) return error; if ((error = rpc_message_recv_int32(message, &window_type)) < 0) return error; window->type = window_type; window->ws_info = NULL; // to be filled in by the plugin window->window = (void *)(Window)window_id; return RPC_ERROR_NO_ERROR; } static int do_send_NPWindow(rpc_message_t *message, void *p_value) { NPWindow *window = (NPWindow *)p_value; int error; if (window == NULL) { if ((error = rpc_message_send_uint32(message, 0)) < 0) return error; } else { if ((error = rpc_message_send_uint32(message, 1)) < 0) return error; if ((error = do_send_NPWindowData(message, window)) < 0) return error; } return RPC_ERROR_NO_ERROR; } static int do_recv_NPWindow(rpc_message_t *message, void *p_value) { NPWindow **window_p = (NPWindow **)p_value; NPWindow *window; uint32_t window_valid; int error; if (window_p) *window_p = NULL; if ((error = rpc_message_recv_uint32(message, &window_valid)) < 0) return error; if (window_valid) { if ((window = malloc(sizeof(NPWindow))) == NULL) return RPC_ERROR_NO_MEMORY; if ((error = do_recv_NPWindowData(message, window)) < 0) { free(window); return error; } if (window_p) *window_p = window; } return RPC_ERROR_NO_ERROR; } /* * Process NPFullPrint objects */ static int do_send_NPFullPrint(rpc_message_t *message, void *p_value) { NPFullPrint *fullPrint = (NPFullPrint *)p_value; int error; if ((error = rpc_message_send_uint32(message, fullPrint->pluginPrinted)) < 0) return error; if ((error = rpc_message_send_uint32(message, fullPrint->printOne)) < 0) return error; return RPC_ERROR_NO_ERROR; } static int do_recv_NPFullPrint(rpc_message_t *message, void *p_value) { NPFullPrint *fullPrint = (NPFullPrint *)p_value; uint32_t pluginPrinted, printOne; int error; if ((error = rpc_message_recv_uint32(message, &pluginPrinted)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &printOne)) < 0) return error; fullPrint->pluginPrinted = pluginPrinted; fullPrint->printOne = printOne; fullPrint->platformPrint = NULL; // to be filled in by the plugin return RPC_ERROR_NO_ERROR; } /* * Process NPEmbedPrint objects */ static int do_send_NPEmbedPrint(rpc_message_t *message, void *p_value) { NPEmbedPrint *embedPrint = (NPEmbedPrint *)p_value; int error; if ((error = do_send_NPWindowData(message, &embedPrint->window)) < 0) return error; return RPC_ERROR_NO_ERROR; } static int do_recv_NPEmbedPrint(rpc_message_t *message, void *p_value) { NPEmbedPrint *embedPrint = (NPEmbedPrint *)p_value; int error; if ((error = do_recv_NPWindowData(message, &embedPrint->window)) < 0) return error; embedPrint->platformPrint = NULL; // to be filled in by the plugin return RPC_ERROR_NO_ERROR; } /* * Process NPPrint objects */ static int do_send_NPPrint(rpc_message_t *message, void *p_value) { NPPrint *printInfo = (NPPrint *)p_value; int error; if ((error = rpc_message_send_uint32(message, printInfo->mode)) < 0) return error; switch (printInfo->mode) { case NP_FULL: if ((error = do_send_NPFullPrint(message, &printInfo->print.fullPrint)) < 0) return error; break; case NP_EMBED: if ((error = do_send_NPEmbedPrint(message, &printInfo->print.embedPrint)) < 0) return error; break; default: return RPC_ERROR_GENERIC; } return RPC_ERROR_NO_ERROR; } static int do_recv_NPPrint(rpc_message_t *message, void *p_value) { NPPrint *printInfo = (NPPrint *)p_value; uint32_t print_mode; int error; if ((error = rpc_message_recv_uint32(message, &print_mode)) < 0) return error; switch (print_mode) { case NP_FULL: if ((error = do_recv_NPFullPrint(message, &printInfo->print.fullPrint)) < 0) return error; break; case NP_EMBED: if ((error = do_recv_NPEmbedPrint(message, &printInfo->print.embedPrint)) < 0) return error; break; default: return RPC_ERROR_GENERIC; } printInfo->mode = print_mode; return RPC_ERROR_NO_ERROR; } /* * Process NPPrintData objects */ static int do_send_NPPrintData(rpc_message_t *message, void *p_value) { NPPrintData *printData = (NPPrintData *)p_value; int error; if ((error = rpc_message_send_uint32(message, printData->size)) < 0) return error; if ((error = rpc_message_send_bytes(message, printData->data, printData->size)) < 0) return error; return RPC_ERROR_NO_ERROR; } static int do_recv_NPPrintData(rpc_message_t *message, void *p_value) { NPPrintData *printData = (NPPrintData *)p_value; int error; if ((error = rpc_message_recv_uint32(message, &printData->size)) < 0) return error; if ((error = rpc_message_recv_bytes(message, printData->data, printData->size)) < 0) return error; return RPC_ERROR_NO_ERROR; } /* * Process NPObject objects */ // XXX propagate reference counters? static int do_send_NPObject(rpc_message_t *message, void *p_value) { uint32_t npobj_id = 0; NPObject *npobj = (NPObject *)p_value; if (npobj) { NPObjectInfo *npobj_info = npobject_info_lookup(npobj); if (npobj_info) npobj_id = npobj_info->npobj_id; #ifdef BUILD_WRAPPER else { // create a new mapping (browser-side) if ((npobj_info = npobject_info_new(npobj)) == NULL) return RPC_ERROR_NO_MEMORY; npobj_id = npobj_info->npobj_id; npobject_associate(npobj, npobj_info); } #endif assert(npobj_id != 0); } return rpc_message_send_uint32(message, npobj_id); } static int do_recv_NPObject(rpc_message_t *message, void *p_value) { int error; uint32_t npobj_id; if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0) return error; NPObject *npobj = NULL; if (npobj_id) { npobj = npobject_lookup(npobj_id); #ifdef BUILD_VIEWER // create a new mapping (plugin-side) if (npobj == NULL) { if ((npobj = npobject_new(npobj_id, NULL, NULL)) == NULL) return RPC_ERROR_NO_MEMORY; } #endif assert(npobj != NULL); } *((NPObject **)p_value) = npobj; return RPC_ERROR_NO_ERROR; } /* * Process NPIdentifier objects */ // Rationale: NPIdentifiers are allocated on the browser side // only. IDs are passed through to the viewer, and they have no // meaning on that side as they are only used to get passed back to // the browser side static int do_send_NPIdentifier(rpc_message_t *message, void *p_value) { NPIdentifier ident = (NPIdentifier)p_value; int id = 0; if (ident) { #ifdef BUILD_WRAPPER id = id_lookup_value(ident); if (id < 0) id = id_create(ident); #endif #ifdef BUILD_VIEWER id = (uintptr_t)ident; #endif assert(id != 0); } return rpc_message_send_uint32(message, id); } static int do_recv_NPIdentifier(rpc_message_t *message, void *p_value) { int error; uint32_t id; if ((error = rpc_message_recv_uint32(message, &id)) < 0) return error; NPIdentifier ident = NULL; if (id) { #ifdef BUILD_WRAPPER ident = id_lookup(id); #endif #ifdef BUILD_VIEWER ident = (void *)(uintptr_t)id; #endif assert(ident != NULL); } *((NPIdentifier *)p_value) = ident; return RPC_ERROR_NO_ERROR; } /* * Process NPString objects */ static int do_send_NPString(rpc_message_t *message, void *p_value) { NPString *string = (NPString *)p_value; if (string == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; int error = rpc_message_send_uint32(message, string->utf8length); if (error < 0) return error; if (string->utf8length && string->utf8characters) return rpc_message_send_bytes(message, (unsigned char *)string->utf8characters, string->utf8length); return RPC_ERROR_NO_ERROR; } static int do_recv_NPString(rpc_message_t *message, void *p_value) { NPString *string = (NPString *)p_value; if (string == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; string->utf8length = 0; string->utf8characters = NULL; int error = rpc_message_recv_uint32(message, &string->utf8length); if (error < 0) return error; if (string->utf8length > 0) { // calloc() will make the string nul-terminated, even if utf8characters is a const NPUTF8 * if ((string->utf8characters = calloc(1, string->utf8length + 1)) == NULL) return RPC_ERROR_NO_MEMORY; if ((error = rpc_message_recv_bytes(message, (unsigned char *)string->utf8characters, string->utf8length)) < 0) return error; } return RPC_ERROR_NO_ERROR; } /* * Process NPVariant objects */ static int do_send_NPVariant(rpc_message_t *message, void *p_value) { NPVariant *variant = (NPVariant *)p_value; if (variant == NULL) return RPC_ERROR_MESSAGE_ARGUMENT_INVALID; int error = rpc_message_send_uint32(message, variant->type); if (error < 0) return error; switch (variant->type) { case NPVariantType_Void: case NPVariantType_Null: // nothing to do (initialized in receiver) break; case NPVariantType_Bool: if ((error = rpc_message_send_uint32(message, variant->value.boolValue)) < 0) return error; break; case NPVariantType_Int32: if ((error = rpc_message_send_uint32(message, variant->value.intValue)) < 0) return error; break; case NPVariantType_Double: if ((error = rpc_message_send_double(message, variant->value.doubleValue)) < 0) return error; break; case NPVariantType_String: if ((error = do_send_NPString(message, &variant->value.stringValue)) < 0) return error; break; case NPVariantType_Object: if ((error = do_send_NPObject(message, variant->value.objectValue)) < 0) return error; break; } return RPC_ERROR_NO_ERROR; } static int do_recv_NPVariant(rpc_message_t *message, void *p_value) { NPVariant *variant = (NPVariant *)p_value; if (variant) VOID_TO_NPVARIANT(*variant); uint32_t type; int error = rpc_message_recv_uint32(message, &type); if (error < 0) return error; NPVariant result; VOID_TO_NPVARIANT(result); switch (type) { case NPVariantType_Void: VOID_TO_NPVARIANT(result); break; case NPVariantType_Null: NULL_TO_NPVARIANT(result); break; case NPVariantType_Bool: { uint32_t value; if ((error = rpc_message_recv_uint32(message, &value)) < 0) return error; result.value.boolValue = value; break; } case NPVariantType_Int32: if ((error = rpc_message_recv_uint32(message, &result.value.intValue)) < 0) return error; break; case NPVariantType_Double: if ((error = rpc_message_recv_double(message, &result.value.doubleValue)) < 0) return error; break; case NPVariantType_String: if ((error = do_recv_NPString(message, &result.value.stringValue)) < 0) return error; break; case NPVariantType_Object: if ((error = do_recv_NPObject(message, &result.value.objectValue)) < 0) return error; break; } if (variant) { *variant = result; variant->type = type; } return RPC_ERROR_NO_ERROR; } /* * Initialize marshalers for NPAPI types */ static const rpc_message_descriptor_t message_descs[] = { { RPC_TYPE_NPP, sizeof(NPP), do_send_NPP, do_recv_NPP }, { RPC_TYPE_NP_STREAM, sizeof(NPStream *), do_send_NPStream, do_recv_NPStream }, { RPC_TYPE_NP_BYTE_RANGE, sizeof(NPByteRange *), do_send_NPByteRange, do_recv_NPByteRange }, { RPC_TYPE_NP_SAVED_DATA, sizeof(NPSavedData *), do_send_NPSavedData, do_recv_NPSavedData }, { RPC_TYPE_NP_NOTIFY_DATA, sizeof(void *), do_send_NotifyData, do_recv_NotifyData }, { RPC_TYPE_NP_RECT, sizeof(NPRect), do_send_NPRect, do_recv_NPRect }, { RPC_TYPE_NP_WINDOW, sizeof(NPWindow *), do_send_NPWindow, do_recv_NPWindow }, { RPC_TYPE_NP_PRINT, sizeof(NPPrint), do_send_NPPrint, do_recv_NPPrint }, { RPC_TYPE_NP_FULL_PRINT, sizeof(NPFullPrint), do_send_NPFullPrint, do_recv_NPFullPrint }, { RPC_TYPE_NP_EMBED_PRINT, sizeof(NPEmbedPrint), do_send_NPEmbedPrint, do_recv_NPEmbedPrint }, { RPC_TYPE_NP_PRINT_DATA, sizeof(NPPrintData), do_send_NPPrintData, do_recv_NPPrintData }, { RPC_TYPE_NP_OBJECT, sizeof(NPObject *), do_send_NPObject, do_recv_NPObject }, { RPC_TYPE_NP_IDENTIFIER, sizeof(NPIdentifier), do_send_NPIdentifier, do_recv_NPIdentifier }, { RPC_TYPE_NP_STRING, sizeof(NPString), do_send_NPString, do_recv_NPString }, { RPC_TYPE_NP_VARIANT, sizeof(NPVariant), do_send_NPVariant, do_recv_NPVariant } }; int rpc_add_np_marshalers(void) { return rpc_message_add_callbacks(message_descs, sizeof(message_descs) / sizeof(message_descs[0])); }