void MediaPluginCEF::authResponse(LLPluginMessage &message) { mAuthOK = message.getValueBoolean("ok"); if (mAuthOK) { mAuthUsername = message.getValue("username"); mAuthPassword = message.getValue("password"); } }
/* virtual */ void LLPluginProcessChild::receivePluginMessage(const std::string &message) { LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; if(mBlockingRequest) { // LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL; } // Incoming message from the plugin instance bool passMessage = true; // FIXME: how should we handle queueing here? // Intercept certain base messages (responses to ones sent by this class) { // Decode this message LLPluginMessage parsed; parsed.parse(message); if(parsed.hasValue("blocking_request")) { mBlockingRequest = true; } std::string message_class = parsed.getClass(); if(message_class == "base") { std::string message_name = parsed.getName(); if(message_name == "init_response") { // The plugin has finished initializing. setState(STATE_RUNNING); // Don't pass this message up to the parent passMessage = false; LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response"); LLSD versions = parsed.getValueLLSD("versions"); new_message.setValueLLSD("versions", versions); if(parsed.hasValue("plugin_version")) { std::string plugin_version = parsed.getValue("plugin_version"); new_message.setValueLLSD("plugin_version", plugin_version); } // Let the parent know it's loaded and initialized. sendMessageToParent(new_message); } else if(message_name == "shm_remove_response") { // Don't pass this message up to the parent passMessage = false; std::string name = parsed.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // detach the shared memory region iter->second->detach(); // and remove it from our map mSharedMemoryRegions.erase(iter); // Finally, send the response to the parent. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response"); message.setValue("name", name); sendMessageToParent(message); } else { LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL; } } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { bool flush = false; std::string message_name = parsed.getName(); if(message_name == "shutdown") { // The plugin is finished. setState(STATE_UNLOADING); flush = true; } else if (message_name == "flush") { flush = true; passMessage = false; } if (flush) { flushMessages(); } } } if(passMessage) { LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; writeMessageRaw(message); } while(mBlockingRequest) { // The plugin wants to block and wait for a response to this message. sleep(mSleepTime); // this will pump the message pipe and process messages if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL)) { // Response has been received, or we've hit an error state. Stop waiting. mBlockingRequest = false; mBlockingResponseReceived = false; } } }
// This is the SLPlugin process (the child process). // This is not part of a DSO. // // This function is called when the serialized message 'message' was received from the viewer. // It parses the message and handles LLPLUGIN_MESSAGE_CLASS_INTERNAL. // Other message classes are passed on to LLPluginInstance::sendMessage. void LLPluginProcessChild::receiveMessageRaw(const std::string &message) { // Incoming message from the TCP Socket LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL; // Decode this message LLPluginMessage parsed; parsed.parse(message); if(mBlockingRequest) { // We're blocking the plugin waiting for a response. if(parsed.hasValue("blocking_response")) { // This is the message we've been waiting for -- fall through and send it immediately. mBlockingResponseReceived = true; } else { // Still waiting. Queue this message and don't process it yet. mMessageQueue.push(message); return; } } bool passMessage = true; // FIXME: how should we handle queueing here? { std::string message_class = parsed.getClass(); if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { passMessage = false; std::string message_name = parsed.getName(); if(message_name == "load_plugin") { mPluginFile = parsed.getValue("file"); mPluginDir = parsed.getValue("dir"); } else if(message_name == "shm_add") { std::string name = parsed.getValue("name"); size_t size = (size_t)parsed.getValueS32("size"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // Need to remove the old region first LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL; } else { // This is a new region LLPluginSharedMemory *region = new LLPluginSharedMemory; if(region->attach(name, size)) { mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); std::stringstream addr; addr << region->getMappedAddress(); // Send the add notification to the plugin LLPluginMessage message("base", "shm_added"); message.setValue("name", name); message.setValueS32("size", (S32)size); message.setValuePointer("address", region->getMappedAddress()); sendMessageToPlugin(message); // and send the response to the parent message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response"); message.setValue("name", name); sendMessageToParent(message); } else { LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; delete region; } } } else if(message_name == "shm_remove") { std::string name = parsed.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // forward the remove request to the plugin -- its response will trigger us to detach the segment. LLPluginMessage message("base", "shm_remove"); message.setValue("name", name); sendMessageToPlugin(message); } else { LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL; } } else if(message_name == "sleep_time") { mSleepTime = llmax(parsed.getValueReal("time"), 1.0 / 100.0); // clamp to maximum of 100Hz } else if(message_name == "crash") { // Crash the plugin LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL; } else if(message_name == "hang") { // Hang the plugin LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL; while(1) { // wheeeeeeeee...... } } else { LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL; } } } if(passMessage && mInstance != NULL) { LLTimer elapsed; mInstance->sendMessage(message); mCPUElapsed += elapsed.getElapsedTimeF64(); } }
// This is the viewer process (the parent process). // // This function is called for messages that have to // be written to the plugin. // Note that LLPLUGIN_MESSAGE_CLASS_INTERNAL messages // are not sent to the plugin, but are handled here. void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { // internal messages should be handled here std::string message_name = message.getName(); if(message_name == "hello") { if(mState == STATE_CONNECTED) { // Plugin host has launched. Tell it which plugin to load. setState(STATE_HELLO); } else { LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL; errorState(); } } else if(message_name == "load_plugin_response") { if(mState == STATE_LOADING) { // Plugin has been loaded. mPluginVersionString = message.getValue("plugin_version"); LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL; // Check which message classes/versions the plugin supports. // TODO: check against current versions // TODO: kill plugin on major mismatches? mMessageClassVersions = message.getValueLLSD("versions"); LLSD::map_iterator iter; for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++) { LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL; } // Send initial sleep time setSleepTime(mSleepTime, true); setState(STATE_RUNNING); } else { LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL; errorState(); } } else if(message_name == "heartbeat") { // this resets our timer. mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); mCPUUsage = message.getValueReal("cpu_usage"); LL_DEBUGS("PluginHeartbeat") << "cpu usage reported as " << mCPUUsage << LL_ENDL; } else if(message_name == "shutdown") { LL_INFOS("Plugin") << "received shutdown message" << LL_ENDL; mReceivedShutdown = true; mOwner->receivedShutdown(); } else if(message_name == "shm_add_response") { // Nothing to do here. } else if(message_name == "shm_remove_response") { std::string name = message.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // destroy the shared memory region iter->second->destroy(); // and remove it from our map mSharedMemoryRegions.erase(iter); } } else if(message_name == "log_message") { std::string msg=message.getValue("message"); S32 level=message.getValueS32("log_level"); switch(level) { case LLPluginMessage::LOG_LEVEL_DEBUG: LL_DEBUGS("Plugin child")<<msg<<LL_ENDL; break; case LLPluginMessage::LOG_LEVEL_INFO: LL_INFOS("Plugin child")<<msg<<LL_ENDL; break; case LLPluginMessage::LOG_LEVEL_WARN: LL_WARNS("Plugin child")<<msg<<LL_ENDL; break; case LLPluginMessage::LOG_LEVEL_ERR: LL_ERRS("Plugin child")<<msg<<LL_ENDL; break; default: break; } } else { LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL; } } else { if(mOwner != NULL) { mOwner->receivePluginMessage(message); } } }
/* virtual */ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) { LLPluginClassBasic::receivePluginMessage(message); } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { std::string message_name = message.getName(); if(message_name == "texture_params") { mRequestedTextureDepth = message.getValueS32("depth"); mRequestedTextureInternalFormat = message.getValueU32("internalformat"); mRequestedTextureFormat = message.getValueU32("format"); mRequestedTextureType = message.getValueU32("type"); mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); // These two are optional, and will default to 0 if they're not specified. mDefaultMediaWidth = message.getValueS32("default_width"); mDefaultMediaHeight = message.getValueS32("default_height"); mAllowDownsample = message.getValueBoolean("allow_downsample"); mPadding = message.getValueS32("padding"); setSizeInternal(); mTextureParamsReceived = true; } else if(message_name == "updated") { if(message.hasValue("left")) { LLRect newDirtyRect; newDirtyRect.mLeft = message.getValueS32("left"); newDirtyRect.mTop = message.getValueS32("top"); newDirtyRect.mRight = message.getValueS32("right"); newDirtyRect.mBottom = message.getValueS32("bottom"); // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. // If they're backwards, swap them. if(newDirtyRect.mTop < newDirtyRect.mBottom) { S32 temp = newDirtyRect.mTop; newDirtyRect.mTop = newDirtyRect.mBottom; newDirtyRect.mBottom = temp; } if(mDirtyRect.isEmpty()) { mDirtyRect = newDirtyRect; } else { mDirtyRect.unionWith(newDirtyRect); } LL_DEBUGS("PluginUpdated") << "adjusted incoming rect is: (" << newDirtyRect.mLeft << ", " << newDirtyRect.mTop << ", " << newDirtyRect.mRight << ", " << newDirtyRect.mBottom << "), new dirty rect is: (" << mDirtyRect.mLeft << ", " << mDirtyRect.mTop << ", " << mDirtyRect.mRight << ", " << mDirtyRect.mBottom << ")" << LL_ENDL; mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); } bool time_duration_updated = false; int previous_percent = mProgressPercent; if(message.hasValue("current_time")) { mCurrentTime = message.getValueReal("current_time"); time_duration_updated = true; } if(message.hasValue("duration")) { mDuration = message.getValueReal("duration"); time_duration_updated = true; } if(message.hasValue("current_rate")) { mCurrentRate = message.getValueReal("current_rate"); } if(message.hasValue("loaded_duration")) { mLoadedDuration = message.getValueReal("loaded_duration"); time_duration_updated = true; } else { // If the message doesn't contain a loaded_duration param, assume it's equal to duration mLoadedDuration = mDuration; } // Calculate a percentage based on the loaded duration and total duration. if(mDuration != 0.0f) // Don't divide by zero. { mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); } if(time_duration_updated) { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); } if(previous_percent != mProgressPercent) { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); } } else if(message_name == "media_status") { std::string status = message.getValue("status"); LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; if(status == "loading") { mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; } else if(status == "loaded") { mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; } else if(status == "error") { mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; } else if(status == "playing") { mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; } else if(status == "paused") { mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; } else if(status == "done") { mStatus = LLPluginClassMediaOwner::MEDIA_DONE; } else { // empty string or any unknown string mStatus = LLPluginClassMediaOwner::MEDIA_NONE; } } else if(message_name == "size_change_request") { S32 width = message.getValueS32("width"); S32 height = message.getValueS32("height"); std::string name = message.getValue("name"); // TODO: check that name matches? mNaturalMediaWidth = width; mNaturalMediaHeight = height; setSizeInternal(); } else if(message_name == "size_change_response") { std::string name = message.getValue("name"); // TODO: check that name matches? mTextureWidth = message.getValueS32("texture_width"); mTextureHeight = message.getValueS32("texture_height"); mMediaWidth = message.getValueS32("width"); mMediaHeight = message.getValueS32("height"); // This invalidates any existing dirty rect. resetDirty(); // TODO: should we verify that the plugin sent back the right values? // Two size changes in a row may cause them to not match, due to queueing, etc. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); } else if(message_name == "cursor_changed") { mCursorName = message.getValue("name"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); } else if(message_name == "edit_state") { if(message.hasValue("cut")) { mCanCut = message.getValueBoolean("cut"); } if(message.hasValue("copy")) { mCanCopy = message.getValueBoolean("copy"); } if(message.hasValue("paste")) { mCanPaste = message.getValueBoolean("paste"); } } else if(message_name == "name_text") { mMediaName = message.getValue("name"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); } else if(message_name == "pick_file") { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); } else if(message_name == "auth_request") { mAuthURL = message.getValue("url"); mAuthRealm = message.getValue("realm"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); } else if(message_name == "debug_message") { mDebugMessageText = message.getValue("message_text"); mDebugMessageLevel = message.getValue("message_level"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE); } else { LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; } } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { std::string message_name = message.getName(); if(message_name == "navigate_begin") { mNavigateURI = message.getValue("uri"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); } else if(message_name == "navigate_complete") { mNavigateURI = message.getValue("uri"); mNavigateResultCode = message.getValueS32("result_code"); mNavigateResultString = message.getValue("result_string"); mHistoryBackAvailable = message.getValueBoolean("history_back_available"); mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); } else if(message_name == "progress") { mProgressPercent = message.getValueS32("percent"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); } else if(message_name == "status_text") { mStatusText = message.getValue("status"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); } else if(message_name == "location_changed") { mLocation = message.getValue("uri"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); } else if(message_name == "click_href") { mClickURL = message.getValue("uri"); mClickTarget = message.getValue("target"); mClickUUID = message.getValue("uuid"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); } else if(message_name == "click_nofollow") { mClickURL = message.getValue("uri"); mClickNavType = message.getValue("nav_type"); mClickTarget.clear(); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); } else if(message_name == "navigate_error_page") { mStatusCode = message.getValueS32("status_code"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); } else if(message_name == "cookie_set") { if(mOwner) { mOwner->handleCookieSet(this, message.getValue("cookie")); } } else if(message_name == "close_request") { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); } else if(message_name == "geometry_change") { mClickUUID = message.getValue("uuid"); mGeometryX = message.getValueS32("x"); mGeometryY = message.getValueS32("y"); mGeometryWidth = message.getValueS32("width"); mGeometryHeight = message.getValueS32("height"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); } else if(message_name == "link_hovered") { // text is not currently used -- the tooltip hover text is taken from the "title". mHoverLink = message.getValue("link"); mHoverText = message.getValue("title"); // message.getValue("text"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); } else { LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; } } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) { std::string message_name = message.getName(); // This class hasn't defined any incoming messages yet. // if(message_name == "message_name") // { // } // else { LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; } } }
/* virtual */ void LLPluginProcessChild::receivePluginMessage(const std::string &message) { LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; // Incoming message from the plugin instance bool passMessage = true; // FIXME: how should we handle queueing here? // Intercept certain base messages (responses to ones sent by this class) { // Decode this message LLPluginMessage parsed; parsed.parse(message); std::string message_class = parsed.getClass(); if(message_class == "base") { std::string message_name = parsed.getName(); if(message_name == "init_response") { // The plugin has finished initializing. setState(STATE_RUNNING); // Don't pass this message up to the parent passMessage = false; LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response"); LLSD versions = parsed.getValueLLSD("versions"); new_message.setValueLLSD("versions", versions); if(parsed.hasValue("plugin_version")) { std::string plugin_version = parsed.getValue("plugin_version"); new_message.setValueLLSD("plugin_version", plugin_version); } // Let the parent know it's loaded and initialized. sendMessageToParent(new_message); } else if(message_name == "shm_remove_response") { // Don't pass this message up to the parent passMessage = false; std::string name = parsed.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // detach the shared memory region iter->second->detach(); // and remove it from our map mSharedMemoryRegions.erase(iter); // Finally, send the response to the parent. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response"); message.setValue("name", name); sendMessageToParent(message); } else { LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL; } } } } if(passMessage) { LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; writeMessageRaw(message); } }