diff options
author | Maki <maki@hotmilk.space> | 2024-05-15 20:58:28 -0400 |
---|---|---|
committer | Maki <maki@hotmilk.space> | 2024-05-15 20:58:28 -0400 |
commit | ec23d45e2e9a87147641fed6f8c3ef6083c2f878 (patch) | |
tree | 169edbab006d8bbd86b2980ab98fb62e097067ff /indra/llplugin | |
parent | 8d824e8923b26c7a1d858e6cb587be1cf7d4dfeb (diff) | |
parent | 2f25f87ee719a79efc8316079f3c881eddb4d266 (diff) |
Merge branch 'release/maint-b' into pipewire-linux-volume-catcher
Diffstat (limited to 'indra/llplugin')
-rw-r--r-- | indra/llplugin/llpluginclassmedia.cpp | 2134 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmedia.h | 839 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmediaowner.h | 74 | ||||
-rw-r--r-- | indra/llplugin/llplugininstance.cpp | 182 | ||||
-rw-r--r-- | indra/llplugin/llplugininstance.h | 80 | ||||
-rw-r--r-- | indra/llplugin/llpluginmessage.cpp | 266 | ||||
-rw-r--r-- | indra/llplugin/llpluginmessage.h | 150 | ||||
-rw-r--r-- | indra/llplugin/llpluginmessageclasses.h | 12 | ||||
-rw-r--r-- | indra/llplugin/llpluginmessagepipe.cpp | 596 | ||||
-rw-r--r-- | indra/llplugin/llpluginmessagepipe.h | 96 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocesschild.cpp | 962 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocesschild.h | 142 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocessparent.cpp | 1728 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocessparent.h | 274 | ||||
-rw-r--r-- | indra/llplugin/llpluginsharedmemory.cpp | 522 | ||||
-rw-r--r-- | indra/llplugin/llpluginsharedmemory.h | 90 | ||||
-rw-r--r-- | indra/llplugin/slplugin/slplugin-objc.h | 10 | ||||
-rw-r--r-- | indra/llplugin/slplugin/slplugin.cpp | 298 |
18 files changed, 4228 insertions, 4227 deletions
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 3d87e2be7c..6e16c4d552 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -42,331 +42,331 @@ static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; static int nextPowerOf2( int value ) { - int next_power_of_2 = 1; - while ( next_power_of_2 < value ) - { - next_power_of_2 <<= 1; - } + int next_power_of_2 = 1; + while ( next_power_of_2 < value ) + { + next_power_of_2 <<= 1; + } - return next_power_of_2; + return next_power_of_2; } LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) { - mOwner = owner; - reset(); + mOwner = owner; + reset(); - //debug use - mDeleteOK = true ; + //debug use + mDeleteOK = true ; } LLPluginClassMedia::~LLPluginClassMedia() { - llassert_always(mDeleteOK) ; - reset(); + llassert_always(mDeleteOK) ; + reset(); } bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) { - LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; - LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; - LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; - mPlugin = LLPluginProcessParent::create(this); - mPlugin->setSleepTime(mSleepTime); + mPlugin = LLPluginProcessParent::create(this); + mPlugin->setSleepTime(mSleepTime); - // Queue up the media init message -- it will be sent after all the currently queued messages. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); - message.setValue("target", mTarget); - message.setValueReal("factor", mZoomFactor); - sendMessage(message); + // Queue up the media init message -- it will be sent after all the currently queued messages. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); + message.setValue("target", mTarget); + message.setValueReal("factor", mZoomFactor); + sendMessage(message); - mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); + mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); - return true; + return true; } void LLPluginClassMedia::reset() { - if(mPlugin) - { + if(mPlugin) + { mPlugin->requestShutdown(); mPlugin.reset(); - } - - mTextureParamsReceived = false; - mRequestedTextureDepth = 0; - mRequestedTextureInternalFormat = 0; - mRequestedTextureFormat = 0; - mRequestedTextureType = 0; - mRequestedTextureSwapBytes = false; - mRequestedTextureCoordsOpenGL = false; - mTextureSharedMemorySize = 0; - mTextureSharedMemoryName.clear(); - mDefaultMediaWidth = 0; - mDefaultMediaHeight = 0; - mNaturalMediaWidth = 0; - mNaturalMediaHeight = 0; - mSetMediaWidth = -1; - mSetMediaHeight = -1; - mRequestedMediaWidth = 0; - mRequestedMediaHeight = 0; - mRequestedTextureWidth = 0; - mRequestedTextureHeight = 0; - mFullMediaWidth = 0; - mFullMediaHeight = 0; - mTextureWidth = 0; - mTextureHeight = 0; - mMediaWidth = 0; - mMediaHeight = 0; - mDirtyRect = LLRect::null; - mAutoScaleMedia = false; - mRequestedVolume = 0.0f; - mPriority = PRIORITY_NORMAL; - mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; - mAllowDownsample = false; - mPadding = 0; - mLastMouseX = 0; - mLastMouseY = 0; - mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - mSleepTime = 1.0f / 100.0f; - mCanCut = false; - mCanCopy = false; - mCanPaste = false; - mMediaName.clear(); - mMediaDescription.clear(); - mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); - - // media_browser class - mNavigateURI.clear(); - mNavigateResultCode = -1; - mNavigateResultString.clear(); - mHistoryBackAvailable = false; - mHistoryForwardAvailable = false; - mStatusText.clear(); - mProgressPercent = 0; - mClickURL.clear(); - mClickNavType.clear(); - mClickTarget.clear(); - mClickUUID.clear(); - mStatusCode = 0; - - mClickEnforceTarget = false; - - // media_time class - mCurrentTime = 0.0f; - mDuration = 0.0f; - mCurrentRate = 0.0f; - mLoadedDuration = 0.0f; + } + + mTextureParamsReceived = false; + mRequestedTextureDepth = 0; + mRequestedTextureInternalFormat = 0; + mRequestedTextureFormat = 0; + mRequestedTextureType = 0; + mRequestedTextureSwapBytes = false; + mRequestedTextureCoordsOpenGL = false; + mTextureSharedMemorySize = 0; + mTextureSharedMemoryName.clear(); + mDefaultMediaWidth = 0; + mDefaultMediaHeight = 0; + mNaturalMediaWidth = 0; + mNaturalMediaHeight = 0; + mSetMediaWidth = -1; + mSetMediaHeight = -1; + mRequestedMediaWidth = 0; + mRequestedMediaHeight = 0; + mRequestedTextureWidth = 0; + mRequestedTextureHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mMediaWidth = 0; + mMediaHeight = 0; + mDirtyRect = LLRect::null; + mAutoScaleMedia = false; + mRequestedVolume = 0.0f; + mPriority = PRIORITY_NORMAL; + mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; + mAllowDownsample = false; + mPadding = 0; + mLastMouseX = 0; + mLastMouseY = 0; + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mMediaName.clear(); + mMediaDescription.clear(); + mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); + + // media_browser class + mNavigateURI.clear(); + mNavigateResultCode = -1; + mNavigateResultString.clear(); + mHistoryBackAvailable = false; + mHistoryForwardAvailable = false; + mStatusText.clear(); + mProgressPercent = 0; + mClickURL.clear(); + mClickNavType.clear(); + mClickTarget.clear(); + mClickUUID.clear(); + mStatusCode = 0; + + mClickEnforceTarget = false; + + // media_time class + mCurrentTime = 0.0f; + mDuration = 0.0f; + mCurrentRate = 0.0f; + mLoadedDuration = 0.0f; } void LLPluginClassMedia::idle(void) { - if(mPlugin) - { - mPlugin->idle(); - } - - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) - { - // Can't process a size change at this time - } - else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) - { - // Calculate the correct size for the media texture - mRequestedTextureHeight = mRequestedMediaHeight; - if(mPadding < 0) - { - // negative values indicate the plugin wants a power of 2 - mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); - } - else - { - mRequestedTextureWidth = mRequestedMediaWidth; - - if(mPadding > 1) - { - // Pad up to a multiple of the specified number of bytes per row - int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; - int pad = rowbytes % mPadding; - if(pad != 0) - { - rowbytes += mPadding - pad; - } - - if(rowbytes % mRequestedTextureDepth == 0) - { - mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; - } - else - { - LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; - } - } - } - - - // Size change has been requested but not initiated yet. - size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; - - // Add an extra line for padding, just in case. - newsize += mRequestedTextureWidth * mRequestedTextureDepth; - - if(newsize != mTextureSharedMemorySize) - { - if(!mTextureSharedMemoryName.empty()) - { - // Tell the plugin to remove the old memory segment - mPlugin->removeSharedMemory(mTextureSharedMemoryName); - mTextureSharedMemoryName.clear(); - } - - mTextureSharedMemorySize = newsize; - mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); - if(!mTextureSharedMemoryName.empty()) - { - void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - - // clear texture memory to avoid random screen visual fuzz from uninitialized texture data - if (addr) - { - memset( addr, 0x00, newsize ); - } - else - { - LL_WARNS("Plugin") << "Failed to get previously created shared memory address: " << mTextureSharedMemoryName << " size: " << mTextureSharedMemorySize << LL_ENDL; - } - - // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, - // so it may not be worthwhile. - // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); - } - } - - // This is our local indicator that a change is in progress. - mTextureWidth = -1; - mTextureHeight = -1; - mMediaWidth = -1; - mMediaHeight = -1; - - // This invalidates any existing dirty rect. - resetDirty(); - - // Send a size change message to the plugin - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); - message.setValue("name", mTextureSharedMemoryName); - message.setValueS32("width", mRequestedMediaWidth); - message.setValueS32("height", mRequestedMediaHeight); - message.setValueS32("texture_width", mRequestedTextureWidth); - message.setValueS32("texture_height", mRequestedTextureHeight); - message.setValueReal("background_r", mBackgroundColor.mV[VX]); - message.setValueReal("background_g", mBackgroundColor.mV[VY]); - message.setValueReal("background_b", mBackgroundColor.mV[VZ]); - message.setValueReal("background_a", mBackgroundColor.mV[VW]); - mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. - - LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; - } - } - - if(mPlugin && mPlugin->isRunning()) - { - // Send queued messages - while(!mSendQueue.empty()) - { - LLPluginMessage message = mSendQueue.front(); - mSendQueue.pop(); - mPlugin->sendMessage(message); - } - } + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) + { + // Can't process a size change at this time + } + else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) + { + // Calculate the correct size for the media texture + mRequestedTextureHeight = mRequestedMediaHeight; + if(mPadding < 0) + { + // negative values indicate the plugin wants a power of 2 + mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); + } + else + { + mRequestedTextureWidth = mRequestedMediaWidth; + + if(mPadding > 1) + { + // Pad up to a multiple of the specified number of bytes per row + int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; + int pad = rowbytes % mPadding; + if(pad != 0) + { + rowbytes += mPadding - pad; + } + + if(rowbytes % mRequestedTextureDepth == 0) + { + mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; + } + else + { + LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; + } + } + } + + + // Size change has been requested but not initiated yet. + size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; + + // Add an extra line for padding, just in case. + newsize += mRequestedTextureWidth * mRequestedTextureDepth; + + if(newsize != mTextureSharedMemorySize) + { + if(!mTextureSharedMemoryName.empty()) + { + // Tell the plugin to remove the old memory segment + mPlugin->removeSharedMemory(mTextureSharedMemoryName); + mTextureSharedMemoryName.clear(); + } + + mTextureSharedMemorySize = newsize; + mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); + if(!mTextureSharedMemoryName.empty()) + { + void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data + if (addr) + { + memset( addr, 0x00, newsize ); + } + else + { + LL_WARNS("Plugin") << "Failed to get previously created shared memory address: " << mTextureSharedMemoryName << " size: " << mTextureSharedMemorySize << LL_ENDL; + } + + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, + // so it may not be worthwhile. + // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); + } + } + + // This is our local indicator that a change is in progress. + mTextureWidth = -1; + mTextureHeight = -1; + mMediaWidth = -1; + mMediaHeight = -1; + + // This invalidates any existing dirty rect. + resetDirty(); + + // Send a size change message to the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); + message.setValue("name", mTextureSharedMemoryName); + message.setValueS32("width", mRequestedMediaWidth); + message.setValueS32("height", mRequestedMediaHeight); + message.setValueS32("texture_width", mRequestedTextureWidth); + message.setValueS32("texture_height", mRequestedTextureHeight); + message.setValueReal("background_r", mBackgroundColor.mV[VX]); + message.setValueReal("background_g", mBackgroundColor.mV[VY]); + message.setValueReal("background_b", mBackgroundColor.mV[VZ]); + message.setValueReal("background_a", mBackgroundColor.mV[VW]); + mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. + + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; + } + } + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } } int LLPluginClassMedia::getTextureWidth() const { - return nextPowerOf2(mTextureWidth); + return nextPowerOf2(mTextureWidth); } int LLPluginClassMedia::getTextureHeight() const { - return nextPowerOf2(mTextureHeight); + return nextPowerOf2(mTextureHeight); } unsigned char* LLPluginClassMedia::getBitsData() { - unsigned char *result = NULL; - if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) - { - result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - } - return result; + unsigned char *result = NULL; + if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + { + result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + } + return result; } void LLPluginClassMedia::setSize(int width, int height) { - if((width > 0) && (height > 0)) - { - mSetMediaWidth = width; - mSetMediaHeight = height; - } - else - { - mSetMediaWidth = -1; - mSetMediaHeight = -1; - } + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } - setSizeInternal(); + setSizeInternal(); } void LLPluginClassMedia::setSizeInternal(void) { - if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) - { - mRequestedMediaWidth = mSetMediaWidth; - mRequestedMediaHeight = mSetMediaHeight; - } - else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) - { - mRequestedMediaWidth = mNaturalMediaWidth; - mRequestedMediaHeight = mNaturalMediaHeight; - } - else - { - mRequestedMediaWidth = mDefaultMediaWidth; - mRequestedMediaHeight = mDefaultMediaHeight; - } - - // Save these for size/interest calculations - mFullMediaWidth = mRequestedMediaWidth; - mFullMediaHeight = mRequestedMediaHeight; - - if(mAllowDownsample) - { - switch(mPriority) - { - case PRIORITY_SLIDESHOW: - case PRIORITY_LOW: - // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit - while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) - { - mRequestedMediaWidth /= 2; - mRequestedMediaHeight /= 2; - } - break; - - default: - // Don't adjust texture size - break; - } - } - - if(mAutoScaleMedia) - { - mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); - mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); - } + if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) + { + mRequestedMediaWidth = mSetMediaWidth; + mRequestedMediaHeight = mSetMediaHeight; + } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } + else + { + mRequestedMediaWidth = mDefaultMediaWidth; + mRequestedMediaHeight = mDefaultMediaHeight; + } + + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + + if(mAllowDownsample) + { + switch(mPriority) + { + case PRIORITY_SLIDESHOW: + case PRIORITY_LOW: + // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit + while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) + { + mRequestedMediaWidth /= 2; + mRequestedMediaHeight /= 2; + } + break; + + default: + // Don't adjust texture size + break; + } + } + + if(mAutoScaleMedia) + { + mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); + mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); + } #if LL_DARWIN if (!gHiDPISupport) @@ -382,312 +382,312 @@ void LLPluginClassMedia::setSizeInternal(void) void LLPluginClassMedia::setAutoScale(bool auto_scale) { - if(auto_scale != mAutoScaleMedia) - { - mAutoScaleMedia = auto_scale; - setSizeInternal(); - } + if(auto_scale != mAutoScaleMedia) + { + mAutoScaleMedia = auto_scale; + setSizeInternal(); + } } bool LLPluginClassMedia::textureValid(void) { - if( - !mTextureParamsReceived || - mTextureWidth <= 0 || - mTextureHeight <= 0 || - mMediaWidth <= 0 || - mMediaHeight <= 0 || - mRequestedMediaWidth != mMediaWidth || - mRequestedMediaHeight != mMediaHeight || - getBitsData() == NULL - ) - return false; + if( + !mTextureParamsReceived || + mTextureWidth <= 0 || + mTextureHeight <= 0 || + mMediaWidth <= 0 || + mMediaHeight <= 0 || + mRequestedMediaWidth != mMediaWidth || + mRequestedMediaHeight != mMediaHeight || + getBitsData() == NULL + ) + return false; - return true; + return true; } bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) { - bool result = !mDirtyRect.isEmpty(); + bool result = !mDirtyRect.isEmpty(); - if(dirty_rect != NULL) - { - *dirty_rect = mDirtyRect; - } + if(dirty_rect != NULL) + { + *dirty_rect = mDirtyRect; + } - return result; + return result; } void LLPluginClassMedia::resetDirty(void) { - mDirtyRect = LLRect::null; + mDirtyRect = LLRect::null; } std::string LLPluginClassMedia::translateModifiers(MASK modifiers) { - std::string result; + std::string result; - if(modifiers & MASK_CONTROL) - { - result += "control|"; - } + if(modifiers & MASK_CONTROL) + { + result += "control|"; + } - if(modifiers & MASK_ALT) - { - result += "alt|"; - } + if(modifiers & MASK_ALT) + { + result += "alt|"; + } - if(modifiers & MASK_SHIFT) - { - result += "shift|"; - } + if(modifiers & MASK_SHIFT) + { + result += "shift|"; + } - // TODO: should I deal with platform differences here or in callers? - // TODO: how do we deal with the Mac "command" key? + // TODO: should I deal with platform differences here or in callers? + // TODO: how do we deal with the Mac "command" key? /* - if(modifiers & MASK_SOMETHING) - { - result += "meta|"; - } + if(modifiers & MASK_SOMETHING) + { + result += "meta|"; + } */ - return result; + return result; } void LLPluginClassMedia::jsEnableObject( bool enable ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object"); - message.setValueBoolean( "enable", enable ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object"); + message.setValueBoolean( "enable", enable ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); - message.setValueReal( "x", x ); - message.setValueReal( "y", y ); - message.setValueReal( "z", z ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); - message.setValueReal( "x", x ); - message.setValueReal( "y", y ); - message.setValueReal( "z", z ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentOrientationEvent( double angle ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); - message.setValueReal( "angle", angle ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); + message.setValueReal( "angle", angle ); - sendMessage( message ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); - message.setValue( "language", language ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); + message.setValue( "language", language ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); - message.setValue( "region", region ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); + message.setValue( "region", region ); + sendMessage( message ); } void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity ) { - if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) - { - return; - } + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); - message.setValue( "maturity", maturity ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); + message.setValue( "maturity", maturity ); + sendMessage( message ); } void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) { - if(type == MOUSE_EVENT_MOVE) - { - if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) - { - // Don't queue up mouse move events that can't be delivered. - return; - } - - if((x == mLastMouseX) && (y == mLastMouseY)) - { - // Don't spam unnecessary mouse move events. - return; - } - - mLastMouseX = x; - mLastMouseY = y; - } + if(type == MOUSE_EVENT_MOVE) + { + if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) + { + // Don't queue up mouse move events that can't be delivered. + return; + } + + if((x == mLastMouseX) && (y == mLastMouseY)) + { + // Don't spam unnecessary mouse move events. + return; + } + + mLastMouseX = x; + mLastMouseY = y; + } - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); - std::string temp; - switch(type) - { - case MOUSE_EVENT_DOWN: temp = "down"; break; - case MOUSE_EVENT_UP: temp = "up"; break; - case MOUSE_EVENT_MOVE: temp = "move"; break; - case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; - } - message.setValue("event", temp); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); + std::string temp; + switch(type) + { + case MOUSE_EVENT_DOWN: temp = "down"; break; + case MOUSE_EVENT_UP: temp = "up"; break; + case MOUSE_EVENT_MOVE: temp = "move"; break; + case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; + } + message.setValue("event", temp); - message.setValueS32("button", button); + message.setValueS32("button", button); - message.setValueS32("x", x); + message.setValueS32("x", x); - // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. - if(!mRequestedTextureCoordsOpenGL) - { - // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? - y = mMediaHeight - y; - } - message.setValueS32("y", y); + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. + if(!mRequestedTextureCoordsOpenGL) + { + // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? + y = mMediaHeight - y; + } + message.setValueS32("y", y); - message.setValue("modifiers", translateModifiers(modifiers)); + message.setValue("modifiers", translateModifiers(modifiers)); - sendMessage(message); + sendMessage(message); } bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) { - bool result = true; - - // FIXME: - // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. - // For now, return false for the ones the webkit plugin won't handle properly. - - switch(key_code) - { - case KEY_BACKSPACE: - case KEY_TAB: - case KEY_RETURN: - case KEY_PAD_RETURN: - case KEY_SHIFT: - case KEY_CONTROL: - case KEY_ALT: - case KEY_CAPSLOCK: - case KEY_ESCAPE: - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_END: - case KEY_HOME: - case KEY_LEFT: - case KEY_UP: - case KEY_RIGHT: - case KEY_DOWN: - case KEY_INSERT: - case KEY_DELETE: - // These will be handled - break; - - default: - // regular ASCII characters will also be handled - if(key_code >= KEY_SPECIAL) - { - // Other "special" codes will not work properly. - result = false; - } - break; - } - -#if LL_DARWIN - if(modifiers & MASK_ALT) - { - // Option-key modified characters should be handled by the unicode input path instead of this one. - result = false; - } -#endif + bool result = true; - if(result) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); - std::string temp; - switch(type) - { - case KEY_EVENT_DOWN: temp = "down"; break; - case KEY_EVENT_UP: temp = "up"; break; - case KEY_EVENT_REPEAT: temp = "repeat"; break; - } - message.setValue("event", temp); + // FIXME: + // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. + // For now, return false for the ones the webkit plugin won't handle properly. - message.setValueS32("key", key_code); + switch(key_code) + { + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: + case KEY_DELETE: + // These will be handled + break; + + default: + // regular ASCII characters will also be handled + if(key_code >= KEY_SPECIAL) + { + // Other "special" codes will not work properly. + result = false; + } + break; + } - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); +#if LL_DARWIN + if(modifiers & MASK_ALT) + { + // Option-key modified characters should be handled by the unicode input path instead of this one. + result = false; + } +#endif - sendMessage(message); - } + if(result) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); + std::string temp; + switch(type) + { + case KEY_EVENT_DOWN: temp = "down"; break; + case KEY_EVENT_UP: temp = "up"; break; + case KEY_EVENT_REPEAT: temp = "repeat"; break; + } + message.setValue("event", temp); + + message.setValueS32("key", key_code); + + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + } - return result; + return result; } void LLPluginClassMedia::scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); - message.setValueS32("x", x); - message.setValueS32("y", y); - message.setValueS32("clicks_x", clicks_x); - message.setValueS32("clicks_y", clicks_y); - message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValueS32("clicks_x", clicks_x); + message.setValueS32("clicks_y", clicks_y); + message.setValue("modifiers", translateModifiers(modifiers)); - sendMessage(message); + sendMessage(message); } bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); - message.setValue("text", text); - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); + message.setValue("text", text); + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); - sendMessage(message); + sendMessage(message); - return true; + return true; } // This function injects a previously stored OpenID cookie into @@ -695,7 +695,7 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD // that the way we use the cache, shared between multiple CEF // instances means that sometimes the OpenID cookie cannot be read // even though it appears to be there. The long term solution to -// this is to create a separate cache directory for each instance +// this is to create a separate cache directory for each instance // but that has its own set of problems. This short term approach // "forces" each new media instance to have a copy of the cookie // so that a page that needs it - e.g. Profiles - finds it and @@ -703,7 +703,7 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD void LLPluginClassMedia::injectOpenIDCookie() { // can be called before we know who the user is at login - // and there is no OpenID cookie at that point so no + // and there is no OpenID cookie at that point so no // need to try to set it (these values will all be empty) if (sOIDcookieName.length() && sOIDcookieValue.length()) { @@ -715,9 +715,9 @@ void LLPluginClassMedia::injectOpenIDCookie() // We store each component of the OpenI cookie individuality here // because previously, there was some significant parsing to // break up the raw string into these components and we do not -// want to have to do that again here. Stored as statics because -// we want to share their value between all instances of this -// class - the ones that receive it at login and any others +// want to have to do that again here. Stored as statics because +// we want to share their value between all instances of this +// class - the ones that receive it at login and any others // that open afterwards (e.g. the Profiles floater) std::string LLPluginClassMedia::sOIDcookieUrl = std::string(); std::string LLPluginClassMedia::sOIDcookieName = std::string(); @@ -752,233 +752,233 @@ void LLPluginClassMedia::storeOpenIDCookie(const std::string url, void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie"); - message.setValue("uri", uri); - message.setValue("name", name); - message.setValue("value", value); - message.setValue("domain", domain); - message.setValue("path", path); - message.setValueBoolean("httponly", httponly); - message.setValueBoolean("secure", secure); + message.setValue("uri", uri); + message.setValue("name", name); + message.setValue("value", value); + message.setValue("domain", domain); + message.setValue("path", path); + message.setValueBoolean("httponly", httponly); + message.setValueBoolean("secure", secure); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::loadURI(const std::string &uri) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); - message.setValue("uri", uri); + message.setValue("uri", uri); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::executeJavaScript(const std::string &code) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "execute_javascript"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "execute_javascript"); - message.setValue("code", code); + message.setValue("code", code); - sendMessage(message); + sendMessage(message); } const char* LLPluginClassMedia::priorityToString(EPriority priority) { - const char* result = "UNKNOWN"; - switch(priority) - { - case PRIORITY_UNLOADED: result = "unloaded"; break; - case PRIORITY_STOPPED: result = "stopped"; break; - case PRIORITY_HIDDEN: result = "hidden"; break; - case PRIORITY_SLIDESHOW: result = "slideshow"; break; - case PRIORITY_LOW: result = "low"; break; - case PRIORITY_NORMAL: result = "normal"; break; - case PRIORITY_HIGH: result = "high"; break; - } + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_UNLOADED: result = "unloaded"; break; + case PRIORITY_STOPPED: result = "stopped"; break; + case PRIORITY_HIDDEN: result = "hidden"; break; + case PRIORITY_SLIDESHOW: result = "slideshow"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } - return result; + return result; } void LLPluginClassMedia::setPriority(EPriority priority) { - if(mPriority != priority) - { - mPriority = priority; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); - - std::string priority_string = priorityToString(priority); - switch(priority) - { - case PRIORITY_UNLOADED: - mSleepTime = 1.0f; - break; - case PRIORITY_STOPPED: - mSleepTime = 1.0f; - break; - case PRIORITY_HIDDEN: - mSleepTime = 1.0f; - break; - case PRIORITY_SLIDESHOW: - mSleepTime = 1.0f; - break; - case PRIORITY_LOW: - mSleepTime = 1.0f / 25.0f; - break; - case PRIORITY_NORMAL: - mSleepTime = 1.0f / 50.0f; - break; - case PRIORITY_HIGH: - mSleepTime = 1.0f / 100.0f; - break; - } - - message.setValue("priority", priority_string); - - sendMessage(message); - - if(mPlugin) - { - mPlugin->setSleepTime(mSleepTime); - } - - LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } + if(mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_UNLOADED: + mSleepTime = 1.0f; + break; + case PRIORITY_STOPPED: + mSleepTime = 1.0f; + break; + case PRIORITY_HIDDEN: + mSleepTime = 1.0f; + break; + case PRIORITY_SLIDESHOW: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } } void LLPluginClassMedia::setLowPrioritySizeLimit(int size) { - int power = nextPowerOf2(size); - if(mLowPrioritySizeLimit != power) - { - mLowPrioritySizeLimit = power; + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) + { + mLowPrioritySizeLimit = power; - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } } F64 LLPluginClassMedia::getCPUUsage() { - F64 result = 0.0f; + F64 result = 0.0f; - if(mPlugin) - { - result = mPlugin->getCPUUsage(); - } + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } - return result; + return result; } void LLPluginClassMedia::sendPickFileResponse(const std::vector<std::string> files) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } - LLSD file_list = LLSD::emptyArray(); - for (std::vector<std::string>::const_iterator in_iter = files.begin(); in_iter != files.end(); ++in_iter) - { - file_list.append(LLSD::String(*in_iter)); - } - message.setValueLLSD("file_list", file_list); + LLSD file_list = LLSD::emptyArray(); + for (std::vector<std::string>::const_iterator in_iter = files.begin(); in_iter != files.end(); ++in_iter) + { + file_list.append(LLSD::String(*in_iter)); + } + message.setValueLLSD("file_list", file_list); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); - message.setValueBoolean("ok", ok); - message.setValue("username", username); - message.setValue("password", password); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); + message.setValueBoolean("ok", ok); + message.setValue("username", username); + message.setValue("password", password); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); } void LLPluginClassMedia::cut() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); + sendMessage(message); } void LLPluginClassMedia::copy() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); + sendMessage(message); } void LLPluginClassMedia::paste() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); + sendMessage(message); } void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, - const std::string &username, - const std::string &user_data_path_cef_log) + const std::string &username, + const std::string &user_data_path_cef_log) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); message.setValue("cache_path", user_data_path_cache); message.setValue("username", username); // cef shares cache between users but creates user-based contexts - message.setValue("cef_log_file", user_data_path_cef_log); + message.setValue("cef_log_file", user_data_path_cef_log); - bool cef_verbose_log = gSavedSettings.getBOOL("CefVerboseLog"); - message.setValueBoolean("cef_verbose_log", cef_verbose_log); - sendMessage(message); + bool cef_verbose_log = gSavedSettings.getBOOL("CefVerboseLog"); + message.setValueBoolean("cef_verbose_log", cef_verbose_log); + sendMessage(message); } void LLPluginClassMedia::setLanguageCode(const std::string &language_code) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); - message.setValue("language", language_code); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); + message.setValue("language", language_code); + sendMessage(message); } void LLPluginClassMedia::setPluginsEnabled(const bool enabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); } void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); } void LLPluginClassMedia::setWebSecurityDisabled(const bool disabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "web_security_disabled"); - message.setValueBoolean("disabled", disabled); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "web_security_disabled"); + message.setValueBoolean("disabled", disabled); + sendMessage(message); } void LLPluginClassMedia::setFileAccessFromFileUrlsEnabled(const bool enabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "file_access_from_file_urls"); - message.setValueBoolean("enabled", enabled); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "file_access_from_file_urls"); + message.setValueBoolean("enabled", enabled); + sendMessage(message); } void LLPluginClassMedia::enableMediaPluginDebugging( bool enable ) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging"); - message.setValueBoolean( "enable", enable ); - sendMessage( message ); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging"); + message.setValueBoolean( "enable", enable ); + sendMessage( message ); } #if LL_LINUX @@ -992,535 +992,535 @@ void LLPluginClassMedia::enablePipeWireVolumeCatcher( bool enable ) void LLPluginClassMedia::setTarget(const std::string &target) { - mTarget = target; + mTarget = target; } /* virtual */ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { - std::string message_class = message.getClass(); - - 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("Plugin") << "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") - { - mHistoryBackAvailable = message.getValueBoolean("history_back_available"); - mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); - mMediaName = message.getValue("name"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); - } - else if(message_name == "pick_file") - { - mIsMultipleFilePick = message.getValueBoolean("multiple_files"); - 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 == "file_download") - { - mFileDownloadFilename = message.getValue("filename"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_FILE_DOWNLOAD); - } - else if(message_name == "debug_message") - { - mDebugMessageText = message.getValue("message_text"); - mDebugMessageLevel = message.getValue("message_level"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE); - } - else if (message_name == "tooltip_text") - { - mHoverText = message.getValue("tooltip"); - } - 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"); - - // need a link to have a UUID that identifies it to a system further - // upstream - plugin could make it but we have access to LLUUID here - // so why don't we use it - mClickUUID = LLUUID::generateNewID().asString(); - - 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 == "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_name << " class message: " << message_name << LL_ENDL; - } - } + std::string message_class = message.getClass(); + + 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("Plugin") << "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") + { + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); + mMediaName = message.getValue("name"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); + } + else if(message_name == "pick_file") + { + mIsMultipleFilePick = message.getValueBoolean("multiple_files"); + 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 == "file_download") + { + mFileDownloadFilename = message.getValue("filename"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_FILE_DOWNLOAD); + } + else if(message_name == "debug_message") + { + mDebugMessageText = message.getValue("message_text"); + mDebugMessageLevel = message.getValue("message_level"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE); + } + else if (message_name == "tooltip_text") + { + mHoverText = message.getValue("tooltip"); + } + 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"); + + // need a link to have a UUID that identifies it to a system further + // upstream - plugin could make it but we have access to LLUUID here + // so why don't we use it + mClickUUID = LLUUID::generateNewID().asString(); + + 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 == "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_name << " class message: " << message_name << LL_ENDL; + } + } } /* virtual */ void LLPluginClassMedia::pluginLaunchFailed() { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); } /* virtual */ void LLPluginClassMedia::pluginDied() { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); } void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) { - if(mOwner) - { - mOwner->handleMediaEvent(this, event); - } + if(mOwner) + { + mOwner->handleMediaEvent(this, event); + } } void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) { - if(mPlugin && mPlugin->isRunning()) - { - mPlugin->sendMessage(message); - } - else - { - // The plugin isn't set up yet -- queue this message to be sent after initialization. - mSendQueue.push(message); - } + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } } //////////////////////////////////////////////////////////// // MARK: media_browser class functions bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) { - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); - return !version.empty(); + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); + return !version.empty(); } void LLPluginClassMedia::focus(bool focused) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); - message.setValueBoolean("focused", focused); + message.setValueBoolean("focused", focused); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::set_page_zoom_factor( F64 factor ) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor"); - message.setValueReal("factor", factor); - sendMessage(message); + message.setValueReal("factor", factor); + sendMessage(message); } void LLPluginClassMedia::clear_cache() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); + sendMessage(message); } void LLPluginClassMedia::clear_cookies() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); + sendMessage(message); } void LLPluginClassMedia::cookies_enabled(bool enable) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookies_enabled"); - message.setValueBoolean("enable", enable); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookies_enabled"); + message.setValueBoolean("enable", enable); + sendMessage(message); } void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); - message.setValueBoolean("enable", enable); - message.setValue("host", host); - message.setValueS32("port", port); + message.setValueBoolean("enable", enable); + message.setValue("host", host); + message.setValueS32("port", port); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::browse_stop() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); + sendMessage(message); } void LLPluginClassMedia::browse_reload(bool ignore_cache) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); - message.setValueBoolean("ignore_cache", ignore_cache); + message.setValueBoolean("ignore_cache", ignore_cache); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::browse_forward() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); + sendMessage(message); } void LLPluginClassMedia::browse_back() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); + sendMessage(message); } void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); - message.setValue("user_agent", user_agent); + message.setValue("user_agent", user_agent); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::showWebInspector( bool show ) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector"); - message.setValueBoolean("show", true); // only open for now - closed manually by user - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector"); + message.setValueBoolean("show", true); // only open for now - closed manually by user + sendMessage(message); } void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); - message.setValue("target", target); - message.setValue("uuid", uuid); + message.setValue("target", target); + message.setValue("uuid", uuid); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); - message.setValue("uuid", uuid); + message.setValue("uuid", uuid); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); - message.setValueBoolean("ignore", ignore); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); + message.setValueBoolean("ignore", ignore); + sendMessage(message); } void LLPluginClassMedia::addCertificateFilePath(const std::string& path) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); - message.setValue("path", path); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); + message.setValue("path", path); + sendMessage(message); } void LLPluginClassMedia::setOverrideClickTarget(const std::string &target) { - mClickEnforceTarget = true; - mOverrideClickTarget = target; + mClickEnforceTarget = true; + mOverrideClickTarget = target; } void LLPluginClassMedia::crashPlugin() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::hangPlugin() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); - sendMessage(message); + sendMessage(message); } @@ -1528,75 +1528,75 @@ void LLPluginClassMedia::hangPlugin() // MARK: media_time class functions bool LLPluginClassMedia::pluginSupportsMediaTime(void) { - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); - return !version.empty(); + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); + return !version.empty(); } void LLPluginClassMedia::stop() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); + sendMessage(message); } void LLPluginClassMedia::start(float rate) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); - message.setValueReal("rate", rate); + message.setValueReal("rate", rate); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::pause() { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); - sendMessage(message); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); + sendMessage(message); } void LLPluginClassMedia::seek(float time) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); - message.setValueReal("time", time); + message.setValueReal("time", time); mCurrentTime = time; // assume that it worked and we will receive an update later - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::setLoop(bool loop) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); - message.setValueBoolean("loop", loop); + message.setValueBoolean("loop", loop); - sendMessage(message); + sendMessage(message); } void LLPluginClassMedia::setVolume(float volume) { - if(volume != mRequestedVolume) - { - mRequestedVolume = volume; + if(volume != mRequestedVolume) + { + mRequestedVolume = volume; - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); - message.setValueReal("volume", volume); + message.setValueReal("volume", volume); - sendMessage(message); - } + sendMessage(message); + } } float LLPluginClassMedia::getVolume() { - return mRequestedVolume; + return mRequestedVolume; } void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) { - // Send URL history to plugin - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); - message.setValueLLSD("history", url_history); - sendMessage(message); + // Send URL history to plugin + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); + message.setValueLLSD("history", url_history); + sendMessage(message); - LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; + LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; } diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4b5ec2b76c..f4f374c894 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -1,4 +1,4 @@ -/** +/** * @file llpluginclassmedia.h * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -38,106 +38,107 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner { - LOG_CLASS(LLPluginClassMedia); + LOG_CLASS(LLPluginClassMedia); public: - LLPluginClassMedia(LLPluginClassMediaOwner *owner); - virtual ~LLPluginClassMedia(); - - // local initialization, called by the media manager when creating a source - bool init(const std::string &launcher_filename, - const std::string &plugin_dir, - const std::string &plugin_filename, - bool debug); - - // undoes everything init() didm called by the media manager when destroying a source - void reset(); - - void idle(void); - - // All of these may return 0 or an actual valid value. - // Callers need to check the return for 0, and not use the values in that case. - int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; - int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; - int getNaturalWidth() const { return mNaturalMediaWidth; }; - int getNaturalHeight() const { return mNaturalMediaHeight; }; - int getSetWidth() const { return mSetMediaWidth; }; - int getSetHeight() const { return mSetMediaHeight; }; - int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; - int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; - int getTextureWidth() const; - int getTextureHeight() const; - int getFullWidth() const { return mFullMediaWidth; }; - int getFullHeight() const { return mFullMediaHeight; }; - F64 getZoomFactor() const { return mZoomFactor; }; - - // This may return NULL. Callers need to check for and handle this case. - unsigned char* getBitsData(); - - // gets the format details of the texture data - // These may return 0 if they haven't been set up yet. The caller needs to detect this case. - int getTextureDepth() const { return mRequestedTextureDepth; }; - int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; - int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; - int getTextureFormatType() const { return mRequestedTextureType; }; - bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; - bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; - - void setSize(int width, int height); - void setAutoScale(bool auto_scale); - void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } - - void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; - - void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; - - // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. - // This will initially be false, and will also be false for some time after setSize while the resize is processed. - // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values - // until you call idle() again. - bool textureValid(void); - - bool getDirty(LLRect *dirty_rect = NULL); - void resetDirty(void); - - typedef enum - { - MOUSE_EVENT_DOWN, - MOUSE_EVENT_UP, - MOUSE_EVENT_MOVE, - MOUSE_EVENT_DOUBLE_CLICK - }EMouseEventType; - - void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); - - typedef enum - { - KEY_EVENT_DOWN, - KEY_EVENT_UP, - KEY_EVENT_REPEAT - }EKeyEventType; - - bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - - void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); - - // enable/disable media plugin debugging messages and info spam - void enableMediaPluginDebugging( bool enable ); + LLPluginClassMedia(LLPluginClassMediaOwner *owner); + virtual ~LLPluginClassMedia(); + + // local initialization, called by the media manager when creating a source + bool init(const std::string &launcher_filename, + const std::string &plugin_dir, + const std::string &plugin_filename, + bool debug); + + // undoes everything init() didm called by the media manager when destroying a source + void reset(); + + void idle(void); + + // All of these may return 0 or an actual valid value. + // Callers need to check the return for 0, and not use the values in that case. + int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; + int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; + int getNaturalWidth() const { return mNaturalMediaWidth; }; + int getNaturalHeight() const { return mNaturalMediaHeight; }; + int getSetWidth() const { return mSetMediaWidth; }; + int getSetHeight() const { return mSetMediaHeight; }; + int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; + int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; + int getTextureWidth() const; + int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; + F64 getZoomFactor() const { return mZoomFactor; }; + + // This may return NULL. Callers need to check for and handle this case. + unsigned char* getBitsData(); + + // gets the format details of the texture data + // These may return 0 if they haven't been set up yet. The caller needs to detect this case. + int getTextureDepth() const { return mRequestedTextureDepth; }; + int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; + int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; + int getTextureFormatType() const { return mRequestedTextureType; }; + bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; + bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; + + void setSize(int width, int height); + void setAutoScale(bool auto_scale); + void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } + + void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + + void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; + + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. + // This will initially be false, and will also be false for some time after setSize while the resize is processed. + // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values + // until you call idle() again. + bool textureValid(void); + + bool getDirty(LLRect *dirty_rect = NULL); + void resetDirty(void); + + typedef enum + { + MOUSE_EVENT_DOWN, + MOUSE_EVENT_UP, + MOUSE_EVENT_MOVE, + MOUSE_EVENT_DOUBLE_CLICK + }EMouseEventType; + + void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); + + typedef enum + { + KEY_EVENT_DOWN, + KEY_EVENT_UP, + KEY_EVENT_REPEAT + }EKeyEventType; + + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); + + void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); + + // enable/disable media plugin debugging messages and info spam + void enableMediaPluginDebugging( bool enable ); + + // Javascript <-> viewer events + void jsEnableObject( bool enable ); + void jsAgentLocationEvent( double x, double y, double z ); + void jsAgentGlobalLocationEvent( double x, double y, double z ); + void jsAgentOrientationEvent( double angle ); + void jsAgentLanguageEvent( const std::string& language ); + void jsAgentRegionEvent( const std::string& region_name ); + void jsAgentMaturityEvent( const std::string& maturity ); + + // Text may be unicode (utf8 encoded) + bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + #if LL_LINUX void enablePipeWireVolumeCatcher( bool enable ); #endif - // Javascript <-> viewer events - void jsEnableObject( bool enable ); - void jsAgentLocationEvent( double x, double y, double z ); - void jsAgentGlobalLocationEvent( double x, double y, double z ); - void jsAgentOrientationEvent( double angle ); - void jsAgentLanguageEvent( const std::string& language ); - void jsAgentRegionEvent( const std::string& region_name ); - void jsAgentMaturityEvent( const std::string& maturity ); - - // Text may be unicode (utf8 encoded) - bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); - static std::string sOIDcookieUrl; static std::string sOIDcookieName; static std::string sOIDcookieValue; @@ -152,331 +153,331 @@ public: void injectOpenIDCookie(); - void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure); - - void loadURI(const std::string &uri); - - void executeJavaScript(const std::string &code); - - // "Loading" means uninitialized or any state prior to fully running (processing commands) - bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; - - // "Running" means the steady state -- i.e. processing messages - bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; - - // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) - bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; - - std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; - - bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; - void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; - - // Inherited from LLPluginProcessParentOwner - /* virtual */ void receivePluginMessage(const LLPluginMessage &message); - /* virtual */ void pluginLaunchFailed(); - /* virtual */ void pluginDied(); - - - typedef enum - { - PRIORITY_UNLOADED, // media plugin isn't even loaded. - PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. - PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently - PRIORITY_LOW, // media is in the distance, may be rendered at reduced size - PRIORITY_NORMAL, // normal (default) priority - PRIORITY_HIGH // media has user focus and/or is taking up most of the screen - }EPriority; - - static const char* priorityToString(EPriority priority); - void setPriority(EPriority priority); - void setLowPrioritySizeLimit(int size); - - F64 getCPUUsage(); - - void sendPickFileResponse(const std::vector<std::string> files); - - void sendAuthResponse(bool ok, const std::string &username, const std::string &password); - - // Valid after a MEDIA_EVENT_CURSOR_CHANGED event - std::string getCursorName() const { return mCursorName; }; - - LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } - - void cut(); - bool canCut() const { return mCanCut; }; - - void copy(); - bool canCopy() const { return mCanCopy; }; - - void paste(); - bool canPaste() const { return mCanPaste; }; - - // These can be called before init(), and they will be queued and sent before the media init message. - void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log); - void setLanguageCode(const std::string &language_code); - void setPluginsEnabled(const bool enabled); - void setJavascriptEnabled(const bool enabled); - void setWebSecurityDisabled(const bool disabled); - void setFileAccessFromFileUrlsEnabled(const bool enabled); - void setTarget(const std::string &target); - - /////////////////////////////////// - // media browser class functions - bool pluginSupportsMediaBrowser(void); - - void focus(bool focused); - void set_page_zoom_factor( F64 factor ); - void clear_cache(); - void clear_cookies(); - void set_cookies(const std::string &cookies); - void cookies_enabled(bool enable); - void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); - void browse_stop(); - void browse_reload(bool ignore_cache = false); - void browse_forward(); - void browse_back(); - void setBrowserUserAgent(const std::string& user_agent); - void showWebInspector( bool show ); - void proxyWindowOpened(const std::string &target, const std::string &uuid); - void proxyWindowClosed(const std::string &uuid); - void ignore_ssl_cert_errors(bool ignore); - void addCertificateFilePath(const std::string& path); - - // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE - std::string getNavigateURI() const { return mNavigateURI; }; - - // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE - S32 getNavigateResultCode() const { return mNavigateResultCode; }; - std::string getNavigateResultString() const { return mNavigateResultString; }; - bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; - bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; - - // This is valid after MEDIA_EVENT_PROGRESS_UPDATED - int getProgressPercent() const { return mProgressPercent; }; - - // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED - std::string getStatusText() const { return mStatusText; }; - - // This is valid after MEDIA_EVENT_LOCATION_CHANGED - std::string getLocation() const { return mLocation; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickURL() const { return mClickURL; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickNavType() const { return mClickNavType; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF - std::string getClickTarget() const { return mClickTarget; }; - - // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE - std::string getClickUUID() const { return mClickUUID; }; - - // mClickTarget is received from message and governs how link will be opened - // use this to enforce your own way of opening links inside plugins - void setOverrideClickTarget(const std::string &target); - void resetOverrideClickTarget() { mClickEnforceTarget = false; }; - bool isOverrideClickTarget() const { return mClickEnforceTarget; } - std::string getOverrideClickTarget() const { return mOverrideClickTarget; }; - - // These are valid during MEDIA_EVENT_DEBUG_MESSAGE - std::string getDebugMessageText() const { return mDebugMessageText; }; - std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; - - // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE - S32 getStatusCode() const { return mStatusCode; }; - - // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE - S32 getGeometryX() const { return mGeometryX; }; - S32 getGeometryY() const { return mGeometryY; }; - S32 getGeometryWidth() const { return mGeometryWidth; }; - S32 getGeometryHeight() const { return mGeometryHeight; }; - - // These are valid during MEDIA_EVENT_AUTH_REQUEST - std::string getAuthURL() const { return mAuthURL; }; - std::string getAuthRealm() const { return mAuthRealm; }; - - // These are valid during MEDIA_EVENT_PICK_FILE_REQUEST - bool getIsMultipleFilePick() const { return mIsMultipleFilePick; } - - // These are valid during MEDIA_EVENT_LINK_HOVERED - std::string getHoverText() const { return mHoverText; }; - std::string getHoverLink() const { return mHoverLink; }; - - // these are valid during MEDIA_EVENT_LINK_HOVERED - std::string getFileDownloadFilename() const { return mFileDownloadFilename; } - - - const std::string& getMediaName() const { return mMediaName; }; - std::string getMediaDescription() const { return mMediaDescription; }; - - // Crash the plugin. If you use this outside of a testbed, you will be punished. - void crashPlugin(); - - // Hang the plugin. If you use this outside of a testbed, you will be punished. - void hangPlugin(); - - /////////////////////////////////// - // media time class functions - bool pluginSupportsMediaTime(void); - void stop(); - void start(float rate = 0.0f); - void pause(); - void seek(float time); - void setLoop(bool loop); - void setVolume(float volume); - float getVolume(); - - F64 getCurrentTime(void) const { return mCurrentTime; }; - F64 getDuration(void) const { return mDuration; }; - F64 getCurrentPlayRate(void) { return mCurrentRate; }; - F64 getLoadedDuration(void) const { return mLoadedDuration; }; - - // Initialize the URL history of the plugin by sending - // "init_history" message - void initializeUrlHistory(const LLSD& url_history); - - boost::shared_ptr<LLPluginClassMedia> getSharedPtr() { return boost::dynamic_pointer_cast<LLPluginClassMedia>(shared_from_this()); } // due to enable_shared_from_this + void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure); + + void loadURI(const std::string &uri); + + void executeJavaScript(const std::string &code); + + // "Loading" means uninitialized or any state prior to fully running (processing commands) + bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; + + // "Running" means the steady state -- i.e. processing messages + bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) + bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; + + std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; + + bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; + void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; + + // Inherited from LLPluginProcessParentOwner + /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginLaunchFailed(); + /* virtual */ void pluginDied(); + + + typedef enum + { + PRIORITY_UNLOADED, // media plugin isn't even loaded. + PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. + PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size + PRIORITY_NORMAL, // normal (default) priority + PRIORITY_HIGH // media has user focus and/or is taking up most of the screen + }EPriority; + + static const char* priorityToString(EPriority priority); + void setPriority(EPriority priority); + void setLowPrioritySizeLimit(int size); + + F64 getCPUUsage(); + + void sendPickFileResponse(const std::vector<std::string> files); + + void sendAuthResponse(bool ok, const std::string &username, const std::string &password); + + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event + std::string getCursorName() const { return mCursorName; }; + + LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + + void cut(); + bool canCut() const { return mCanCut; }; + + void copy(); + bool canCopy() const { return mCanCopy; }; + + void paste(); + bool canPaste() const { return mCanPaste; }; + + // These can be called before init(), and they will be queued and sent before the media init message. + void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log); + void setLanguageCode(const std::string &language_code); + void setPluginsEnabled(const bool enabled); + void setJavascriptEnabled(const bool enabled); + void setWebSecurityDisabled(const bool disabled); + void setFileAccessFromFileUrlsEnabled(const bool enabled); + void setTarget(const std::string &target); + + /////////////////////////////////// + // media browser class functions + bool pluginSupportsMediaBrowser(void); + + void focus(bool focused); + void set_page_zoom_factor( F64 factor ); + void clear_cache(); + void clear_cookies(); + void set_cookies(const std::string &cookies); + void cookies_enabled(bool enable); + void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void browse_stop(); + void browse_reload(bool ignore_cache = false); + void browse_forward(); + void browse_back(); + void setBrowserUserAgent(const std::string& user_agent); + void showWebInspector( bool show ); + void proxyWindowOpened(const std::string &target, const std::string &uuid); + void proxyWindowClosed(const std::string &uuid); + void ignore_ssl_cert_errors(bool ignore); + void addCertificateFilePath(const std::string& path); + + // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE + std::string getNavigateURI() const { return mNavigateURI; }; + + // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE + S32 getNavigateResultCode() const { return mNavigateResultCode; }; + std::string getNavigateResultString() const { return mNavigateResultString; }; + bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; + bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; + + // This is valid after MEDIA_EVENT_PROGRESS_UPDATED + int getProgressPercent() const { return mProgressPercent; }; + + // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED + std::string getStatusText() const { return mStatusText; }; + + // This is valid after MEDIA_EVENT_LOCATION_CHANGED + std::string getLocation() const { return mLocation; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickURL() const { return mClickURL; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickNavType() const { return mClickNavType; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF + std::string getClickTarget() const { return mClickTarget; }; + + // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE + std::string getClickUUID() const { return mClickUUID; }; + + // mClickTarget is received from message and governs how link will be opened + // use this to enforce your own way of opening links inside plugins + void setOverrideClickTarget(const std::string &target); + void resetOverrideClickTarget() { mClickEnforceTarget = false; }; + bool isOverrideClickTarget() const { return mClickEnforceTarget; } + std::string getOverrideClickTarget() const { return mOverrideClickTarget; }; + + // These are valid during MEDIA_EVENT_DEBUG_MESSAGE + std::string getDebugMessageText() const { return mDebugMessageText; }; + std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; + + // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE + S32 getStatusCode() const { return mStatusCode; }; + + // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE + S32 getGeometryX() const { return mGeometryX; }; + S32 getGeometryY() const { return mGeometryY; }; + S32 getGeometryWidth() const { return mGeometryWidth; }; + S32 getGeometryHeight() const { return mGeometryHeight; }; + + // These are valid during MEDIA_EVENT_AUTH_REQUEST + std::string getAuthURL() const { return mAuthURL; }; + std::string getAuthRealm() const { return mAuthRealm; }; + + // These are valid during MEDIA_EVENT_PICK_FILE_REQUEST + bool getIsMultipleFilePick() const { return mIsMultipleFilePick; } + + // These are valid during MEDIA_EVENT_LINK_HOVERED + std::string getHoverText() const { return mHoverText; }; + std::string getHoverLink() const { return mHoverLink; }; + + // these are valid during MEDIA_EVENT_LINK_HOVERED + std::string getFileDownloadFilename() const { return mFileDownloadFilename; } + + + const std::string& getMediaName() const { return mMediaName; }; + std::string getMediaDescription() const { return mMediaDescription; }; + + // Crash the plugin. If you use this outside of a testbed, you will be punished. + void crashPlugin(); + + // Hang the plugin. If you use this outside of a testbed, you will be punished. + void hangPlugin(); + + /////////////////////////////////// + // media time class functions + bool pluginSupportsMediaTime(void); + void stop(); + void start(float rate = 0.0f); + void pause(); + void seek(float time); + void setLoop(bool loop); + void setVolume(float volume); + float getVolume(); + + F64 getCurrentTime(void) const { return mCurrentTime; }; + F64 getDuration(void) const { return mDuration; }; + F64 getCurrentPlayRate(void) { return mCurrentRate; }; + F64 getLoadedDuration(void) const { return mLoadedDuration; }; + + // Initialize the URL history of the plugin by sending + // "init_history" message + void initializeUrlHistory(const LLSD& url_history); + + std::shared_ptr<LLPluginClassMedia> getSharedPtr() { return std::dynamic_pointer_cast<LLPluginClassMedia>(shared_from_this()); } // due to enable_shared_from_this protected: - LLPluginClassMediaOwner *mOwner; - - // Notify this object's owner that an event has occurred. - void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); - - void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. - std::queue<LLPluginMessage> mSendQueue; // Used to queue messages while the plugin initializes. - - void setSizeInternal(void); - - bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true - S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; - bool mRequestedTextureSwapBytes; - bool mRequestedTextureCoordsOpenGL; - - std::string mTextureSharedMemoryName; - size_t mTextureSharedMemorySize; - - // True to scale requested media up to the full size of the texture (i.e. next power of two) - bool mAutoScaleMedia; - - // default media size for the plugin, from the texture_params message. - int mDefaultMediaWidth; - int mDefaultMediaHeight; - - // Size that has been requested by the plugin itself - int mNaturalMediaWidth; - int mNaturalMediaHeight; - - // Size that has been requested with setSize() - int mSetMediaWidth; - int mSetMediaHeight; - - // Full calculated media size (before auto-scale and downsample calculations) - int mFullMediaWidth; - int mFullMediaHeight; - - // Actual media size being set (after auto-scale) - int mRequestedMediaWidth; - int mRequestedMediaHeight; - - // Texture size calculated from actual media size - int mRequestedTextureWidth; - int mRequestedTextureHeight; - - // Size that the plugin has acknowledged - int mTextureWidth; - int mTextureHeight; - int mMediaWidth; - int mMediaHeight; - - F64 mZoomFactor; - - float mRequestedVolume; - - // Priority of this media stream - EPriority mPriority; - int mLowPrioritySizeLimit; - - bool mAllowDownsample; - int mPadding; - - - LLPluginProcessParent::ptr_t mPlugin; - - LLRect mDirtyRect; - - std::string translateModifiers(MASK modifiers); - - std::string mCursorName; - int mLastMouseX; - int mLastMouseY; - - LLPluginClassMediaOwner::EMediaStatus mStatus; - - F64 mSleepTime; - - bool mCanCut; - bool mCanCopy; - bool mCanPaste; - - std::string mMediaName; - std::string mMediaDescription; - - LLColor4 mBackgroundColor; - - std::string mTarget; - - ///////////////////////////////////////// - // media_browser class - std::string mNavigateURI; - S32 mNavigateResultCode; - std::string mNavigateResultString; - bool mHistoryBackAvailable; - bool mHistoryForwardAvailable; - std::string mStatusText; - int mProgressPercent; - std::string mLocation; - std::string mClickURL; - std::string mClickNavType; - std::string mClickTarget; - std::string mClickUUID; - bool mClickEnforceTarget; - std::string mOverrideClickTarget; - std::string mDebugMessageText; - std::string mDebugMessageLevel; - S32 mGeometryX; - S32 mGeometryY; - S32 mGeometryWidth; - S32 mGeometryHeight; - S32 mStatusCode; - std::string mAuthURL; - std::string mAuthRealm; - std::string mHoverText; - std::string mHoverLink; - std::string mFileDownloadFilename; - bool mIsMultipleFilePick; - - ///////////////////////////////////////// - // media_time class - F64 mCurrentTime; - F64 mDuration; - F64 mCurrentRate; - F64 mLoadedDuration; - + LLPluginClassMediaOwner *mOwner; + + // Notify this object's owner that an event has occurred. + void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); + + void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. + std::queue<LLPluginMessage> mSendQueue; // Used to queue messages while the plugin initializes. + + void setSizeInternal(void); + + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true + S32 mRequestedTextureDepth; + LLGLenum mRequestedTextureInternalFormat; + LLGLenum mRequestedTextureFormat; + LLGLenum mRequestedTextureType; + bool mRequestedTextureSwapBytes; + bool mRequestedTextureCoordsOpenGL; + + std::string mTextureSharedMemoryName; + size_t mTextureSharedMemorySize; + + // True to scale requested media up to the full size of the texture (i.e. next power of two) + bool mAutoScaleMedia; + + // default media size for the plugin, from the texture_params message. + int mDefaultMediaWidth; + int mDefaultMediaHeight; + + // Size that has been requested by the plugin itself + int mNaturalMediaWidth; + int mNaturalMediaHeight; + + // Size that has been requested with setSize() + int mSetMediaWidth; + int mSetMediaHeight; + + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) + int mRequestedMediaWidth; + int mRequestedMediaHeight; + + // Texture size calculated from actual media size + int mRequestedTextureWidth; + int mRequestedTextureHeight; + + // Size that the plugin has acknowledged + int mTextureWidth; + int mTextureHeight; + int mMediaWidth; + int mMediaHeight; + + F64 mZoomFactor; + + float mRequestedVolume; + + // Priority of this media stream + EPriority mPriority; + int mLowPrioritySizeLimit; + + bool mAllowDownsample; + int mPadding; + + + LLPluginProcessParent::ptr_t mPlugin; + + LLRect mDirtyRect; + + std::string translateModifiers(MASK modifiers); + + std::string mCursorName; + int mLastMouseX; + int mLastMouseY; + + LLPluginClassMediaOwner::EMediaStatus mStatus; + + F64 mSleepTime; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + std::string mMediaName; + std::string mMediaDescription; + + LLColor4 mBackgroundColor; + + std::string mTarget; + + ///////////////////////////////////////// + // media_browser class + std::string mNavigateURI; + S32 mNavigateResultCode; + std::string mNavigateResultString; + bool mHistoryBackAvailable; + bool mHistoryForwardAvailable; + std::string mStatusText; + int mProgressPercent; + std::string mLocation; + std::string mClickURL; + std::string mClickNavType; + std::string mClickTarget; + std::string mClickUUID; + bool mClickEnforceTarget; + std::string mOverrideClickTarget; + std::string mDebugMessageText; + std::string mDebugMessageLevel; + S32 mGeometryX; + S32 mGeometryY; + S32 mGeometryWidth; + S32 mGeometryHeight; + S32 mStatusCode; + std::string mAuthURL; + std::string mAuthRealm; + std::string mHoverText; + std::string mHoverLink; + std::string mFileDownloadFilename; + bool mIsMultipleFilePick; + + ///////////////////////////////////////// + // media_time class + F64 mCurrentTime; + F64 mDuration; + F64 mCurrentRate; + F64 mLoadedDuration; + //-------------------------------------- - //debug use only - // + //debug use only + // private: - bool mDeleteOK ; + bool mDeleteOK ; public: - void setDeleteOK(bool flag) { mDeleteOK = flag ;} + void setDeleteOK(bool flag) { mDeleteOK = flag ;} //-------------------------------------- }; diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 89f55eaf71..a75d0b9960 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -38,53 +38,53 @@ class LLPluginClassMedia; class LLPluginClassMediaOwner { public: - typedef enum - { - MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated - MEDIA_EVENT_TIME_DURATION_UPDATED, // current time and/or duration have updated - MEDIA_EVENT_SIZE_CHANGED, // media size has changed - MEDIA_EVENT_CURSOR_CHANGED, // plugin has requested a cursor change + typedef enum + { + MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated + MEDIA_EVENT_TIME_DURATION_UPDATED, // current time and/or duration have updated + MEDIA_EVENT_SIZE_CHANGED, // media size has changed + MEDIA_EVENT_CURSOR_CHANGED, // plugin has requested a cursor change - MEDIA_EVENT_NAVIGATE_BEGIN, // browser has begun navigation - MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation - MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress - MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text - MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically <title> tag) - MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc) - MEDIA_EVENT_NAVIGATE_ERROR_PAGE, // browser navigated to a page that resulted in an HTTP error - MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are - MEDIA_EVENT_CLICK_LINK_NOFOLLOW, - MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit) - MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file - MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface) + MEDIA_EVENT_NAVIGATE_BEGIN, // browser has begun navigation + MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation + MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress + MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text + MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically <title> tag) + MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc) + MEDIA_EVENT_NAVIGATE_ERROR_PAGE, // browser navigated to a page that resulted in an HTTP error + MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are + MEDIA_EVENT_CLICK_LINK_NOFOLLOW, + MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit) + MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file + MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface) - MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch - MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly + MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch + MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly - MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog + MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog - MEDIA_EVENT_FILE_DOWNLOAD, // the plugin wants to download a file + MEDIA_EVENT_FILE_DOWNLOAD, // the plugin wants to download a file - MEDIA_EVENT_DEBUG_MESSAGE, // plugin sending back debug information for host to process + MEDIA_EVENT_DEBUG_MESSAGE, // plugin sending back debug information for host to process - MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin + MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin - } EMediaEvent; + } EMediaEvent; - typedef enum - { - MEDIA_NONE, // Uninitialized -- no useful state - MEDIA_LOADING, // loading or navigating - MEDIA_LOADED, // navigation/preroll complete - MEDIA_ERROR, // navigation/preroll failed - MEDIA_PLAYING, // playing (only for time-based media) - MEDIA_PAUSED, // paused (only for time-based media) - MEDIA_DONE // finished playing (only for time-based media) + typedef enum + { + MEDIA_NONE, // Uninitialized -- no useful state + MEDIA_LOADING, // loading or navigating + MEDIA_LOADED, // navigation/preroll complete + MEDIA_ERROR, // navigation/preroll failed + MEDIA_PLAYING, // playing (only for time-based media) + MEDIA_PAUSED, // paused (only for time-based media) + MEDIA_DONE // finished playing (only for time-based media) - } EMediaStatus; + } EMediaStatus; - virtual ~LLPluginClassMediaOwner() {}; - virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {}; + virtual ~LLPluginClassMediaOwner() {}; + virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {}; }; #endif // LL_LLPLUGINCLASSMEDIAOWNER_H diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index 7cde82a20e..67c12820e8 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llplugininstance.cpp * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -33,7 +33,7 @@ #include "llapr.h" #if LL_WINDOWS -#include "direct.h" // needed for _chdir() +#include "direct.h" // needed for _chdir() #endif /** Virtual destructor. */ @@ -41,37 +41,37 @@ LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener() { } -/** +/** * TODO:DOC describe how it's used */ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoint"; -/** +/** * Constructor. * * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is? */ LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : - mDSOHandle(NULL), - mPluginUserData(NULL), - mPluginSendMessageFunction(NULL) + mDSOHandle(NULL), + mPluginUserData(NULL), + mPluginSendMessageFunction(NULL) { - mOwner = owner; + mOwner = owner; } -/** +/** * Destructor. */ LLPluginInstance::~LLPluginInstance() { - if(mDSOHandle != NULL) - { - apr_dso_unload(mDSOHandle); - mDSOHandle = NULL; - } + if(mDSOHandle != NULL) + { + apr_dso_unload(mDSOHandle); + mDSOHandle = NULL; + } } -/** +/** * Dynamically loads the plugin and runs the plugin's init function. * * @param[in] plugin_file Name of plugin dll/dylib/so. TODO:DOC is this correct? see .h @@ -79,75 +79,75 @@ LLPluginInstance::~LLPluginInstance() */ int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_file) { - pluginInitFunction init_function = NULL; - - if ( plugin_dir.length() ) - { + pluginInitFunction init_function = NULL; + + if ( plugin_dir.length() ) + { #if LL_WINDOWS - // VWR-21275: - // *SOME* Windows systems fail to load the Qt plugins if the current working - // directory is not the same as the directory with the Qt DLLs in. - // This should not cause any run time issues since we are changing the cwd for the - // plugin shell process and not the viewer. - // Changing back to the previous directory is not necessary since the plugin shell - // quits once the plugin exits. - _chdir( plugin_dir.c_str() ); + // VWR-21275: + // *SOME* Windows systems fail to load the Qt plugins if the current working + // directory is not the same as the directory with the Qt DLLs in. + // This should not cause any run time issues since we are changing the cwd for the + // plugin shell process and not the viewer. + // Changing back to the previous directory is not necessary since the plugin shell + // quits once the plugin exits. + _chdir( plugin_dir.c_str() ); #endif - }; - - int result = apr_dso_load(&mDSOHandle, - plugin_file.c_str(), - gAPRPoolp); - if(result != APR_SUCCESS) - { - char buf[1024]; - apr_dso_error(mDSOHandle, buf, sizeof(buf)); - - LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL; - - } - - if(result == APR_SUCCESS) - { - result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function, - mDSOHandle, - PLUGIN_INIT_FUNCTION_NAME); - - if(result != APR_SUCCESS) - { - LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL; - } - } - - if(result == APR_SUCCESS) - { - result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); - - if(result != APR_SUCCESS) - { - LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; - } - } - - return (int)result; + }; + + int result = apr_dso_load(&mDSOHandle, + plugin_file.c_str(), + gAPRPoolp); + if(result != APR_SUCCESS) + { + char buf[1024]; + apr_dso_error(mDSOHandle, buf, sizeof(buf)); + + LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL; + + } + + if(result == APR_SUCCESS) + { + result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function, + mDSOHandle, + PLUGIN_INIT_FUNCTION_NAME); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL; + } + } + + if(result == APR_SUCCESS) + { + result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; + } + } + + return (int)result; } -/** +/** * Sends a message to the plugin. * * @param[in] message Message */ void LLPluginInstance::sendMessage(const std::string &message) { - if(mPluginSendMessageFunction) - { - LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; - mPluginSendMessageFunction(message.c_str(), &mPluginUserData); - } - else - { - LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL; - } + if(mPluginSendMessageFunction) + { + LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; + mPluginSendMessageFunction(message.c_str(), &mPluginUserData); + } + else + { + LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL; + } } /** @@ -161,10 +161,10 @@ void LLPluginInstance::idle(void) // static void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) { - // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer - // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill - LLPluginInstance *self = (LLPluginInstance*)*user_data; - self->receiveMessage(message_string); + // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer + // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill + LLPluginInstance *self = (LLPluginInstance*)*user_data; + self->receiveMessage(message_string); } /** @@ -174,13 +174,13 @@ void LLPluginInstance::staticReceiveMessage(const char *message_string, void **u */ void LLPluginInstance::receiveMessage(const char *message_string) { - if(mOwner) - { - LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL; - mOwner->receivePluginMessage(message_string); - } - else - { - LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL; - } + if(mOwner) + { + LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL; + mOwner->receivePluginMessage(message_string); + } + else + { + LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL; + } } diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h index e6926c3e37..4ab46b4290 100644 --- a/indra/llplugin/llplugininstance.h +++ b/indra/llplugin/llplugininstance.h @@ -1,25 +1,25 @@ -/** +/** * @file llplugininstance.h * * @cond * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -39,9 +39,9 @@ class LLPluginInstanceMessageListener { public: - virtual ~LLPluginInstanceMessageListener(); + virtual ~LLPluginInstanceMessageListener(); /** Plugin receives message from plugin loader shell. */ - virtual void receivePluginMessage(const std::string &message) = 0; + virtual void receivePluginMessage(const std::string &message) = 0; }; /** @@ -49,51 +49,51 @@ public: */ class LLPluginInstance { - LOG_CLASS(LLPluginInstance); + LOG_CLASS(LLPluginInstance); public: - LLPluginInstance(LLPluginInstanceMessageListener *owner); - virtual ~LLPluginInstance(); - - // Load a plugin dll/dylib/so - // Returns 0 if successful, APR error code or error code returned from the plugin's init function on failure. - int load(const std::string& plugin_dir, std::string &plugin_file); - - // Sends a message to the plugin. - void sendMessage(const std::string &message); - + LLPluginInstance(LLPluginInstanceMessageListener *owner); + virtual ~LLPluginInstance(); + + // Load a plugin dll/dylib/so + // Returns 0 if successful, APR error code or error code returned from the plugin's init function on failure. + int load(const std::string& plugin_dir, std::string &plugin_file); + + // Sends a message to the plugin. + void sendMessage(const std::string &message); + // TODO:DOC is this comment obsolete? can't find "send_count" anywhere in indra tree. - // send_count is the maximum number of message to process from the send queue. If negative, it will drain the queue completely. - // The receive queue is always drained completely. - // Returns the total number of messages processed from both queues. - void idle(void); - - /** The signature of the function for sending a message from plugin to plugin loader shell. + // send_count is the maximum number of message to process from the send queue. If negative, it will drain the queue completely. + // The receive queue is always drained completely. + // Returns the total number of messages processed from both queues. + void idle(void); + + /** The signature of the function for sending a message from plugin to plugin loader shell. * - * @param[in] message_string Null-terminated C string + * @param[in] message_string Null-terminated C string * @param[in] user_data The opaque reference that the callee supplied during setup. */ - typedef void (*sendMessageFunction) (const char *message_string, void **user_data); + typedef void (*sendMessageFunction) (const char *message_string, void **user_data); - /** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?) + /** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?) * * @param[in] host_user_data Data from plugin loader shell. * @param[in] plugin_send_function Function for sending from the plugin loader shell to plugin. */ - typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); - + typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); + /** Name of plugin init function */ - static const char *PLUGIN_INIT_FUNCTION_NAME; - + static const char *PLUGIN_INIT_FUNCTION_NAME; + private: - static void staticReceiveMessage(const char *message_string, void **user_data); - void receiveMessage(const char *message_string); - - apr_dso_handle_t *mDSOHandle; - - void *mPluginUserData; - sendMessageFunction mPluginSendMessageFunction; - - LLPluginInstanceMessageListener *mOwner; + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + + apr_dso_handle_t *mDSOHandle; + + void *mPluginUserData; + sendMessageFunction mPluginSendMessageFunction; + + LLPluginInstanceMessageListener *mOwner; }; #endif // LL_LLPLUGININSTANCE_H diff --git a/indra/llplugin/llpluginmessage.cpp b/indra/llplugin/llpluginmessage.cpp index b39e951155..188d71227b 100644 --- a/indra/llplugin/llpluginmessage.cpp +++ b/indra/llplugin/llpluginmessage.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginmessage.cpp * @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -46,7 +46,7 @@ LLPluginMessage::LLPluginMessage() */ LLPluginMessage::LLPluginMessage(const LLPluginMessage &p) { - mMessage = p.mMessage; + mMessage = p.mMessage; } /** @@ -57,7 +57,7 @@ LLPluginMessage::LLPluginMessage(const LLPluginMessage &p) */ LLPluginMessage::LLPluginMessage(const std::string &message_class, const std::string &message_name) { - setMessage(message_class, message_name); + setMessage(message_class, message_name); } @@ -73,8 +73,8 @@ LLPluginMessage::~LLPluginMessage() */ void LLPluginMessage::clear() { - mMessage = LLSD::emptyMap(); - mMessage["params"] = LLSD::emptyMap(); + mMessage = LLSD::emptyMap(); + mMessage["params"] = LLSD::emptyMap(); } /** @@ -85,9 +85,9 @@ void LLPluginMessage::clear() */ void LLPluginMessage::setMessage(const std::string &message_class, const std::string &message_name) { - clear(); - mMessage["class"] = message_class; - mMessage["name"] = message_name; + clear(); + mMessage["class"] = message_class; + mMessage["name"] = message_name; } /** @@ -98,7 +98,7 @@ void LLPluginMessage::setMessage(const std::string &message_class, const std::st */ void LLPluginMessage::setValue(const std::string &key, const std::string &value) { - mMessage["params"][key] = value; + mMessage["params"][key] = value; } /** @@ -109,7 +109,7 @@ void LLPluginMessage::setValue(const std::string &key, const std::string &value) */ void LLPluginMessage::setValueLLSD(const std::string &key, const LLSD &value) { - mMessage["params"][key] = value; + mMessage["params"][key] = value; } /** @@ -120,7 +120,7 @@ void LLPluginMessage::setValueLLSD(const std::string &key, const LLSD &value) */ void LLPluginMessage::setValueS32(const std::string &key, S32 value) { - mMessage["params"][key] = value; + mMessage["params"][key] = value; } /** @@ -131,9 +131,9 @@ void LLPluginMessage::setValueS32(const std::string &key, S32 value) */ void LLPluginMessage::setValueU32(const std::string &key, U32 value) { - std::stringstream temp; - temp << "0x" << std::hex << value; - setValue(key, temp.str()); + std::stringstream temp; + temp << "0x" << std::hex << value; + setValue(key, temp.str()); } /** @@ -144,7 +144,7 @@ void LLPluginMessage::setValueU32(const std::string &key, U32 value) */ void LLPluginMessage::setValueBoolean(const std::string &key, bool value) { - mMessage["params"][key] = value; + mMessage["params"][key] = value; } /** @@ -155,7 +155,7 @@ void LLPluginMessage::setValueBoolean(const std::string &key, bool value) */ void LLPluginMessage::setValueReal(const std::string &key, F64 value) { - mMessage["params"][key] = value; + mMessage["params"][key] = value; } /** @@ -166,10 +166,10 @@ void LLPluginMessage::setValueReal(const std::string &key, F64 value) */ void LLPluginMessage::setValuePointer(const std::string &key, void* value) { - std::stringstream temp; - // iostreams should output pointer values in hex with an initial 0x by default. - temp << value; - setValue(key, temp.str()); + std::stringstream temp; + // iostreams should output pointer values in hex with an initial 0x by default. + temp << value; + setValue(key, temp.str()); } /** @@ -179,7 +179,7 @@ void LLPluginMessage::setValuePointer(const std::string &key, void* value) */ std::string LLPluginMessage::getClass(void) const { - return mMessage["class"]; + return mMessage["class"]; } /** @@ -189,11 +189,11 @@ std::string LLPluginMessage::getClass(void) const */ std::string LLPluginMessage::getName(void) const { - return mMessage["name"]; + return mMessage["name"]; } /** - * Returns true if the specified key exists in this message (useful for optional parameters). + * Returns true if the specified key exists in this message (useful for optional parameters). * * @param[in] key Key * @@ -201,18 +201,18 @@ std::string LLPluginMessage::getName(void) const */ bool LLPluginMessage::hasValue(const std::string &key) const { - bool result = false; - - if(mMessage["params"].has(key)) - { - result = true; - } - - return result; + bool result = false; + + if(mMessage["params"].has(key)) + { + result = true; + } + + return result; } /** - * Gets the value of a key as a string. If the key does not exist, an empty string will be returned. + * Gets the value of a key as a string. If the key does not exist, an empty string will be returned. * * @param[in] key Key * @@ -220,18 +220,18 @@ bool LLPluginMessage::hasValue(const std::string &key) const */ std::string LLPluginMessage::getValue(const std::string &key) const { - std::string result; - - if(mMessage["params"].has(key)) - { - result = mMessage["params"][key].asString(); - } - - return result; + std::string result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asString(); + } + + return result; } /** - * Gets the value of a key as LLSD. If the key does not exist, a null LLSD will be returned. + * Gets the value of a key as LLSD. If the key does not exist, a null LLSD will be returned. * * @param[in] key Key * @@ -239,18 +239,18 @@ std::string LLPluginMessage::getValue(const std::string &key) const */ LLSD LLPluginMessage::getValueLLSD(const std::string &key) const { - LLSD result; - - if(mMessage["params"].has(key)) - { - result = mMessage["params"][key]; - } - - return result; + LLSD result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key]; + } + + return result; } /** - * Gets the value of a key as signed 32-bit int. If the key does not exist, 0 will be returned. + * Gets the value of a key as signed 32-bit int. If the key does not exist, 0 will be returned. * * @param[in] key Key * @@ -258,18 +258,18 @@ LLSD LLPluginMessage::getValueLLSD(const std::string &key) const */ S32 LLPluginMessage::getValueS32(const std::string &key) const { - S32 result = 0; - - if(mMessage["params"].has(key)) - { - result = mMessage["params"][key].asInteger(); - } - - return result; + S32 result = 0; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asInteger(); + } + + return result; } /** - * Gets the value of a key as unsigned 32-bit int. If the key does not exist, 0 will be returned. + * Gets the value of a key as unsigned 32-bit int. If the key does not exist, 0 will be returned. * * @param[in] key Key * @@ -277,20 +277,20 @@ S32 LLPluginMessage::getValueS32(const std::string &key) const */ U32 LLPluginMessage::getValueU32(const std::string &key) const { - U32 result = 0; - - if(mMessage["params"].has(key)) - { - std::string value = mMessage["params"][key].asString(); - - result = (U32)strtoul(value.c_str(), NULL, 16); - } - - return result; + U32 result = 0; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (U32)strtoul(value.c_str(), NULL, 16); + } + + return result; } /** - * Gets the value of a key as a bool. If the key does not exist, false will be returned. + * Gets the value of a key as a bool. If the key does not exist, false will be returned. * * @param[in] key Key * @@ -298,18 +298,18 @@ U32 LLPluginMessage::getValueU32(const std::string &key) const */ bool LLPluginMessage::getValueBoolean(const std::string &key) const { - bool result = false; - - if(mMessage["params"].has(key)) - { - result = mMessage["params"][key].asBoolean(); - } - - return result; + bool result = false; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asBoolean(); + } + + return result; } /** - * Gets the value of a key as a double. If the key does not exist, 0 will be returned. + * Gets the value of a key as a double. If the key does not exist, 0 will be returned. * * @param[in] key Key * @@ -317,18 +317,18 @@ bool LLPluginMessage::getValueBoolean(const std::string &key) const */ F64 LLPluginMessage::getValueReal(const std::string &key) const { - F64 result = 0.0f; - - if(mMessage["params"].has(key)) - { - result = mMessage["params"][key].asReal(); - } - - return result; + F64 result = 0.0f; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asReal(); + } + + return result; } /** - * Gets the value of a key as a pointer. If the key does not exist, NULL will be returned. + * Gets the value of a key as a pointer. If the key does not exist, NULL will be returned. * * @param[in] key Key * @@ -336,49 +336,49 @@ F64 LLPluginMessage::getValueReal(const std::string &key) const */ void* LLPluginMessage::getValuePointer(const std::string &key) const { - void* result = NULL; - - if(mMessage["params"].has(key)) - { - std::string value = mMessage["params"][key].asString(); - - result = (void*)llstrtou64(value.c_str(), NULL, 16); - } - - return result; + void* result = NULL; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (void*)llstrtou64(value.c_str(), NULL, 16); + } + + return result; } /** - * Flatten the message into a string. + * Flatten the message into a string. * * @return Message as a string. */ std::string LLPluginMessage::generate(void) const { - std::ostringstream result; - - // Pretty XML may be slightly easier to deal with while debugging... -// LLSDSerialize::toXML(mMessage, result); - LLSDSerialize::toPrettyXML(mMessage, result); - - return result.str(); + std::ostringstream result; + + // Pretty XML may be slightly easier to deal with while debugging... +// LLSDSerialize::toXML(mMessage, result); + LLSDSerialize::toPrettyXML(mMessage, result); + + return result.str(); } /** - * Parse an incoming message into component parts. Clears all existing state before starting the parse. + * Parse an incoming message into component parts. Clears all existing state before starting the parse. * * @return Returns -1 on failure, otherwise returns the number of key/value pairs in the incoming message. */ int LLPluginMessage::parse(const std::string &message) { - // clear any previous state - clear(); - - std::istringstream input(message); - - S32 parse_result = LLSDSerialize::fromXML(mMessage, input); - - return (int)parse_result; + // clear any previous state + clear(); + + std::istringstream input(message); + + S32 parse_result = LLSDSerialize::fromXML(mMessage, input); + + return (int)parse_result; } @@ -387,7 +387,7 @@ int LLPluginMessage::parse(const std::string &message) */ LLPluginMessageListener::~LLPluginMessageListener() { - // TODO: should listeners have a way to ensure they're removed from dispatcher lists when deleted? + // TODO: should listeners have a way to ensure they're removed from dispatcher lists when deleted? } @@ -396,9 +396,9 @@ LLPluginMessageListener::~LLPluginMessageListener() */ LLPluginMessageDispatcher::~LLPluginMessageDispatcher() { - + } - + /** * Add a message listener. TODO:DOC need more info on what uses this. when are multiple listeners needed? * @@ -406,7 +406,7 @@ LLPluginMessageDispatcher::~LLPluginMessageDispatcher() */ void LLPluginMessageDispatcher::addPluginMessageListener(LLPluginMessageListener *listener) { - mListeners.insert(listener); + mListeners.insert(listener); } /** @@ -416,7 +416,7 @@ void LLPluginMessageDispatcher::addPluginMessageListener(LLPluginMessageListener */ void LLPluginMessageDispatcher::removePluginMessageListener(LLPluginMessageListener *listener) { - mListeners.erase(listener); + mListeners.erase(listener); } /** @@ -426,13 +426,13 @@ void LLPluginMessageDispatcher::removePluginMessageListener(LLPluginMessageListe */ void LLPluginMessageDispatcher::dispatchPluginMessage(const LLPluginMessage &message) { - for (listener_set_t::iterator it = mListeners.begin(); - it != mListeners.end(); - ) - { - LLPluginMessageListener* listener = *it; - listener->receivePluginMessage(message); - // In case something deleted an entry. - it = mListeners.upper_bound(listener); - } + for (listener_set_t::iterator it = mListeners.begin(); + it != mListeners.end(); + ) + { + LLPluginMessageListener* listener = *it; + listener->receivePluginMessage(message); + // In case something deleted an entry. + it = mListeners.upper_bound(listener); + } } diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index f86b68d16e..93756cd0dc 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -1,25 +1,25 @@ -/** +/** * @file llpluginmessage.h * * @cond * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -35,68 +35,68 @@ */ class LLPluginMessage { - LOG_CLASS(LLPluginMessage); + LOG_CLASS(LLPluginMessage); public: - LLPluginMessage(); - LLPluginMessage(const LLPluginMessage &p); - LLPluginMessage(const std::string &message_class, const std::string &message_name); - ~LLPluginMessage(); - - // reset all internal state - void clear(void); - - // Sets the message class and name - // Also has the side-effect of clearing any key/value pairs in the message. - void setMessage(const std::string &message_class, const std::string &message_name); - - // Sets a key/value pair in the message - void setValue(const std::string &key, const std::string &value); - void setValueLLSD(const std::string &key, const LLSD &value); - void setValueS32(const std::string &key, S32 value); - void setValueU32(const std::string &key, U32 value); - void setValueBoolean(const std::string &key, bool value); - void setValueReal(const std::string &key, F64 value); - void setValuePointer(const std::string &key, void *value); - - std::string getClass(void) const; - std::string getName(void) const; - - // Returns true if the specified key exists in this message (useful for optional parameters) - bool hasValue(const std::string &key) const; - - // get the value of a particular key as a string. If the key doesn't exist in the message, an empty string will be returned. - std::string getValue(const std::string &key) const; - - // get the value of a particular key as LLSD. If the key doesn't exist in the message, a null LLSD will be returned. - LLSD getValueLLSD(const std::string &key) const; - - // get the value of a key as a S32. If the value wasn't set as a S32, behavior is undefined. - S32 getValueS32(const std::string &key) const; - - // get the value of a key as a U32. Since there isn't an LLSD type for this, we use a hexadecimal string instead. - U32 getValueU32(const std::string &key) const; - - // get the value of a key as a Boolean. - bool getValueBoolean(const std::string &key) const; - - // get the value of a key as a float. - F64 getValueReal(const std::string &key) const; - - // get the value of a key as a pointer. - void* getValuePointer(const std::string &key) const; - - // Flatten the message into a string - std::string generate(void) const; - - // Parse an incoming message into component parts - // (this clears out all existing state before starting the parse) - // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. - int parse(const std::string &message); - - + LLPluginMessage(); + LLPluginMessage(const LLPluginMessage &p); + LLPluginMessage(const std::string &message_class, const std::string &message_name); + ~LLPluginMessage(); + + // reset all internal state + void clear(void); + + // Sets the message class and name + // Also has the side-effect of clearing any key/value pairs in the message. + void setMessage(const std::string &message_class, const std::string &message_name); + + // Sets a key/value pair in the message + void setValue(const std::string &key, const std::string &value); + void setValueLLSD(const std::string &key, const LLSD &value); + void setValueS32(const std::string &key, S32 value); + void setValueU32(const std::string &key, U32 value); + void setValueBoolean(const std::string &key, bool value); + void setValueReal(const std::string &key, F64 value); + void setValuePointer(const std::string &key, void *value); + + std::string getClass(void) const; + std::string getName(void) const; + + // Returns true if the specified key exists in this message (useful for optional parameters) + bool hasValue(const std::string &key) const; + + // get the value of a particular key as a string. If the key doesn't exist in the message, an empty string will be returned. + std::string getValue(const std::string &key) const; + + // get the value of a particular key as LLSD. If the key doesn't exist in the message, a null LLSD will be returned. + LLSD getValueLLSD(const std::string &key) const; + + // get the value of a key as a S32. If the value wasn't set as a S32, behavior is undefined. + S32 getValueS32(const std::string &key) const; + + // get the value of a key as a U32. Since there isn't an LLSD type for this, we use a hexadecimal string instead. + U32 getValueU32(const std::string &key) const; + + // get the value of a key as a Boolean. + bool getValueBoolean(const std::string &key) const; + + // get the value of a key as a float. + F64 getValueReal(const std::string &key) const; + + // get the value of a key as a pointer. + void* getValuePointer(const std::string &key) const; + + // Flatten the message into a string + std::string generate(void) const; + + // Parse an incoming message into component parts + // (this clears out all existing state before starting the parse) + // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. + int parse(const std::string &message); + + private: - - LLSD mMessage; + + LLSD mMessage; }; @@ -106,10 +106,10 @@ private: class LLPluginMessageListener { public: - virtual ~LLPluginMessageListener(); + virtual ~LLPluginMessageListener(); /** Plugin receives message from plugin loader shell. */ - virtual void receivePluginMessage(const LLPluginMessage &message) = 0; - + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + }; /** @@ -120,17 +120,17 @@ public: class LLPluginMessageDispatcher { public: - virtual ~LLPluginMessageDispatcher(); - - void addPluginMessageListener(LLPluginMessageListener *); - void removePluginMessageListener(LLPluginMessageListener *); + virtual ~LLPluginMessageDispatcher(); + + void addPluginMessageListener(LLPluginMessageListener *); + void removePluginMessageListener(LLPluginMessageListener *); protected: - void dispatchPluginMessage(const LLPluginMessage &message); + void dispatchPluginMessage(const LLPluginMessage &message); /** A set of message listeners. */ - typedef std::set<LLPluginMessageListener*> listener_set_t; + typedef std::set<LLPluginMessageListener*> listener_set_t; /** The set of message listeners. */ - listener_set_t mListeners; + listener_set_t mListeners; }; diff --git a/indra/llplugin/llpluginmessageclasses.h b/indra/llplugin/llpluginmessageclasses.h index 65fc8cb5ff..465e2d7530 100644 --- a/indra/llplugin/llpluginmessageclasses.h +++ b/indra/llplugin/llpluginmessageclasses.h @@ -1,4 +1,4 @@ -/** +/** * @file llpluginmessageclasses.h * @brief This file defines the versions of existing message classes for LLPluginMessage. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -29,7 +29,7 @@ #ifndef LL_LLPLUGINMESSAGECLASSES_H #define LL_LLPLUGINMESSAGECLASSES_H -// Version strings for each plugin message class. +// Version strings for each plugin message class. // Backwards-compatible changes (i.e. changes which only add new messges) should increment the minor version (i.e. "1.0" -> "1.1"). // Non-backwards-compatible changes (which delete messages or change their semantics) should increment the major version (i.e. "1.1" -> "2.0"). // Plugins will supply the set of message classes they understand, with version numbers, as part of their init_response message. diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 9766e1bfed..2cbc16ceec 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginmessagepipe.cpp * @brief Classes that implement connections from the plugin system to pipes/pumps. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -36,362 +36,362 @@ static const char MESSAGE_DELIMITER = '\0'; LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() : - mMessagePipe(NULL), - mSocketError(APR_SUCCESS) + mMessagePipe(NULL), + mSocketError(APR_SUCCESS) { } -// virtual +// virtual LLPluginMessagePipeOwner::~LLPluginMessagePipeOwner() { - killMessagePipe(); + killMessagePipe(); } -// virtual +// virtual apr_status_t LLPluginMessagePipeOwner::socketError(apr_status_t error) -{ - mSocketError = error; - return error; +{ + mSocketError = error; + return error; }; -//virtual +//virtual void LLPluginMessagePipeOwner::setMessagePipe(LLPluginMessagePipe *read_pipe) { - // Save a reference to this pipe - mMessagePipe = read_pipe; + // Save a reference to this pipe + mMessagePipe = read_pipe; } bool LLPluginMessagePipeOwner::canSendMessage(void) { - return (mMessagePipe != NULL); + return (mMessagePipe != NULL); } bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) { - bool result = true; - if(mMessagePipe != NULL) - { - result = mMessagePipe->addMessage(message); - } - else - { - LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; - result = false; - } - - return result; + bool result = true; + if(mMessagePipe != NULL) + { + result = mMessagePipe->addMessage(message); + } + else + { + LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; + result = false; + } + + return result; } void LLPluginMessagePipeOwner::killMessagePipe(void) { - if(mMessagePipe != NULL) - { - delete mMessagePipe; - mMessagePipe = NULL; - } + if(mMessagePipe != NULL) + { + delete mMessagePipe; + mMessagePipe = NULL; + } } LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): - mInputMutex(), - mOutputMutex(), - mOutputStartIndex(0), - mOwner(owner), - mSocket(socket) + mInputMutex(), + mOutputMutex(), + mOutputStartIndex(0), + mOwner(owner), + mSocket(socket) { - mOwner->setMessagePipe(this); + mOwner->setMessagePipe(this); } LLPluginMessagePipe::~LLPluginMessagePipe() { - if(mOwner != NULL) - { - mOwner->setMessagePipe(NULL); - } + if(mOwner != NULL) + { + mOwner->setMessagePipe(NULL); + } } bool LLPluginMessagePipe::addMessage(const std::string &message) { - // queue the message for later output - LLMutexLock lock(&mOutputMutex); - - // If we're starting to use up too much memory, clear - if (mOutputStartIndex > 1024 * 1024) - { - mOutput = mOutput.substr(mOutputStartIndex); - mOutputStartIndex = 0; - } - - mOutput += message; - mOutput += MESSAGE_DELIMITER; // message separator - - return true; + // queue the message for later output + LLMutexLock lock(&mOutputMutex); + + // If we're starting to use up too much memory, clear + if (mOutputStartIndex > 1024 * 1024) + { + mOutput = mOutput.substr(mOutputStartIndex); + mOutputStartIndex = 0; + } + + mOutput += message; + mOutput += MESSAGE_DELIMITER; // message separator + + return true; } void LLPluginMessagePipe::clearOwner(void) { - // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. - mOwner = NULL; + // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. + mOwner = NULL; } void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec) { - // We never want to sleep forever, so force negative timeouts to become non-blocking. - - // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html - // blocking/non-blocking with apr sockets is somewhat non-portable. - - if(timeout_usec <= 0) - { - // Make the socket non-blocking - apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); - apr_socket_timeout_set(mSocket->getSocket(), 0); - } - else - { - // Make the socket blocking-with-timeout - apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); - apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); - } + // We never want to sleep forever, so force negative timeouts to become non-blocking. + + // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html + // blocking/non-blocking with apr sockets is somewhat non-portable. + + if(timeout_usec <= 0) + { + // Make the socket non-blocking + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), 0); + } + else + { + // Make the socket blocking-with-timeout + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); + } } bool LLPluginMessagePipe::pump(F64 timeout) { - bool result = pumpOutput(); - - if(result) - { - result = pumpInput(timeout); - } - - return result; + bool result = pumpOutput(); + + if(result) + { + result = pumpInput(timeout); + } + + return result; } bool LLPluginMessagePipe::pumpOutput() { - bool result = true; - - if(mSocket) - { - apr_status_t status; - apr_size_t in_size, out_size; - - LLMutexLock lock(&mOutputMutex); - - const char * output_data = &(mOutput.data()[mOutputStartIndex]); - if(*output_data != '\0') - { - // write any outgoing messages - in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex); - out_size = in_size; - - setSocketTimeout(0); - -// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; - - status = apr_socket_send(mSocket->getSocket(), - output_data, - &out_size); - -// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; - - if((status == APR_SUCCESS) || APR_STATUS_IS_EAGAIN(status)) - { - // Success or Socket buffer is full... - - // If we've pumped the entire string, clear it - if (out_size == in_size) - { - mOutputStartIndex = 0; - mOutput.clear(); - } - else - { - llassert(in_size > out_size); - - // Remove the written part from the buffer and try again later. - mOutputStartIndex += out_size; - } - } - else if(APR_STATUS_IS_EOF(status)) - { - // This is what we normally expect when a plugin exits. - //LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - } - else - { - // some other error - // Treat this as fatal. - ll_apr_warn_status(status); - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - } - } - } - - return result; + bool result = true; + + if(mSocket) + { + apr_status_t status; + apr_size_t in_size, out_size; + + LLMutexLock lock(&mOutputMutex); + + const char * output_data = &(mOutput.data()[mOutputStartIndex]); + if(*output_data != '\0') + { + // write any outgoing messages + in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex); + out_size = in_size; + + setSocketTimeout(0); + +// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; + + status = apr_socket_send(mSocket->getSocket(), + output_data, + &out_size); + +// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; + + if((status == APR_SUCCESS) || APR_STATUS_IS_EAGAIN(status)) + { + // Success or Socket buffer is full... + + // If we've pumped the entire string, clear it + if (out_size == in_size) + { + mOutputStartIndex = 0; + mOutput.clear(); + } + else + { + llassert(in_size > out_size); + + // Remove the written part from the buffer and try again later. + mOutputStartIndex += out_size; + } + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + //LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + } + } + + return result; } bool LLPluginMessagePipe::pumpInput(F64 timeout) { - bool result = true; + bool result = true; - if(mSocket) - { - apr_status_t status; - apr_size_t size; + if(mSocket) + { + apr_status_t status; + apr_size_t size; - // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. - // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. + // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. + // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. #if LL_WINDOWS - if(result) - { - if(timeout != 0.0f) - { - ms_sleep((int)(timeout * 1000.0f)); - timeout = 0.0f; - } - } + if(result) + { + if(timeout != 0.0f) + { + ms_sleep((int)(timeout * 1000.0f)); + timeout = 0.0f; + } + } #endif - - // Check for incoming messages - if(result) - { - char input_buf[1024]; - apr_size_t request_size; - - if(timeout == 0.0f) - { - // If we have no timeout, start out with a full read. - request_size = sizeof(input_buf); - } - else - { - // Start out by reading one byte, so that any data received will wake us up. - request_size = 1; - } - - // and use the timeout so we'll sleep if no data is available. - setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); - - while(1) - { - size = request_size; - -// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; - - status = apr_socket_recv( - mSocket->getSocket(), - input_buf, - &size); - -// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; - - if(size > 0) - { - LLMutexLock lock(&mInputMutex); - mInput.append(input_buf, size); - } - - if(status == APR_SUCCESS) - { - LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL; - - if(size != request_size) - { - // This was a short read, so we're done. - break; - } - } - else if(APR_STATUS_IS_TIMEUP(status)) - { - LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL; - - // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. - break; - } - else if(APR_STATUS_IS_EAGAIN(status)) - { - LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL; - - // Non-blocking read returned immediately. - break; - } - else if(APR_STATUS_IS_EOF(status)) - { - // This is what we normally expect when a plugin exits. - //LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - break; - } - else - { - // some other error - // Treat this as fatal. - ll_apr_warn_status(status); - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - break; - } - - if(timeout != 0.0f) - { - // Second and subsequent reads should not use the timeout - setSocketTimeout(0); - // and should try to fill the input buffer - request_size = sizeof(input_buf); - } - } - - processInput(); - } - } - - return result; + + // Check for incoming messages + if(result) + { + char input_buf[1024]; + apr_size_t request_size; + + if(timeout == 0.0f) + { + // If we have no timeout, start out with a full read. + request_size = sizeof(input_buf); + } + else + { + // Start out by reading one byte, so that any data received will wake us up. + request_size = 1; + } + + // and use the timeout so we'll sleep if no data is available. + setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); + + while(1) + { + size = request_size; + +// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; + + status = apr_socket_recv( + mSocket->getSocket(), + input_buf, + &size); + +// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; + + if(size > 0) + { + LLMutexLock lock(&mInputMutex); + mInput.append(input_buf, size); + } + + if(status == APR_SUCCESS) + { + LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL; + + if(size != request_size) + { + // This was a short read, so we're done. + break; + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { + LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL; + + // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. + break; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { + LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL; + + // Non-blocking read returned immediately. + break; + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + //LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + + if(timeout != 0.0f) + { + // Second and subsequent reads should not use the timeout + setSocketTimeout(0); + // and should try to fill the input buffer + request_size = sizeof(input_buf); + } + } + + processInput(); + } + } + + return result; } void LLPluginMessagePipe::processInput(void) { - // Look for input delimiter(s) in the input buffer. - int delim; - mInputMutex.lock(); - while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos) - { - // Let the owner process this message - if (mOwner) - { - // Pull the message out of the input buffer before calling receiveMessageRaw. - // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request) - // and this guarantees that the messages will get dequeued correctly. - std::string message(mInput, 0, delim); - mInput.erase(0, delim + 1); - mInputMutex.unlock(); - mOwner->receiveMessageRaw(message); - mInputMutex.lock(); - } - else - { - LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; - } - } - mInputMutex.unlock(); + // Look for input delimiter(s) in the input buffer. + int delim; + mInputMutex.lock(); + while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos) + { + // Let the owner process this message + if (mOwner) + { + // Pull the message out of the input buffer before calling receiveMessageRaw. + // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request) + // and this guarantees that the messages will get dequeued correctly. + std::string message(mInput, 0, delim); + mInput.erase(0, delim + 1); + mInputMutex.unlock(); + mOwner->receiveMessageRaw(message); + mInputMutex.lock(); + } + else + { + LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; + } + } + mInputMutex.unlock(); } diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h index 9d5835eb82..20b1ee06a8 100644 --- a/indra/llplugin/llpluginmessagepipe.h +++ b/indra/llplugin/llpluginmessagepipe.h @@ -1,4 +1,4 @@ -/** +/** * @file llpluginmessagepipe.h * @brief Classes that implement connections from the plugin system to pipes/pumps. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -38,59 +38,59 @@ class LLPluginMessagePipe; // Inherit from this to be able to receive messages from the LLPluginMessagePipe class LLPluginMessagePipeOwner { - LOG_CLASS(LLPluginMessagePipeOwner); + LOG_CLASS(LLPluginMessagePipeOwner); public: - LLPluginMessagePipeOwner(); - virtual ~LLPluginMessagePipeOwner(); + LLPluginMessagePipeOwner(); + virtual ~LLPluginMessagePipeOwner(); - // called with incoming messages - virtual void receiveMessageRaw(const std::string &message) = 0; - // called when the socket has an error - virtual apr_status_t socketError(apr_status_t error); + // called with incoming messages + virtual void receiveMessageRaw(const std::string &message) = 0; + // called when the socket has an error + virtual apr_status_t socketError(apr_status_t error); - // called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use! - virtual void setMessagePipe(LLPluginMessagePipe *message_pipe); + // called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use! + virtual void setMessagePipe(LLPluginMessagePipe *message_pipe); protected: - // returns false if writeMessageRaw() would drop the message - bool canSendMessage(void); - // call this to send a message over the pipe - bool writeMessageRaw(const std::string &message); - // call this to close the pipe - void killMessagePipe(void); - - LLPluginMessagePipe *mMessagePipe; - apr_status_t mSocketError; + // returns false if writeMessageRaw() would drop the message + bool canSendMessage(void); + // call this to send a message over the pipe + bool writeMessageRaw(const std::string &message); + // call this to close the pipe + void killMessagePipe(void); + + LLPluginMessagePipe *mMessagePipe; + apr_status_t mSocketError; }; class LLPluginMessagePipe { - LOG_CLASS(LLPluginMessagePipe); + LOG_CLASS(LLPluginMessagePipe); public: - LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket); - virtual ~LLPluginMessagePipe(); - - bool addMessage(const std::string &message); - void clearOwner(void); - - bool pump(F64 timeout = 0.0f); - bool pumpOutput(); - bool pumpInput(F64 timeout = 0.0f); - -protected: - void processInput(void); - - // used internally by pump() - void setSocketTimeout(apr_interval_time_t timeout_usec); - - LLMutex mInputMutex; - std::string mInput; - LLMutex mOutputMutex; - std::string mOutput; - std::string::size_type mOutputStartIndex; - - LLPluginMessagePipeOwner *mOwner; - LLSocket::ptr_t mSocket; + LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket); + virtual ~LLPluginMessagePipe(); + + bool addMessage(const std::string &message); + void clearOwner(void); + + bool pump(F64 timeout = 0.0f); + bool pumpOutput(); + bool pumpInput(F64 timeout = 0.0f); + +protected: + void processInput(void); + + // used internally by pump() + void setSocketTimeout(apr_interval_time_t timeout_usec); + + LLMutex mInputMutex; + std::string mInput; + LLMutex mOutputMutex; + std::string mOutput; + std::string::size_type mOutputStartIndex; + + LLPluginMessagePipeOwner *mOwner; + LLSocket::ptr_t mSocket; }; #endif // LL_LLPLUGINMESSAGE_H diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index d93ec8cf4b..a854ced7aa 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -39,192 +39,192 @@ static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will LLPluginProcessChild::LLPluginProcessChild() { - mState = STATE_UNINITIALIZED; - mInstance = NULL; - mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); - mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz - mCPUElapsed = 0.0f; - mBlockingRequest = false; - mBlockingResponseReceived = false; + mState = STATE_UNINITIALIZED; + mInstance = NULL; + mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz + mCPUElapsed = 0.0f; + mBlockingRequest = false; + mBlockingResponseReceived = false; } LLPluginProcessChild::~LLPluginProcessChild() { - if (mInstance != NULL) - { - sendMessageToPlugin(LLPluginMessage("base", "cleanup")); - - // IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted - // appears to fail and lock up which means that a given instance of the slplugin process never exits. - // This is bad, especially when users try to update their version of SL - it fails because the slplugin - // process as well as a bunch of plugin specific files are locked and cannot be overwritten. - exit(0); - //delete mInstance; - //mInstance = NULL; - } + if (mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + + // IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted + // appears to fail and lock up which means that a given instance of the slplugin process never exits. + // This is bad, especially when users try to update their version of SL - it fails because the slplugin + // process as well as a bunch of plugin specific files are locked and cannot be overwritten. + exit(0); + //delete mInstance; + //mInstance = NULL; + } } void LLPluginProcessChild::killSockets(void) { - killMessagePipe(); - mSocket.reset(); + killMessagePipe(); + mSocket.reset(); } void LLPluginProcessChild::init(U32 launcher_port) { - mLauncherHost = LLHost("127.0.0.1", launcher_port); - setState(STATE_INITIALIZED); + mLauncherHost = LLHost("127.0.0.1", launcher_port); + setState(STATE_INITIALIZED); } void LLPluginProcessChild::idle(void) { - bool idle_again; - do - { - if (mState < STATE_SHUTDOWNREQ) - { // Once we have hit the shutdown request state checking for errors might put us in a spurious - // error state... don't do that. - - if (APR_STATUS_IS_EOF(mSocketError)) - { - // Plugin socket was closed. This covers both normal plugin termination and host crashes. - setState(STATE_ERROR); - } - else if (mSocketError != APR_SUCCESS) - { - LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR" << LL_ENDL; - setState(STATE_ERROR); - } - - if ((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) - { - // The pipe has been closed -- we're done. - // TODO: This could be slightly more subtle, but I'm not sure it needs to be. - LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR" << LL_ENDL; - setState(STATE_ERROR); - } - } - - // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). - // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. - // When in doubt, don't do it. - idle_again = false; - - if (mInstance != NULL) - { - // Provide some time to the plugin - mInstance->idle(); - } - - switch (mState) - { - case STATE_UNINITIALIZED: - break; - - case STATE_INITIALIZED: - if (mSocket->blockingConnect(mLauncherHost)) - { - // This automatically sets mMessagePipe - new LLPluginMessagePipe(this, mSocket); - - setState(STATE_CONNECTED); - } - else - { - // connect failed - setState(STATE_ERROR); - } - break; - - case STATE_CONNECTED: - sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); - setState(STATE_PLUGIN_LOADING); - break; - - case STATE_PLUGIN_LOADING: - if (!mPluginFile.empty()) - { - mInstance = new LLPluginInstance(this); - if (mInstance->load(mPluginDir, mPluginFile) == 0) - { - mHeartbeat.start(); - mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); - mCPUElapsed = 0.0f; - setState(STATE_PLUGIN_LOADED); - } - else - { - setState(STATE_ERROR); - } - } - break; - - case STATE_PLUGIN_LOADED: - { - setState(STATE_PLUGIN_INITIALIZING); - LLPluginMessage message("base", "init"); - sendMessageToPlugin(message); - } - break; - - case STATE_PLUGIN_INITIALIZING: - // waiting for init_response... - break; - - case STATE_RUNNING: - if (mInstance != NULL) - { - // Provide some time to the plugin - LLPluginMessage message("base", "idle"); - message.setValueReal("time", PLUGIN_IDLE_SECONDS); - sendMessageToPlugin(message); - - mInstance->idle(); - - if (mHeartbeat.hasExpired()) - { - - // This just proves that we're not stuck down inside the plugin code. - LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); - - // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. - // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. - // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. - heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); - - sendMessageToParent(heartbeat); - - mHeartbeat.reset(); - mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); - mCPUElapsed = 0.0f; - } - } - // receivePluginMessage will transition to STATE_UNLOADING - break; - - case STATE_SHUTDOWNREQ: - // set next state first thing in case "cleanup" message advances state. - setState(STATE_UNLOADING); - mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS); - - if (mInstance != NULL) - { - sendMessageToPlugin(LLPluginMessage("base", "cleanup")); - } - break; - - case STATE_UNLOADING: - // waiting for goodbye from plugin. - if (mWaitGoodbye.hasExpired()) - { - LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL; - if (mInstance != NULL) - { - // Something went wrong, at least make sure plugin will terminate - sendMessageToPlugin(LLPluginMessage("base", "force_exit")); - } - setState(STATE_UNLOADED); - } + bool idle_again; + do + { + if (mState < STATE_SHUTDOWNREQ) + { // Once we have hit the shutdown request state checking for errors might put us in a spurious + // error state... don't do that. + + if (APR_STATUS_IS_EOF(mSocketError)) + { + // Plugin socket was closed. This covers both normal plugin termination and host crashes. + setState(STATE_ERROR); + } + else if (mSocketError != APR_SUCCESS) + { + LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR" << LL_ENDL; + setState(STATE_ERROR); + } + + if ((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) + { + // The pipe has been closed -- we're done. + // TODO: This could be slightly more subtle, but I'm not sure it needs to be. + LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR" << LL_ENDL; + setState(STATE_ERROR); + } + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + + if (mInstance != NULL) + { + // Provide some time to the plugin + mInstance->idle(); + } + + switch (mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + if (mSocket->blockingConnect(mLauncherHost)) + { + // This automatically sets mMessagePipe + new LLPluginMessagePipe(this, mSocket); + + setState(STATE_CONNECTED); + } + else + { + // connect failed + setState(STATE_ERROR); + } + break; + + case STATE_CONNECTED: + sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); + setState(STATE_PLUGIN_LOADING); + break; + + case STATE_PLUGIN_LOADING: + if (!mPluginFile.empty()) + { + mInstance = new LLPluginInstance(this); + if (mInstance->load(mPluginDir, mPluginFile) == 0) + { + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; + setState(STATE_PLUGIN_LOADED); + } + else + { + setState(STATE_ERROR); + } + } + break; + + case STATE_PLUGIN_LOADED: + { + setState(STATE_PLUGIN_INITIALIZING); + LLPluginMessage message("base", "init"); + sendMessageToPlugin(message); + } + break; + + case STATE_PLUGIN_INITIALIZING: + // waiting for init_response... + break; + + case STATE_RUNNING: + if (mInstance != NULL) + { + // Provide some time to the plugin + LLPluginMessage message("base", "idle"); + message.setValueReal("time", PLUGIN_IDLE_SECONDS); + sendMessageToPlugin(message); + + mInstance->idle(); + + if (mHeartbeat.hasExpired()) + { + + // This just proves that we're not stuck down inside the plugin code. + LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); + + // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. + // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. + // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. + heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); + + sendMessageToParent(heartbeat); + + mHeartbeat.reset(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; + } + } + // receivePluginMessage will transition to STATE_UNLOADING + break; + + case STATE_SHUTDOWNREQ: + // set next state first thing in case "cleanup" message advances state. + setState(STATE_UNLOADING); + mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS); + + if (mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + } + break; + + case STATE_UNLOADING: + // waiting for goodbye from plugin. + if (mWaitGoodbye.hasExpired()) + { + LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL; + if (mInstance != NULL) + { + // Something went wrong, at least make sure plugin will terminate + sendMessageToPlugin(LLPluginMessage("base", "force_exit")); + } + setState(STATE_UNLOADED); + } if (mInstance) { @@ -237,370 +237,370 @@ void LLPluginProcessChild::idle(void) mInstance->idle(); } - break; + break; - case STATE_UNLOADED: - killSockets(); - delete mInstance; - mInstance = NULL; - setState(STATE_DONE); - break; + case STATE_UNLOADED: + killSockets(); + delete mInstance; + mInstance = NULL; + setState(STATE_DONE); + break; - case STATE_ERROR: - // Close the socket to the launcher - killSockets(); - // TODO: Where do we go from here? Just exit()? - setState(STATE_DONE); - break; + case STATE_ERROR: + // Close the socket to the launcher + killSockets(); + // TODO: Where do we go from here? Just exit()? + setState(STATE_DONE); + break; - case STATE_DONE: - // just sit here. - break; - } + case STATE_DONE: + // just sit here. + break; + } - } while (idle_again); + } while (idle_again); } void LLPluginProcessChild::sleep(F64 seconds) { - deliverQueuedMessages(); - if (mMessagePipe) - { - mMessagePipe->pump(seconds); - } - else - { + deliverQueuedMessages(); + if (mMessagePipe) + { + mMessagePipe->pump(seconds); + } + else + { ms_sleep((int)(seconds * 1000.0f)); - } + } } void LLPluginProcessChild::pump(void) { - deliverQueuedMessages(); - if (mMessagePipe) - { - mMessagePipe->pump(0.0f); - } - else - { - // Should we warn here? - } + deliverQueuedMessages(); + if (mMessagePipe) + { + mMessagePipe->pump(0.0f); + } + else + { + // Should we warn here? + } } bool LLPluginProcessChild::isRunning(void) { - bool result = false; + bool result = false; - if (mState == STATE_RUNNING) - result = true; + if (mState == STATE_RUNNING) + result = true; - return result; + return result; } bool LLPluginProcessChild::isDone(void) { - bool result = false; - - switch (mState) - { - case STATE_DONE: - result = true; - break; - default: - break; - } - - return result; + bool result = false; + + switch (mState) + { + case STATE_DONE: + result = true; + break; + default: + break; + } + + return result; } void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) { - if (mInstance) - { - std::string buffer = message.generate(); + if (mInstance) + { + std::string buffer = message.generate(); - LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; - LLTimer elapsed; + LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; + LLTimer elapsed; - mInstance->sendMessage(buffer); + mInstance->sendMessage(buffer); - mCPUElapsed += elapsed.getElapsedTimeF64(); - } - else - { - LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL; - } + mCPUElapsed += elapsed.getElapsedTimeF64(); + } + else + { + LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL; + } } void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) { - std::string buffer = message.generate(); + std::string buffer = message.generate(); - LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; + LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; - writeMessageRaw(buffer); + writeMessageRaw(buffer); } 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 == "shutdown_plugin") - { - setState(STATE_SHUTDOWNREQ); - } - 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(); - } + // 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 == "shutdown_plugin") + { + setState(STATE_SHUTDOWNREQ); + } + 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(); + } } /* 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 == "goodbye") - { - setState(STATE_UNLOADED); - } - 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); - } - - 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; - } - } + 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 == "goodbye") + { + setState(STATE_UNLOADED); + } + 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); + } + + 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; + } + } } void LLPluginProcessChild::setState(EState state) { - LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; - mState = state; + LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; + mState = state; }; void LLPluginProcessChild::deliverQueuedMessages() { - if (!mBlockingRequest) - { - while (!mMessageQueue.empty()) - { - receiveMessageRaw(mMessageQueue.front()); - mMessageQueue.pop(); - } - } + if (!mBlockingRequest) + { + while (!mMessageQueue.empty()) + { + receiveMessageRaw(mMessageQueue.front()); + mMessageQueue.pop(); + } + } } diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index b916cc9528..5de0f90209 100644 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -1,26 +1,26 @@ -/** +/** * @file llpluginprocesschild.h - * @brief LLPluginProcessChild handles the child side of the external-process plugin API. + * @brief LLPluginProcessChild handles the child side of the external-process plugin API. * * @cond * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -40,76 +40,76 @@ class LLPluginInstance; class LLPluginProcessChild: public LLPluginMessagePipeOwner, public LLPluginInstanceMessageListener { - LOG_CLASS(LLPluginProcessChild); + LOG_CLASS(LLPluginProcessChild); public: - LLPluginProcessChild(); - ~LLPluginProcessChild(); - - void init(U32 launcher_port); - void idle(void); - void sleep(F64 seconds); - void pump(); - - // returns true if the plugin is in the steady state (processing messages) - bool isRunning(void); - - // returns true if the plugin is unloaded or we're in an unrecoverable error state. - bool isDone(void); - - void killSockets(void); - - F64 getSleepTime(void) const { return mSleepTime; }; - - void sendMessageToPlugin(const LLPluginMessage &message); - void sendMessageToParent(const LLPluginMessage &message); - - // Inherited from LLPluginMessagePipeOwner - /* virtual */ void receiveMessageRaw(const std::string &message); - - // Inherited from LLPluginInstanceMessageListener - /* virtual */ void receivePluginMessage(const std::string &message); - + LLPluginProcessChild(); + ~LLPluginProcessChild(); + + void init(U32 launcher_port); + void idle(void); + void sleep(F64 seconds); + void pump(); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); + + // returns true if the plugin is unloaded or we're in an unrecoverable error state. + bool isDone(void); + + void killSockets(void); + + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessageToPlugin(const LLPluginMessage &message); + void sendMessageToParent(const LLPluginMessage &message); + + // Inherited from LLPluginMessagePipeOwner + /* virtual */ void receiveMessageRaw(const std::string &message); + + // Inherited from LLPluginInstanceMessageListener + /* virtual */ void receivePluginMessage(const std::string &message); + private: - enum EState - { - STATE_UNINITIALIZED, - STATE_INITIALIZED, // init() has been called - STATE_CONNECTED, // connected back to launcher - STATE_PLUGIN_LOADING, // plugin library needs to be loaded - STATE_PLUGIN_LOADED, // plugin library has been loaded - STATE_PLUGIN_INITIALIZING, // plugin is processing init message - STATE_RUNNING, // steady state (processing messages) + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_CONNECTED, // connected back to launcher + STATE_PLUGIN_LOADING, // plugin library needs to be loaded + STATE_PLUGIN_LOADED, // plugin library has been loaded + STATE_PLUGIN_INITIALIZING, // plugin is processing init message + STATE_RUNNING, // steady state (processing messages) STATE_SHUTDOWNREQ, // Parent has requested a shutdown. - STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded - STATE_UNLOADED, // plugin has been unloaded - STATE_ERROR, // generic bailout state - STATE_DONE // state machine will sit in this state after either error or normal termination. - }; - void setState(EState state); - - EState mState; - - LLHost mLauncherHost; - LLSocket::ptr_t mSocket; - - std::string mPluginFile; - std::string mPluginDir; - - LLPluginInstance *mInstance; - - typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; - sharedMemoryRegionsType mSharedMemoryRegions; - - LLTimer mHeartbeat; - F64 mSleepTime; - F64 mCPUElapsed; - bool mBlockingRequest; - bool mBlockingResponseReceived; - std::queue<std::string> mMessageQueue; + STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded + STATE_UNLOADED, // plugin has been unloaded + STATE_ERROR, // generic bailout state + STATE_DONE // state machine will sit in this state after either error or normal termination. + }; + void setState(EState state); + + EState mState; + + LLHost mLauncherHost; + LLSocket::ptr_t mSocket; + + std::string mPluginFile; + std::string mPluginDir; + + LLPluginInstance *mInstance; + + typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLTimer mHeartbeat; + F64 mSleepTime; + F64 mCPUElapsed; + bool mBlockingRequest; + bool mBlockingResponseReceived; + std::queue<std::string> mMessageQueue; LLTimer mWaitGoodbye; - void deliverQueuedMessages(); - + void deliverQueuedMessages(); + }; #endif // LL_LLPLUGINPROCESSCHILD_H diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 756d0b5db8..567a9b9559 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginprocessparent.cpp * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -37,10 +37,10 @@ #include "llapr.h" -//virtual +//virtual LLPluginProcessParentOwner::~LLPluginProcessParentOwner() { - + } bool LLPluginProcessParent::sUseReadThread = false; @@ -54,29 +54,29 @@ LLThread *LLPluginProcessParent::sReadThread = NULL; class LLPluginProcessParentPollThread: public LLThread { public: - LLPluginProcessParentPollThread() : - LLThread("LLPluginProcessParentPollThread", gAPRPoolp) - { - } + LLPluginProcessParentPollThread() : + LLThread("LLPluginProcessParentPollThread", gAPRPoolp) + { + } protected: - // Inherited from LLThread - /*virtual*/ void run(void) - { - while(!isQuitting() && LLPluginProcessParent::getUseReadThread()) - { - LLPluginProcessParent::poll(0.1f); - checkPause(); - } - - // Final poll to clean up the pollset, etc. - LLPluginProcessParent::poll(0.0f); - } - - // Inherited from LLThread - /*virtual*/ bool runCondition(void) - { - return(LLPluginProcessParent::canPollThreadRun()); - } + // Inherited from LLThread + /*virtual*/ void run(void) + { + while(!isQuitting() && LLPluginProcessParent::getUseReadThread()) + { + LLPluginProcessParent::poll(0.1f); + checkPause(); + } + + // Final poll to clean up the pollset, etc. + LLPluginProcessParent::poll(0.0f); + } + + // Inherited from LLThread + /*virtual*/ bool runCondition(void) + { + return(LLPluginProcessParent::canPollThreadRun()); + } }; @@ -104,33 +104,33 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): mIncomingQueueMutex(), pProcessCreationThread(NULL) { - if(!sInstancesMutex) - { - sInstancesMutex = new LLMutex(); - } - - mOwner = owner; - mBoundPort = 0; - mState = STATE_UNINITIALIZED; - mSleepTime = 0.0; - mCPUUsage = 0.0; - mDisableTimeout = false; - mDebug = false; - mBlocked = false; - mPolledInput = false; - mPollFD.client_data = NULL; - - mPluginLaunchTimeout = 60.0f; - mPluginLockupTimeout = 15.0f; - - // Don't start the timer here -- start it when we actually launch the plugin process. - mHeartbeat.stop(); - + if(!sInstancesMutex) + { + sInstancesMutex = new LLMutex(); + } + + mOwner = owner; + mBoundPort = 0; + mState = STATE_UNINITIALIZED; + mSleepTime = 0.0; + mCPUUsage = 0.0; + mDisableTimeout = false; + mDebug = false; + mBlocked = false; + mPolledInput = false; + mPollFD.client_data = NULL; + + mPluginLaunchTimeout = 60.0f; + mPluginLockupTimeout = 15.0f; + + // Don't start the timer here -- start it when we actually launch the plugin process. + mHeartbeat.stop(); + } LLPluginProcessParent::~LLPluginProcessParent() { - LL_DEBUGS("Plugin") << "destructor" << LL_ENDL; + LL_DEBUGS("Plugin") << "destructor" << LL_ENDL; if (pProcessCreationThread) { if (!pProcessCreationThread->isStopped()) @@ -144,20 +144,20 @@ LLPluginProcessParent::~LLPluginProcessParent() pProcessCreationThread = NULL; } - // Destroy any remaining shared memory regions - sharedMemoryRegionsType::iterator iter; - while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end()) - { - // destroy the shared memory region - iter->second->destroy(); - delete iter->second; - iter->second = NULL; - - // and remove it from our map - mSharedMemoryRegions.erase(iter); - } - - LLProcess::kill(mProcess); + // Destroy any remaining shared memory regions + sharedMemoryRegionsType::iterator iter; + while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end()) + { + // destroy the shared memory region + iter->second->destroy(); + delete iter->second; + iter->second = NULL; + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + + LLProcess::kill(mProcess); if (!LLApp::isQuitting()) { // If we are quitting, the network sockets will already have been destroyed. killSockets(); @@ -227,7 +227,7 @@ void LLPluginProcessParent::requestShutdown() namestream << "LLPluginProcessParentListener" << ++count; //*HACK!*// - // After requestShutdown has been called our previous owner will no longer call + // After requestShutdown has been called our previous owner will no longer call // our idle() method. Tie into the event loop here to do that until we are good // and finished. LL_DEBUGS("LLPluginProcessParent") << "listening on \"mainloop\"" << LL_ENDL; @@ -279,78 +279,78 @@ bool LLPluginProcessParent::wantsPolling() const void LLPluginProcessParent::killSockets(void) { - { - LLMutexLock lock(&mIncomingQueueMutex); - killMessagePipe(); - } + { + LLMutexLock lock(&mIncomingQueueMutex); + killMessagePipe(); + } - mListenSocket.reset(); - mSocket.reset(); + mListenSocket.reset(); + mSocket.reset(); } void LLPluginProcessParent::errorState(void) { - if(mState < STATE_RUNNING) - setState(STATE_LAUNCH_FAILURE); - else - setState(STATE_ERROR); + if(mState < STATE_RUNNING) + setState(STATE_LAUNCH_FAILURE); + else + setState(STATE_ERROR); } void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) -{ - mProcessParams.executable = launcher_filename; - mProcessParams.cwd = plugin_dir; - mPluginFile = plugin_filename; - mPluginDir = plugin_dir; - mCPUUsage = 0.0f; - mDebug = debug; - setState(STATE_INITIALIZED); +{ + mProcessParams.executable = launcher_filename; + mProcessParams.cwd = plugin_dir; + mPluginFile = plugin_filename; + mPluginDir = plugin_dir; + mCPUUsage = 0.0f; + mDebug = debug; + setState(STATE_INITIALIZED); } bool LLPluginProcessParent::accept() { - bool result = false; - - apr_status_t status = APR_EGENERAL; - apr_socket_t *new_socket = NULL; - - status = apr_socket_accept( - &new_socket, - mListenSocket->getSocket(), - gAPRPoolp); - - - if(status == APR_SUCCESS) - { -// LL_INFOS() << "SUCCESS" << LL_ENDL; - // Success. Create a message pipe on the new socket - - // we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor! - apr_pool_t* new_pool = NULL; - status = apr_pool_create(&new_pool, gAPRPoolp); - - mSocket = LLSocket::create(new_socket, new_pool); - new LLPluginMessagePipe(this, mSocket); - - result = true; - } - else if(APR_STATUS_IS_EAGAIN(status)) - { -// LL_INFOS() << "EAGAIN" << LL_ENDL; - - // No incoming connections. This is not an error. - status = APR_SUCCESS; - } - else - { -// LL_INFOS() << "Error:" << LL_ENDL; - ll_apr_warn_status(status); - - // Some other error. - errorState(); - } - - return result; + bool result = false; + + apr_status_t status = APR_EGENERAL; + apr_socket_t *new_socket = NULL; + + status = apr_socket_accept( + &new_socket, + mListenSocket->getSocket(), + gAPRPoolp); + + + if(status == APR_SUCCESS) + { +// LL_INFOS() << "SUCCESS" << LL_ENDL; + // Success. Create a message pipe on the new socket + + // we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor! + apr_pool_t* new_pool = NULL; + status = apr_pool_create(&new_pool, gAPRPoolp); + + mSocket = LLSocket::create(new_socket, new_pool); + new LLPluginMessagePipe(this, mSocket); + + result = true; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { +// LL_INFOS() << "EAGAIN" << LL_ENDL; + + // No incoming connections. This is not an error. + status = APR_SUCCESS; + } + else + { +// LL_INFOS() << "Error:" << LL_ENDL; + ll_apr_warn_status(status); + + // Some other error. + errorState(); + } + + return result; } bool LLPluginProcessParent::createPluginProcess() @@ -384,166 +384,166 @@ void LLPluginProcessParent::clearProcessCreationThread() void LLPluginProcessParent::idle(void) { - bool idle_again; + bool idle_again; - do - { - // process queued messages + do + { + // process queued messages // Inside main thread, it is preferable not to block it on mutex. - bool locked = mIncomingQueueMutex.trylock(); - while(locked && !mIncomingQueue.empty()) - { - LLPluginMessage message = mIncomingQueue.front(); - mIncomingQueue.pop(); - mIncomingQueueMutex.unlock(); - - receiveMessage(message); - - locked = mIncomingQueueMutex.trylock(); - } + bool locked = mIncomingQueueMutex.trylock(); + while(locked && !mIncomingQueue.empty()) + { + LLPluginMessage message = mIncomingQueue.front(); + mIncomingQueue.pop(); + mIncomingQueueMutex.unlock(); + + receiveMessage(message); + + locked = mIncomingQueueMutex.trylock(); + } if (locked) { mIncomingQueueMutex.unlock(); } - - // Give time to network processing - if(mMessagePipe) - { - // Drain any queued outgoing messages - mMessagePipe->pumpOutput(); - - // Only do input processing here if this instance isn't in a pollset. - // If viewer and plugin are both shutting down, don't process further - // input, viewer won't be able to handle it. - if(!mPolledInput - && !(mState >= STATE_GOODBYE && LLApp::isExiting())) - { - mMessagePipe->pumpInput(); - } - } - - if(mState <= STATE_RUNNING) - { - if(APR_STATUS_IS_EOF(mSocketError)) - { - // Plugin socket was closed. This covers both normal plugin termination and plugin crashes. - errorState(); - } - else if(mSocketError != APR_SUCCESS) - { - // The socket is in an error state -- the plugin is gone. - LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; - errorState(); - } - } - - // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). - // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. - // When in doubt, don't do it. - idle_again = false; - switch(mState) - { - case STATE_UNINITIALIZED: - break; - - case STATE_INITIALIZED: - { - - apr_status_t status = APR_SUCCESS; - apr_sockaddr_t* addr = NULL; - mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); - mBoundPort = 0; - - // This code is based on parts of LLSocket::create() in lliosocket.cpp. - - status = apr_sockaddr_info_get( - &addr, - "127.0.0.1", - APR_INET, - 0, // port 0 = ephemeral ("find me a port") - 0, - gAPRPoolp); - - if(ll_apr_warn_status(status)) - { - killSockets(); - errorState(); - break; - } - - // This allows us to reuse the address on quick down/up. This is unlikely to create problems. - ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); - - status = apr_socket_bind(mListenSocket->getSocket(), addr); - if(ll_apr_warn_status(status)) - { - killSockets(); - errorState(); - break; - } - - // Get the actual port the socket was bound to - { - apr_sockaddr_t* bound_addr = NULL; - if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) - { - killSockets(); - errorState(); - break; - } - mBoundPort = bound_addr->port; - - if(mBoundPort == 0) - { - LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; - - killSockets(); - errorState(); - break; - } - } - - LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; - - // Make the listen socket non-blocking - status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); - if(ll_apr_warn_status(status)) - { - killSockets(); - errorState(); - break; - } - - apr_socket_timeout_set(mListenSocket->getSocket(), 0); - if(ll_apr_warn_status(status)) - { - killSockets(); - errorState(); - break; - } - - // If it's a stream based socket, we need to tell the OS - // to keep a queue of incoming connections for ACCEPT. - status = apr_socket_listen( - mListenSocket->getSocket(), - 10); // FIXME: Magic number for queue size - - if(ll_apr_warn_status(status)) - { - killSockets(); - errorState(); - break; - } - - // If we got here, we're listening. - setState(STATE_LISTENING); - } - break; - - case STATE_LISTENING: - { - // Launch the plugin process. + + // Give time to network processing + if(mMessagePipe) + { + // Drain any queued outgoing messages + mMessagePipe->pumpOutput(); + + // Only do input processing here if this instance isn't in a pollset. + // If viewer and plugin are both shutting down, don't process further + // input, viewer won't be able to handle it. + if(!mPolledInput + && !(mState >= STATE_GOODBYE && LLApp::isExiting())) + { + mMessagePipe->pumpInput(); + } + } + + if(mState <= STATE_RUNNING) + { + if(APR_STATUS_IS_EOF(mSocketError)) + { + // Plugin socket was closed. This covers both normal plugin termination and plugin crashes. + errorState(); + } + else if(mSocketError != APR_SUCCESS) + { + // The socket is in an error state -- the plugin is gone. + LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; + errorState(); + } + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + switch(mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + { + + apr_status_t status = APR_SUCCESS; + apr_sockaddr_t* addr = NULL; + mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mBoundPort = 0; + + // This code is based on parts of LLSocket::create() in lliosocket.cpp. + + status = apr_sockaddr_info_get( + &addr, + "127.0.0.1", + APR_INET, + 0, // port 0 = ephemeral ("find me a port") + 0, + gAPRPoolp); + + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // This allows us to reuse the address on quick down/up. This is unlikely to create problems. + ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); + + status = apr_socket_bind(mListenSocket->getSocket(), addr); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // Get the actual port the socket was bound to + { + apr_sockaddr_t* bound_addr = NULL; + if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) + { + killSockets(); + errorState(); + break; + } + mBoundPort = bound_addr->port; + + if(mBoundPort == 0) + { + LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; + + killSockets(); + errorState(); + break; + } + } + + LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; + + // Make the listen socket non-blocking + status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + apr_socket_timeout_set(mListenSocket->getSocket(), 0); + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // If it's a stream based socket, we need to tell the OS + // to keep a queue of incoming connections for ACCEPT. + status = apr_socket_listen( + mListenSocket->getSocket(), + 10); // FIXME: Magic number for queue size + + if(ll_apr_warn_status(status)) + { + killSockets(); + errorState(); + break; + } + + // If we got here, we're listening. + setState(STATE_LISTENING); + } + break; + + case STATE_LISTENING: + { + // Launch the plugin process. if (mDebug && !pProcessCreationThread) { createPluginProcess(); @@ -566,36 +566,36 @@ void LLPluginProcessParent::idle(void) errorState(); } - - if (mProcess) - { - if(mDebug) - { + + if (mProcess) + { + if(mDebug) + { #if LL_DARWIN - // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. - - // The command we're constructing would look like this on the command line: - // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' - - LLProcess::Params params; - params.executable = "/usr/bin/osascript"; - params.args.add("-e"); - params.args.add("tell application \"Terminal\""); - params.args.add("-e"); - params.args.add(STRINGIZE("set win to do script \"gdb -pid " - << mProcess->getProcessID() << "\"")); - params.args.add("-e"); - params.args.add("do script \"continue\" in win"); - params.args.add("-e"); - params.args.add("end tell"); - mDebugger = LLProcess::create(params); + // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. + + // The command we're constructing would look like this on the command line: + // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' + + LLProcess::Params params; + params.executable = "/usr/bin/osascript"; + params.args.add("-e"); + params.args.add("tell application \"Terminal\""); + params.args.add("-e"); + params.args.add(STRINGIZE("set win to do script \"gdb -pid " + << mProcess->getProcessID() << "\"")); + params.args.add("-e"); + params.args.add("do script \"continue\" in win"); + params.args.add("-e"); + params.args.add("end tell"); + mDebugger = LLProcess::create(params); #endif - } - - // This will allow us to time out if the process never starts. - mHeartbeat.start(); - mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); + } + + // This will allow us to time out if the process never starts. + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); // pProcessCreationThread should have stopped by this point, // but check just in case it paused on statistics sync @@ -605,67 +605,67 @@ void LLPluginProcessParent::idle(void) pProcessCreationThread = NULL; } - setState(STATE_LAUNCHED); - } - } - break; - - case STATE_LAUNCHED: - // waiting for the plugin to connect - if(pluginLockedUpOrQuit()) - { - errorState(); - } - else - { - // Check for the incoming connection. - if(accept()) - { - // Stop listening on the server port - mListenSocket.reset(); - setState(STATE_CONNECTED); - } - } - break; - - case STATE_CONNECTED: - // waiting for hello message from the plugin - - if(pluginLockedUpOrQuit()) - { - errorState(); - } - break; - - case STATE_HELLO: - LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL; - - // Send the message to load the plugin - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); - message.setValue("file", mPluginFile); - message.setValue("dir", mPluginDir); - sendMessage(message); - } - - setState(STATE_LOADING); - break; - - case STATE_LOADING: - // The load_plugin_response message will kick us from here into STATE_RUNNING - if(pluginLockedUpOrQuit()) - { - errorState(); - } - break; - - case STATE_RUNNING: - if(pluginLockedUpOrQuit()) - { - errorState(); - } - break; - + setState(STATE_LAUNCHED); + } + } + break; + + case STATE_LAUNCHED: + // waiting for the plugin to connect + if(pluginLockedUpOrQuit()) + { + errorState(); + } + else + { + // Check for the incoming connection. + if(accept()) + { + // Stop listening on the server port + mListenSocket.reset(); + setState(STATE_CONNECTED); + } + } + break; + + case STATE_CONNECTED: + // waiting for hello message from the plugin + + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + + case STATE_HELLO: + LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL; + + // Send the message to load the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); + message.setValue("file", mPluginFile); + message.setValue("dir", mPluginDir); + sendMessage(message); + } + + setState(STATE_LOADING); + break; + + case STATE_LOADING: + // The load_plugin_response message will kick us from here into STATE_RUNNING + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + + case STATE_RUNNING: + if(pluginLockedUpOrQuit()) + { + errorState(); + } + break; + case STATE_GOODBYE: { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown_plugin"); @@ -674,292 +674,292 @@ void LLPluginProcessParent::idle(void) setState(STATE_EXITING); break; - case STATE_EXITING: - if (! LLProcess::isRunning(mProcess)) - { - setState(STATE_CLEANUP); - } - else if(pluginLockedUp()) - { - LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL; - errorState(); - } - break; - - case STATE_LAUNCH_FAILURE: - if(mOwner != NULL) - { - mOwner->pluginLaunchFailed(); - } - setState(STATE_CLEANUP); - break; - - case STATE_ERROR: - if(mOwner != NULL) - { - mOwner->pluginDied(); - } - setState(STATE_CLEANUP); - break; - - case STATE_CLEANUP: - LLProcess::kill(mProcess); - killSockets(); - setState(STATE_DONE); + case STATE_EXITING: + if (! LLProcess::isRunning(mProcess)) + { + setState(STATE_CLEANUP); + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL; + errorState(); + } + break; + + case STATE_LAUNCH_FAILURE: + if(mOwner != NULL) + { + mOwner->pluginLaunchFailed(); + } + setState(STATE_CLEANUP); + break; + + case STATE_ERROR: + if(mOwner != NULL) + { + mOwner->pluginDied(); + } + setState(STATE_CLEANUP); + break; + + case STATE_CLEANUP: + LLProcess::kill(mProcess); + killSockets(); + setState(STATE_DONE); dirtyPollSet(); clearProcessCreationThread(); - break; - - case STATE_DONE: - // just sit here. - break; - } - - } while (idle_again); + break; + + case STATE_DONE: + // just sit here. + break; + } + + } while (idle_again); } bool LLPluginProcessParent::isLoading(void) { - bool result = false; - - if(mState <= STATE_LOADING) - result = true; - - return result; + bool result = false; + + if(mState <= STATE_LOADING) + result = true; + + return result; } bool LLPluginProcessParent::isRunning(void) { - bool result = false; - - if(mState == STATE_RUNNING) - result = true; - - return result; + bool result = false; + + if(mState == STATE_RUNNING) + result = true; + + return result; } bool LLPluginProcessParent::isDone(void) { - bool result = false; - - if(mState == STATE_DONE) - result = true; - - return result; + bool result = false; + + if(mState == STATE_DONE) + result = true; + + return result; } void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send) { - if(force_send || (sleep_time != mSleepTime)) - { - // Cache the time locally - mSleepTime = sleep_time; - - if(canSendMessage()) - { - // and send to the plugin. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time"); - message.setValueReal("time", mSleepTime); - sendMessage(message); - } - else - { - // Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later. - } - } + if(force_send || (sleep_time != mSleepTime)) + { + // Cache the time locally + mSleepTime = sleep_time; + + if(canSendMessage()) + { + // and send to the plugin. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time"); + message.setValueReal("time", mSleepTime); + sendMessage(message); + } + else + { + // Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later. + } + } } void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) { - if(message.hasValue("blocking_response")) - { - mBlocked = false; - - // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. - mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); - } - - std::string buffer = message.generate(); - LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; - writeMessageRaw(buffer); - - // Try to send message immediately. - if(mMessagePipe) - { - mMessagePipe->pumpOutput(); - } + if(message.hasValue("blocking_response")) + { + mBlocked = false; + + // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. + mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); + } + + std::string buffer = message.generate(); + LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; + writeMessageRaw(buffer); + + // Try to send message immediately. + if(mMessagePipe) + { + mMessagePipe->pumpOutput(); + } } -//virtual +//virtual void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe) { - bool update_pollset = false; - - if(mMessagePipe) - { - // Unsetting an existing message pipe -- remove from the pollset - mPollFD.client_data = NULL; - - // pollset needs an update - update_pollset = true; - } - if(message_pipe != NULL) - { - // Set up the apr_pollfd_t - mPollFD.p = gAPRPoolp; - mPollFD.desc_type = APR_POLL_SOCKET; - mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP; - mPollFD.rtnevents = 0; - mPollFD.desc.s = mSocket->getSocket(); - mPollFD.client_data = (void*)this; - - // pollset needs an update - update_pollset = true; - } - - mMessagePipe = message_pipe; - - if(update_pollset) - { - dirtyPollSet(); - } + bool update_pollset = false; + + if(mMessagePipe) + { + // Unsetting an existing message pipe -- remove from the pollset + mPollFD.client_data = NULL; + + // pollset needs an update + update_pollset = true; + } + if(message_pipe != NULL) + { + // Set up the apr_pollfd_t + mPollFD.p = gAPRPoolp; + mPollFD.desc_type = APR_POLL_SOCKET; + mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP; + mPollFD.rtnevents = 0; + mPollFD.desc.s = mSocket->getSocket(); + mPollFD.client_data = (void*)this; + + // pollset needs an update + update_pollset = true; + } + + mMessagePipe = message_pipe; + + if(update_pollset) + { + dirtyPollSet(); + } } -//static +//static void LLPluginProcessParent::dirtyPollSet() { - sPollsetNeedsRebuild = true; - - if(sReadThread) - { - LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL; - sReadThread->unpause(); - } + sPollsetNeedsRebuild = true; + + if(sReadThread) + { + LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL; + sReadThread->unpause(); + } } void LLPluginProcessParent::updatePollset() { - if(!sInstancesMutex) - { - // No instances have been created yet. There's no work to do. - return; - } - - LLMutexLock lock(sInstancesMutex); - - if(sPollSet) - { - LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL; - // delete the existing pollset. - apr_pollset_destroy(sPollSet); - sPollSet = NULL; - } - + if(!sInstancesMutex) + { + // No instances have been created yet. There's no work to do. + return; + } + + LLMutexLock lock(sInstancesMutex); + + if(sPollSet) + { + LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL; + // delete the existing pollset. + apr_pollset_destroy(sPollSet); + sPollSet = NULL; + } + mapInstances_t::iterator iter; - int count = 0; - - // Count the number of instances that want to be in the pollset - for(iter = sInstances.begin(); iter != sInstances.end(); iter++) - { - (*iter).second->mPolledInput = false; + int count = 0; + + // Count the number of instances that want to be in the pollset + for(iter = sInstances.begin(); iter != sInstances.end(); iter++) + { + (*iter).second->mPolledInput = false; if ((*iter).second->wantsPolling()) - { - // This instance has a socket that needs to be polled. - ++count; - } - } - - if(sUseReadThread && sReadThread && !sReadThread->isQuitting()) - { - if(!sPollSet && (count > 0)) - { + { + // This instance has a socket that needs to be polled. + ++count; + } + } + + if(sUseReadThread && sReadThread && !sReadThread->isQuitting()) + { + if(!sPollSet && (count > 0)) + { #ifdef APR_POLLSET_NOCOPY - // The pollset doesn't exist yet. Create it now. - apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY); - if(status != APR_SUCCESS) - { + // The pollset doesn't exist yet. Create it now. + apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY); + if(status != APR_SUCCESS) + { #endif // APR_POLLSET_NOCOPY - LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL; - sPollSet = NULL; + LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL; + sPollSet = NULL; #ifdef APR_POLLSET_NOCOPY - } - else - { - LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL; - - // Pollset was created, add all instances to it. - for(iter = sInstances.begin(); iter != sInstances.end(); iter++) - { + } + else + { + LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL; + + // Pollset was created, add all instances to it. + for(iter = sInstances.begin(); iter != sInstances.end(); iter++) + { if ((*iter).second->wantsPolling()) - { - status = apr_pollset_add(sPollSet, &((*iter).second->mPollFD)); - if(status == APR_SUCCESS) - { - (*iter).second->mPolledInput = true; - } - else - { - LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL; - } - } - } - } + { + status = apr_pollset_add(sPollSet, &((*iter).second->mPollFD)); + if(status == APR_SUCCESS) + { + (*iter).second->mPolledInput = true; + } + else + { + LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL; + } + } + } + } #endif // APR_POLLSET_NOCOPY - } - } + } + } } void LLPluginProcessParent::setUseReadThread(bool use_read_thread) { - if(sUseReadThread != use_read_thread) - { - sUseReadThread = use_read_thread; - - if(sUseReadThread) - { - if(!sReadThread) - { - // start up the read thread - LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL; - - // make sure the pollset gets rebuilt. - sPollsetNeedsRebuild = true; - - sReadThread = new LLPluginProcessParentPollThread; - sReadThread->start(); - } - } - else - { - if(sReadThread) - { - // shut down the read thread - LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL; - delete sReadThread; - sReadThread = NULL; - } - } - - } + if(sUseReadThread != use_read_thread) + { + sUseReadThread = use_read_thread; + + if(sUseReadThread) + { + if(!sReadThread) + { + // start up the read thread + LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL; + + // make sure the pollset gets rebuilt. + sPollsetNeedsRebuild = true; + + sReadThread = new LLPluginProcessParentPollThread; + sReadThread->start(); + } + } + else + { + if(sReadThread) + { + // shut down the read thread + LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL; + delete sReadThread; + sReadThread = NULL; + } + } + + } } void LLPluginProcessParent::poll(F64 timeout) { - if(sPollsetNeedsRebuild || !sUseReadThread) - { - sPollsetNeedsRebuild = false; - updatePollset(); - } - - if(sPollSet) - { - apr_status_t status; - apr_int32_t count; - const apr_pollfd_t *descriptors; - status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors); - if(status == APR_SUCCESS) - { - // One or more of the descriptors signalled. Call them. + if(sPollsetNeedsRebuild || !sUseReadThread) + { + sPollsetNeedsRebuild = false; + updatePollset(); + } + + if(sPollSet) + { + apr_status_t status; + apr_int32_t count; + const apr_pollfd_t *descriptors; + status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors); + if(status == APR_SUCCESS) + { + // One or more of the descriptors signalled. Call them. for (int i = 0; i < count; i++) { void *thatId = descriptors[i].client_data; @@ -981,23 +981,23 @@ void LLPluginProcessParent::poll(F64 timeout) that->mIncomingQueueMutex.unlock(); } - } - } - else if(APR_STATUS_IS_TIMEUP(status)) - { - // timed out with no incoming data. Just return. - } - else if(status == EBADF) - { - // This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed. - // The pollset has been or will be recreated, so just return. - LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL; - } - else if(status != APR_SUCCESS) - { - LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL; - } - } + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { + // timed out with no incoming data. Just return. + } + else if(status == EBADF) + { + // This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed. + // The pollset has been or will be recreated, so just return. + LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL; + } + else if(status != APR_SUCCESS) + { + LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL; + } + } // Remove instances in the done state from the sInstances map. mapInstances_t::iterator itClean = sInstances.begin(); @@ -1012,293 +1012,293 @@ void LLPluginProcessParent::poll(F64 timeout) void LLPluginProcessParent::servicePoll() { - bool result = true; - - // poll signalled on this object's socket. Try to process incoming messages. - if(mMessagePipe) - { - result = mMessagePipe->pumpInput(0.0f); - } - - if(!result) - { - // If we got a read error on input, remove this pipe from the pollset - apr_pollset_remove(sPollSet, &mPollFD); - - // and tell the code not to re-add it - mPollFD.client_data = NULL; - } + bool result = true; + + // poll signalled on this object's socket. Try to process incoming messages. + if(mMessagePipe) + { + result = mMessagePipe->pumpInput(0.0f); + } + + if(!result) + { + // If we got a read error on input, remove this pipe from the pollset + apr_pollset_remove(sPollSet, &mPollFD); + + // and tell the code not to re-add it + mPollFD.client_data = NULL; + } } void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { - LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; - - LLPluginMessage parsed; - if(LLSDParser::PARSE_FAILURE != parsed.parse(message)) - { - if(parsed.hasValue("blocking_request")) - { - mBlocked = true; - } - - if(mPolledInput) - { - // This is being called on the polling thread -- only do minimal processing/queueing. - receiveMessageEarly(parsed); - } - else - { - // This is not being called on the polling thread -- do full message processing at this time. - receiveMessage(parsed); - } - } + LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; + + LLPluginMessage parsed; + if(LLSDParser::PARSE_FAILURE != parsed.parse(message)) + { + if(parsed.hasValue("blocking_request")) + { + mBlocked = true; + } + + if(mPolledInput) + { + // This is being called on the polling thread -- only do minimal processing/queueing. + receiveMessageEarly(parsed); + } + else + { + // This is not being called on the polling thread -- do full message processing at this time. + receiveMessage(parsed); + } + } } void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message) { - // NOTE: this function will be called from the polling thread. It will be called with mIncomingQueueMutex _already locked_. - - bool handled = false; - - std::string message_class = message.getClass(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) - { - // no internal messages need to be handled early. - } - else - { - // Call out to the owner and see if they to reply - // TODO: Should this only happen when blocked? - if(mOwner != NULL) - { - handled = mOwner->receivePluginMessageEarly(message); - } - } - - if(!handled) - { - // any message that wasn't handled early needs to be queued. - mIncomingQueue.push(message); - } + // NOTE: this function will be called from the polling thread. It will be called with mIncomingQueueMutex _already locked_. + + bool handled = false; + + std::string message_class = message.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + // no internal messages need to be handled early. + } + else + { + // Call out to the owner and see if they to reply + // TODO: Should this only happen when blocked? + if(mOwner != NULL) + { + handled = mOwner->receivePluginMessageEarly(message); + } + } + + if(!handled) + { + // any message that wasn't handled early needs to be queued. + mIncomingQueue.push(message); + } } 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 - llassert_always(mSleepTime != 0.f); - 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("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; - - } - 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(); - delete iter->second; - iter->second = NULL; - - // and remove it from our map - mSharedMemoryRegions.erase(iter); - } - } - else - { - LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL; - } - } - else - { - if(mOwner != NULL) - { - mOwner->receivePluginMessage(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 + llassert_always(mSleepTime != 0.f); + 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("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; + + } + 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(); + delete iter->second; + iter->second = NULL; + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + } + else + { + LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL; + } + } + else + { + if(mOwner != NULL) + { + mOwner->receivePluginMessage(message); + } + } } std::string LLPluginProcessParent::addSharedMemory(size_t size) { - std::string name; - - LLPluginSharedMemory *region = new LLPluginSharedMemory; - - // This is a new region - if(region->create(size)) - { - name = region->getName(); - - mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add"); - message.setValue("name", name); - message.setValueS32("size", (S32)size); - sendMessage(message); - } - else - { - LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; - - // Don't leak - delete region; - } - - return name; + std::string name; + + LLPluginSharedMemory *region = new LLPluginSharedMemory; + + // This is a new region + if(region->create(size)) + { + name = region->getName(); + + mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add"); + message.setValue("name", name); + message.setValueS32("size", (S32)size); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + + // Don't leak + delete region; + } + + return name; } void LLPluginProcessParent::removeSharedMemory(const std::string &name) { - sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); - - if(iter != mSharedMemoryRegions.end()) - { - // This segment exists. Send the message to the child to unmap it. The response will cause the parent to unmap our end. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove"); - message.setValue("name", name); - sendMessage(message); - } - else - { - LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL; - } + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + + if(iter != mSharedMemoryRegions.end()) + { + // This segment exists. Send the message to the child to unmap it. The response will cause the parent to unmap our end. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove"); + message.setValue("name", name); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL; + } } size_t LLPluginProcessParent::getSharedMemorySize(const std::string &name) { - size_t result = 0; - - sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); - if(iter != mSharedMemoryRegions.end()) - { - result = iter->second->getSize(); - } - - return result; + size_t result = 0; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getSize(); + } + + return result; } void *LLPluginProcessParent::getSharedMemoryAddress(const std::string &name) { - void *result = NULL; - - sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); - if(iter != mSharedMemoryRegions.end()) - { - result = iter->second->getMappedAddress(); - } - - return result; + void *result = NULL; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getMappedAddress(); + } + + return result; } std::string LLPluginProcessParent::getMessageClassVersion(const std::string &message_class) { - std::string result; - - if(mMessageClassVersions.has(message_class)) - { - result = mMessageClassVersions[message_class].asString(); - } - - return result; + std::string result; + + if(mMessageClassVersions.has(message_class)) + { + result = mMessageClassVersions[message_class].asString(); + } + + return result; } std::string LLPluginProcessParent::getPluginVersion(void) { - return mPluginVersionString; + return mPluginVersionString; } void LLPluginProcessParent::setState(EState state) { - LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; - mState = state; + LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; + mState = state; }; bool LLPluginProcessParent::pluginLockedUpOrQuit() { - bool result = false; - - if (! LLProcess::isRunning(mProcess)) - { - LL_WARNS("Plugin") << "child exited" << LL_ENDL; - result = true; - } - else if(pluginLockedUp()) - { - LL_WARNS("Plugin") << "timeout" << LL_ENDL; - result = true; - } - - return result; + bool result = false; + + if (! LLProcess::isRunning(mProcess)) + { + LL_WARNS("Plugin") << "child exited" << LL_ENDL; + result = true; + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout" << LL_ENDL; + result = true; + } + + return result; } bool LLPluginProcessParent::pluginLockedUp() { - if(mDisableTimeout || mDebug || mBlocked) - { - // Never time out a plugin process in these cases. - return false; - } - - // If the timer is running and has expired, the plugin has locked up. - return (mHeartbeat.getStarted() && mHeartbeat.hasExpired()); + if(mDisableTimeout || mDebug || mBlocked) + { + // Never time out a plugin process in these cases. + return false; + } + + // If the timer is running and has expired, the plugin has locked up. + return (mHeartbeat.getStarted() && mHeartbeat.hasExpired()); } diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 1893c9e657..1966e6b13c 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -1,4 +1,4 @@ -/** +/** * @file llpluginprocessparent.h * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -43,182 +43,182 @@ #include "llsd.h" #include "llevents.h" -class LLPluginProcessParentOwner : public boost::enable_shared_from_this < LLPluginProcessParentOwner > +class LLPluginProcessParentOwner : public std::enable_shared_from_this < LLPluginProcessParentOwner > { public: - virtual ~LLPluginProcessParentOwner(); - virtual void receivePluginMessage(const LLPluginMessage &message) = 0; - virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;}; - // This will only be called when the plugin has died unexpectedly - virtual void pluginLaunchFailed() {}; - virtual void pluginDied() {}; + virtual ~LLPluginProcessParentOwner(); + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;}; + // This will only be called when the plugin has died unexpectedly + virtual void pluginLaunchFailed() {}; + virtual void pluginDied() {}; }; class LLPluginProcessParent : public LLPluginMessagePipeOwner { - LOG_CLASS(LLPluginProcessParent); + LOG_CLASS(LLPluginProcessParent); LLPluginProcessParent(LLPluginProcessParentOwner *owner); public: - typedef boost::shared_ptr<LLPluginProcessParent> ptr_t; + typedef std::shared_ptr<LLPluginProcessParent> ptr_t; - ~LLPluginProcessParent(); - - void init(const std::string &launcher_filename, - const std::string &plugin_dir, - const std::string &plugin_filename, - bool debug); + ~LLPluginProcessParent(); + + void init(const std::string &launcher_filename, + const std::string &plugin_dir, + const std::string &plugin_filename, + bool debug); // Creates a process // returns true if process already exists or if created, // false if failed to create bool createPluginProcess(); - void idle(void); - - // returns true if the plugin is on its way to steady state - bool isLoading(void); + void idle(void); + + // returns true if the plugin is on its way to steady state + bool isLoading(void); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); - // returns true if the plugin is in the steady state (processing messages) - bool isRunning(void); + // returns true if the process has exited or we've had a fatal error + bool isDone(void); - // returns true if the process has exited or we've had a fatal error - bool isDone(void); - - // returns true if the process is currently waiting on a blocking request - bool isBlocked(void) { return mBlocked; }; - - void killSockets(void); - - // Go to the proper error state - void errorState(void); + // returns true if the process is currently waiting on a blocking request + bool isBlocked(void) { return mBlocked; }; - void setSleepTime(F64 sleep_time, bool force_send = false); - F64 getSleepTime(void) const { return mSleepTime; }; + void killSockets(void); - void sendMessage(const LLPluginMessage &message); - - void receiveMessage(const LLPluginMessage &message); + // Go to the proper error state + void errorState(void); + + void setSleepTime(F64 sleep_time, bool force_send = false); + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessage(const LLPluginMessage &message); + + void receiveMessage(const LLPluginMessage &message); static ptr_t create(LLPluginProcessParentOwner *owner); void requestShutdown(); - // Inherited from LLPluginMessagePipeOwner - /*virtual*/ void receiveMessageRaw(const std::string &message); - /*virtual*/ void receiveMessageEarly(const LLPluginMessage &message); - /*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ; - - // This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host. - // The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name. - std::string addSharedMemory(size_t size); - // Negotiates for the removal of a shared memory segment. It is the caller's responsibility to ensure that nothing touches the memory - // after this has been called, since the segment will be unmapped shortly thereafter. - void removeSharedMemory(const std::string &name); - size_t getSharedMemorySize(const std::string &name); - void *getSharedMemoryAddress(const std::string &name); - - // Returns the version string the plugin indicated for the message class, or an empty string if that class wasn't in the list. - std::string getMessageClassVersion(const std::string &message_class); - - std::string getPluginVersion(void); - - bool getDisableTimeout() { return mDisableTimeout; }; - void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; - - void setLaunchTimeout(F32 timeout) { mPluginLaunchTimeout = timeout; }; - void setLockupTimeout(F32 timeout) { mPluginLockupTimeout = timeout; }; - - F64 getCPUUsage() { return mCPUUsage; }; - - static void poll(F64 timeout); - static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); }; - static void setUseReadThread(bool use_read_thread); - static bool getUseReadThread() { return sUseReadThread; }; + // Inherited from LLPluginMessagePipeOwner + /*virtual*/ void receiveMessageRaw(const std::string &message); + /*virtual*/ void receiveMessageEarly(const LLPluginMessage &message); + /*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ; + + // This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host. + // The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name. + std::string addSharedMemory(size_t size); + // Negotiates for the removal of a shared memory segment. It is the caller's responsibility to ensure that nothing touches the memory + // after this has been called, since the segment will be unmapped shortly thereafter. + void removeSharedMemory(const std::string &name); + size_t getSharedMemorySize(const std::string &name); + void *getSharedMemoryAddress(const std::string &name); + + // Returns the version string the plugin indicated for the message class, or an empty string if that class wasn't in the list. + std::string getMessageClassVersion(const std::string &message_class); + + std::string getPluginVersion(void); + + bool getDisableTimeout() { return mDisableTimeout; }; + void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; + + void setLaunchTimeout(F32 timeout) { mPluginLaunchTimeout = timeout; }; + void setLockupTimeout(F32 timeout) { mPluginLockupTimeout = timeout; }; + + F64 getCPUUsage() { return mCPUUsage; }; + + static void poll(F64 timeout); + static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); }; + static void setUseReadThread(bool use_read_thread); + static bool getUseReadThread() { return sUseReadThread; }; static void shutdown(); private: typedef std::map<void *, ptr_t> mapInstances_t; - enum EState - { - STATE_UNINITIALIZED, - STATE_INITIALIZED, // init() has been called - STATE_LISTENING, // listening for incoming connection - STATE_LAUNCHED, // process has been launched - STATE_CONNECTED, // process has connected - STATE_HELLO, // first message from the plugin process has been received - STATE_LOADING, // process has been asked to load the plugin - STATE_RUNNING, // + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_LISTENING, // listening for incoming connection + STATE_LAUNCHED, // process has been launched + STATE_CONNECTED, // process has connected + STATE_HELLO, // first message from the plugin process has been received + STATE_LOADING, // process has been asked to load the plugin + STATE_RUNNING, // STATE_GOODBYE, - STATE_LAUNCH_FAILURE, // Failure before plugin loaded - STATE_ERROR, // generic bailout state - STATE_CLEANUP, // clean everything up - STATE_EXITING, // Tried to kill process, waiting for it to exit - STATE_DONE // + STATE_LAUNCH_FAILURE, // Failure before plugin loaded + STATE_ERROR, // generic bailout state + STATE_CLEANUP, // clean everything up + STATE_EXITING, // Tried to kill process, waiting for it to exit + STATE_DONE // - }; - EState mState; - void setState(EState state); + }; + EState mState; + void setState(EState state); bool wantsPolling() const; void removeFromProcessing(); - bool pluginLockedUp(); - bool pluginLockedUpOrQuit(); + bool pluginLockedUp(); + bool pluginLockedUpOrQuit(); - bool accept(); + bool accept(); void clearProcessCreationThread(); - LLSocket::ptr_t mListenSocket; - LLSocket::ptr_t mSocket; - U32 mBoundPort; - - LLProcess::Params mProcessParams; - LLProcessPtr mProcess; - LLThread *pProcessCreationThread; - - std::string mPluginFile; - std::string mPluginDir; - - LLPluginProcessParentOwner *mOwner; - - typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; - sharedMemoryRegionsType mSharedMemoryRegions; - - LLSD mMessageClassVersions; - std::string mPluginVersionString; - - LLTimer mHeartbeat; - F64 mSleepTime; - F64 mCPUUsage; - - bool mDisableTimeout; - bool mDebug; - bool mBlocked; - bool mPolledInput; - - LLProcessPtr mDebugger; - - F32 mPluginLaunchTimeout; // Somewhat longer timeout for initial launch. - F32 mPluginLockupTimeout; // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. - - static bool sUseReadThread; - apr_pollfd_t mPollFD; - static apr_pollset_t *sPollSet; - static bool sPollsetNeedsRebuild; - static LLMutex *sInstancesMutex; + LLSocket::ptr_t mListenSocket; + LLSocket::ptr_t mSocket; + U32 mBoundPort; + + LLProcess::Params mProcessParams; + LLProcessPtr mProcess; + LLThread *pProcessCreationThread; + + std::string mPluginFile; + std::string mPluginDir; + + LLPluginProcessParentOwner *mOwner; + + typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLSD mMessageClassVersions; + std::string mPluginVersionString; + + LLTimer mHeartbeat; + F64 mSleepTime; + F64 mCPUUsage; + + bool mDisableTimeout; + bool mDebug; + bool mBlocked; + bool mPolledInput; + + LLProcessPtr mDebugger; + + F32 mPluginLaunchTimeout; // Somewhat longer timeout for initial launch. + F32 mPluginLockupTimeout; // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. + + static bool sUseReadThread; + apr_pollfd_t mPollFD; + static apr_pollset_t *sPollSet; + static bool sPollsetNeedsRebuild; + static LLMutex *sInstancesMutex; static mapInstances_t sInstances; - static void dirtyPollSet(); - static void updatePollset(); - void servicePoll(); - static LLThread *sReadThread; + static void dirtyPollSet(); + static void updatePollset(); + void servicePoll(); + static LLThread *sReadThread; LLTempBoundListener mPolling; bool pollTick(); - LLMutex mIncomingQueueMutex; - std::queue<LLPluginMessage> mIncomingQueue; + LLMutex mIncomingQueueMutex; + std::queue<LLPluginMessage> mIncomingQueue; }; #endif // LL_LLPLUGINPROCESSPARENT_H diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp index 63ff5085c6..bfb551ff8d 100644 --- a/indra/llplugin/llpluginsharedmemory.cpp +++ b/indra/llplugin/llpluginsharedmemory.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginsharedmemory.cpp * LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -31,44 +31,44 @@ #include "llpluginsharedmemory.h" // on Mac and Linux, we use the native shm_open/mmap interface by using -// #define USE_SHM_OPEN_SHARED_MEMORY 1 +// #define USE_SHM_OPEN_SHARED_MEMORY 1 // in the appropriate sections below. // For Windows, use: -// #define USE_WIN32_SHARED_MEMORY 1 +// #define USE_WIN32_SHARED_MEMORY 1 // If we ever want to fall back to the apr implementation for a platform, use: -// #define USE_APR_SHARED_MEMORY 1 +// #define USE_APR_SHARED_MEMORY 1 #if LL_WINDOWS -// #define USE_APR_SHARED_MEMORY 1 - #define USE_WIN32_SHARED_MEMORY 1 +// #define USE_APR_SHARED_MEMORY 1 + #define USE_WIN32_SHARED_MEMORY 1 #elif LL_DARWIN - #define USE_SHM_OPEN_SHARED_MEMORY 1 + #define USE_SHM_OPEN_SHARED_MEMORY 1 #elif LL_LINUX - #define USE_SHM_OPEN_SHARED_MEMORY 1 + #define USE_SHM_OPEN_SHARED_MEMORY 1 #endif // FIXME: This path thing is evil and unacceptable. #if LL_WINDOWS - #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_" - // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista. - // Other options I've seen referenced are "Local\\" and "Session\\". - #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_" + #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_" + // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista. + // Other options I've seen referenced are "Local\\" and "Session\\". + #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_" #else - // mac and linux - #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_" - #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL" + // mac and linux + #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_" + #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL" #endif -#if USE_APR_SHARED_MEMORY - #include "llapr.h" - #include "apr_shm.h" +#if USE_APR_SHARED_MEMORY + #include "llapr.h" + #include "apr_shm.h" #elif USE_SHM_OPEN_SHARED_MEMORY - #include <sys/fcntl.h> - #include <sys/mman.h> - #include <errno.h> + #include <sys/fcntl.h> + #include <sys/mman.h> + #include <errno.h> #elif USE_WIN32_SHARED_MEMORY #include <windows.h> #endif // USE_APR_SHARED_MEMORY @@ -78,17 +78,17 @@ int LLPluginSharedMemory::sSegmentNumber = 0; std::string LLPluginSharedMemory::createName(void) { - std::stringstream newname; + std::stringstream newname; #if LL_WINDOWS - newname << GetCurrentProcessId(); + newname << GetCurrentProcessId(); #else // LL_WINDOWS - newname << getpid(); + newname << getpid(); #endif // LL_WINDOWS - - newname << "_" << sSegmentNumber++; - - return newname.str(); + + newname << "_" << sSegmentNumber++; + + return newname.str(); } /** @@ -98,15 +98,15 @@ std::string LLPluginSharedMemory::createName(void) class LLPluginSharedMemoryPlatformImpl { public: - LLPluginSharedMemoryPlatformImpl(); - ~LLPluginSharedMemoryPlatformImpl(); - + LLPluginSharedMemoryPlatformImpl(); + ~LLPluginSharedMemoryPlatformImpl(); + #if USE_APR_SHARED_MEMORY - apr_shm_t* mAprSharedMemory; + apr_shm_t* mAprSharedMemory; #elif USE_SHM_OPEN_SHARED_MEMORY - int mSharedMemoryFD; + int mSharedMemoryFD; #elif USE_WIN32_SHARED_MEMORY - HANDLE mMapFile; + HANDLE mMapFile; #endif }; @@ -116,11 +116,11 @@ public: */ LLPluginSharedMemory::LLPluginSharedMemory() { - mSize = 0; - mMappedAddress = NULL; - mNeedsDestroy = false; + mSize = 0; + mMappedAddress = NULL; + mNeedsDestroy = false; - mImpl = new LLPluginSharedMemoryPlatformImpl; + mImpl = new LLPluginSharedMemoryPlatformImpl; } /** @@ -128,14 +128,14 @@ LLPluginSharedMemory::LLPluginSharedMemory() */ LLPluginSharedMemory::~LLPluginSharedMemory() { - if(mNeedsDestroy) - destroy(); - else - detach(); - - unlink(); - - delete mImpl; + if(mNeedsDestroy) + destroy(); + else + detach(); + + unlink(); + + delete mImpl; } #if USE_APR_SHARED_MEMORY @@ -143,106 +143,106 @@ LLPluginSharedMemory::~LLPluginSharedMemory() LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() { - mAprSharedMemory = NULL; + mAprSharedMemory = NULL; } LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() { - + } bool LLPluginSharedMemory::map(void) { - mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory); - if(mMappedAddress == NULL) - { - return false; - } - - return true; + mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory); + if(mMappedAddress == NULL) + { + return false; + } + + return true; } bool LLPluginSharedMemory::unmap(void) { - // This is a no-op under apr. - return true; + // This is a no-op under apr. + return true; } bool LLPluginSharedMemory::close(void) { - // This is a no-op under apr. - return true; + // This is a no-op under apr. + return true; } bool LLPluginSharedMemory::unlink(void) { - // This is a no-op under apr. - return true; + // This is a no-op under apr. + return true; } bool LLPluginSharedMemory::create(size_t size) { - mName = APR_SHARED_MEMORY_PREFIX_STRING; - mName += createName(); - mSize = size; - - apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp ); - - if(ll_apr_warn_status(status)) - { - return false; - } + mName = APR_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp ); + + if(ll_apr_warn_status(status)) + { + return false; + } - mNeedsDestroy = true; - - return map(); + mNeedsDestroy = true; + + return map(); } bool LLPluginSharedMemory::destroy(void) { - if(mImpl->mAprSharedMemory) - { - apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory); - if(ll_apr_warn_status(status)) - { - // TODO: Is this a fatal error? I think not... - } - mImpl->mAprSharedMemory = NULL; - } - - return true; + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + + return true; } bool LLPluginSharedMemory::attach(const std::string &name, size_t size) { - mName = name; - mSize = size; - - apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp ); - - if(ll_apr_warn_status(status)) - { - return false; - } + mName = name; + mSize = size; + + apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp ); - return map(); + if(ll_apr_warn_status(status)) + { + return false; + } + + return map(); } bool LLPluginSharedMemory::detach(void) { - if(mImpl->mAprSharedMemory) - { - apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory); - if(ll_apr_warn_status(status)) - { - // TODO: Is this a fatal error? I think not... - } - mImpl->mAprSharedMemory = NULL; - } - - return true; + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + + return true; } @@ -251,7 +251,7 @@ bool LLPluginSharedMemory::detach(void) LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() { - mSharedMemoryFD = -1; + mSharedMemoryFD = -1; } LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() @@ -260,119 +260,119 @@ LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() bool LLPluginSharedMemory::map(void) { - mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0); - if(mMappedAddress == NULL) - { - return false; - } - - LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0); + if(mMappedAddress == NULL) + { + return false; + } - return true; + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; } bool LLPluginSharedMemory::unmap(void) { - if(mMappedAddress != NULL) - { - LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL; - if(::munmap(mMappedAddress, mSize) == -1) - { - // TODO: Is this a fatal error? I think not... - } - - mMappedAddress = NULL; - } + if(mMappedAddress != NULL) + { + LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL; + if(::munmap(mMappedAddress, mSize) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mMappedAddress = NULL; + } - return true; + return true; } bool LLPluginSharedMemory::close(void) { - if(mImpl->mSharedMemoryFD != -1) - { - LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL; - if(::close(mImpl->mSharedMemoryFD) == -1) - { - // TODO: Is this a fatal error? I think not... - } - - mImpl->mSharedMemoryFD = -1; - } - return true; + if(mImpl->mSharedMemoryFD != -1) + { + LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL; + if(::close(mImpl->mSharedMemoryFD) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mImpl->mSharedMemoryFD = -1; + } + return true; } bool LLPluginSharedMemory::unlink(void) { - if(!mName.empty()) - { - if(::shm_unlink(mName.c_str()) == -1) - { - return false; - } - } - - return true; + if(!mName.empty()) + { + if(::shm_unlink(mName.c_str()) == -1) + { + return false; + } + } + + return true; } bool LLPluginSharedMemory::create(size_t size) { - mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING; - mName += createName(); - mSize = size; - - // Preemptive unlink, just in case something didn't get cleaned up. - unlink(); - - mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - if(mImpl->mSharedMemoryFD == -1) - { - return false; - } - - mNeedsDestroy = true; - - if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1) - { - return false; - } - - - return map(); + mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + // Preemptive unlink, just in case something didn't get cleaned up. + unlink(); + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + mNeedsDestroy = true; + + if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1) + { + return false; + } + + + return map(); } bool LLPluginSharedMemory::destroy(void) { - unmap(); - close(); - - return true; + unmap(); + close(); + + return true; } bool LLPluginSharedMemory::attach(const std::string &name, size_t size) { - mName = name; - mSize = size; + mName = name; + mSize = size; + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + // unlink here so the segment will be cleaned up automatically after the last close. + unlink(); - mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); - if(mImpl->mSharedMemoryFD == -1) - { - return false; - } - - // unlink here so the segment will be cleaned up automatically after the last close. - unlink(); - - return map(); + return map(); } bool LLPluginSharedMemory::detach(void) { - unmap(); - close(); - return true; + unmap(); + close(); + return true; } #elif USE_WIN32_SHARED_MEMORY @@ -382,119 +382,119 @@ bool LLPluginSharedMemory::detach(void) LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() { - mMapFile = NULL; + mMapFile = NULL; } LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() { - + } bool LLPluginSharedMemory::map(void) { - mMappedAddress = MapViewOfFile( - mImpl->mMapFile, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - mSize); - - if(mMappedAddress == NULL) - { - LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL; - return false; - } - - LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + mMappedAddress = MapViewOfFile( + mImpl->mMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + mSize); + + if(mMappedAddress == NULL) + { + LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL; + return false; + } - return true; + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; } bool LLPluginSharedMemory::unmap(void) { - if(mMappedAddress != NULL) - { - UnmapViewOfFile(mMappedAddress); - mMappedAddress = NULL; - } + if(mMappedAddress != NULL) + { + UnmapViewOfFile(mMappedAddress); + mMappedAddress = NULL; + } - return true; + return true; } bool LLPluginSharedMemory::close(void) { - if(mImpl->mMapFile != NULL) - { - CloseHandle(mImpl->mMapFile); - mImpl->mMapFile = NULL; - } - - return true; + if(mImpl->mMapFile != NULL) + { + CloseHandle(mImpl->mMapFile); + mImpl->mMapFile = NULL; + } + + return true; } bool LLPluginSharedMemory::unlink(void) { - // This is a no-op on Windows. - return true; + // This is a no-op on Windows. + return true; } bool LLPluginSharedMemory::create(size_t size) { - mName = WIN32_SHARED_MEMORY_PREFIX_STRING; - mName += createName(); - mSize = size; + mName = WIN32_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + mImpl->mMapFile = CreateFileMappingA( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // max. object size + mSize, // buffer size + mName.c_str()); // name of mapping object - mImpl->mMapFile = CreateFileMappingA( - INVALID_HANDLE_VALUE, // use paging file - NULL, // default security - PAGE_READWRITE, // read/write access - 0, // max. object size - mSize, // buffer size - mName.c_str()); // name of mapping object + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } - if(mImpl->mMapFile == NULL) - { - LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL; - return false; - } + mNeedsDestroy = true; - mNeedsDestroy = true; - - return map(); + return map(); } bool LLPluginSharedMemory::destroy(void) { - unmap(); - close(); - return true; + unmap(); + close(); + return true; } bool LLPluginSharedMemory::attach(const std::string &name, size_t size) { - mName = name; - mSize = size; + mName = name; + mSize = size; + + mImpl->mMapFile = OpenFileMappingA( + FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + mName.c_str()); // name of mapping object + + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } - mImpl->mMapFile = OpenFileMappingA( - FILE_MAP_ALL_ACCESS, // read/write access - FALSE, // do not inherit the name - mName.c_str()); // name of mapping object - - if(mImpl->mMapFile == NULL) - { - LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL; - return false; - } - - return map(); + return map(); } bool LLPluginSharedMemory::detach(void) { - unmap(); - close(); - return true; + unmap(); + close(); + return true; } diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h index c6cd49cabb..a0aa885a58 100644 --- a/indra/llplugin/llpluginsharedmemory.h +++ b/indra/llplugin/llpluginsharedmemory.h @@ -1,25 +1,25 @@ -/** +/** * @file llpluginsharedmemory.h * * @cond * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -36,15 +36,15 @@ class LLPluginSharedMemoryPlatformImpl; */ class LLPluginSharedMemory { - LOG_CLASS(LLPluginSharedMemory); + LOG_CLASS(LLPluginSharedMemory); public: - LLPluginSharedMemory(); - ~LLPluginSharedMemory(); - - // Parent will use create/destroy, child will use attach/detach. - // Message transactions will ensure child attaches after parent creates and detaches before parent destroys. - - /** + LLPluginSharedMemory(); + ~LLPluginSharedMemory(); + + // Parent will use create/destroy, child will use attach/detach. + // Message transactions will ensure child attaches after parent creates and detaches before parent destroys. + + /** * Creates a shared memory segment, with a name which is guaranteed to be unique on the host at the current time. Used by parent. * Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys. * @@ -52,16 +52,16 @@ public: * * @return False for failure, true for success. */ - bool create(size_t size); - /** + bool create(size_t size); + /** * Destroys a shared memory segment. Used by parent. * Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys. * * @return True. TODO:DOC - always returns true. Is this the intended behavior? */ - bool destroy(void); - - /** + bool destroy(void); + + /** * Creates and attaches a name to a shared memory segment. TODO:DOC what's the difference between attach() and create()? * * @param[in] name Name to attach to memory segment @@ -69,55 +69,55 @@ public: * * @return False on failure, true otherwise. */ - bool attach(const std::string &name, size_t size); - /** + bool attach(const std::string &name, size_t size); + /** * Detaches shared memory segment. * * @return False on failure, true otherwise. */ - bool detach(void); + bool detach(void); - /** + /** * Checks if shared memory is mapped to a non-null address. * * @return True if memory address is non-null, false otherwise. */ - bool isMapped(void) const { return (mMappedAddress != NULL); }; - /** + bool isMapped(void) const { return (mMappedAddress != NULL); }; + /** * Get pointer to shared memory. * * @return Pointer to shared memory. */ - void *getMappedAddress(void) const { return mMappedAddress; }; - /** + void *getMappedAddress(void) const { return mMappedAddress; }; + /** * Get size of shared memory. * * @return Size of shared memory in bytes. TODO:DOC are bytes the correct unit? */ - size_t getSize(void) const { return mSize; }; - /** + size_t getSize(void) const { return mSize; }; + /** * Get name of shared memory. * * @return Name of shared memory. */ - std::string getName() const { return mName; }; - + std::string getName() const { return mName; }; + private: - bool map(void); - bool unmap(void); - bool close(void); - bool unlink(void); - - std::string mName; - size_t mSize; - void *mMappedAddress; - bool mNeedsDestroy; - - LLPluginSharedMemoryPlatformImpl *mImpl; - - static int sSegmentNumber; - static std::string createName(); - + bool map(void); + bool unmap(void); + bool close(void); + bool unlink(void); + + std::string mName; + size_t mSize; + void *mMappedAddress; + bool mNeedsDestroy; + + LLPluginSharedMemoryPlatformImpl *mImpl; + + static int sSegmentNumber; + static std::string createName(); + }; diff --git a/indra/llplugin/slplugin/slplugin-objc.h b/indra/llplugin/slplugin/slplugin-objc.h index af0ebe1af2..b2e5c16ff0 100644 --- a/indra/llplugin/slplugin/slplugin-objc.h +++ b/indra/llplugin/slplugin/slplugin-objc.h @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @@ -37,7 +37,7 @@ class NSWindow; class LLCocoaPlugin { -public: +public: LLCocoaPlugin(); void setupCocoa(); void createAutoReleasePool(); diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 5c54705c71..f2925a1fa1 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @@ -43,49 +43,49 @@ using namespace std; #if LL_DARWIN - #include "slplugin-objc.h" + #include "slplugin-objc.h" #endif #if LL_DARWIN || LL_LINUX - #include <signal.h> + #include <signal.h> #endif /* - On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist. + On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist. + + Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags: - Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags: + -sectcreate __TEXT __info_plist /path/to/slplugin_info.plist - -sectcreate __TEXT __info_plist /path/to/slplugin_info.plist + which means adding this to the gcc flags: - which means adding this to the gcc flags: + -Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist - -Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist - - Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity. + Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity. */ #if LL_DARWIN || LL_LINUX // Signal handlers to make crashes not show an OS dialog... static void crash_handler(int sig) { - // Just exit cleanly. - // TODO: add our own crash reporting - _exit(1); + // Just exit cleanly. + // TODO: add our own crash reporting + _exit(1); } #endif #if LL_WINDOWS #include <windows.h> //////////////////////////////////////////////////////////////////////////////// -// Our exception handler - will probably just exit and the host application -// will miss the heartbeat and log the error in the usual fashion. +// Our exception handler - will probably just exit and the host application +// will miss the heartbeat and log the error in the usual fashion. LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop ) { - //std::cerr << "This plugin (" << __FILE__ << ") - "; - //std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl; + //std::cerr << "This plugin (" << __FILE__ << ") - "; + //std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl; - // TODO: replace exception handler before we exit? - return EXCEPTION_EXECUTE_HANDLER; + // TODO: replace exception handler before we exit? + return EXCEPTION_EXECUTE_HANDLER; } // Taken from : http://blog.kalmbachnet.de/?postid=75 @@ -93,56 +93,56 @@ LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop // even with the other exception handling code. This (terrifying) piece of code // patches things so that doesn't happen. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( - LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) + LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) { - return NULL; + return NULL; } BOOL PreventSetUnhandledExceptionFilter() { - // remove the scary stuff that also isn't supported on 64 bit Windows - return TRUE; + // remove the scary stuff that also isn't supported on 64 bit Windows + return TRUE; } //////////////////////////////////////////////////////////////////////////////// -// Hook our exception handler and replace the system one +// Hook our exception handler and replace the system one void initExceptionHandler() { - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - // save old exception handler in case we need to restore it at the end - prev_filter = SetUnhandledExceptionFilter( myWin32ExceptionHandler ); - PreventSetUnhandledExceptionFilter(); + // save old exception handler in case we need to restore it at the end + prev_filter = SetUnhandledExceptionFilter( myWin32ExceptionHandler ); + PreventSetUnhandledExceptionFilter(); } bool checkExceptionHandler() { - bool ok = true; - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - prev_filter = SetUnhandledExceptionFilter(myWin32ExceptionHandler); - - PreventSetUnhandledExceptionFilter(); - - if (prev_filter != myWin32ExceptionHandler) - { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with " << prev_filter << "!" << LL_ENDL; - ok = false; - } - - if (prev_filter == NULL) - { - ok = FALSE; - if (NULL == myWin32ExceptionHandler) - { - LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; - } - else - { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with NULL!" << LL_ENDL; - } - } - - return ok; + bool ok = true; + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + prev_filter = SetUnhandledExceptionFilter(myWin32ExceptionHandler); + + PreventSetUnhandledExceptionFilter(); + + if (prev_filter != myWin32ExceptionHandler) + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with " << prev_filter << "!" << LL_ENDL; + ok = false; + } + + if (prev_filter == NULL) + { + ok = FALSE; + if (NULL == myWin32ExceptionHandler) + { + LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; + } + else + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with NULL!" << LL_ENDL; + } + } + + return ok; } #endif @@ -156,132 +156,132 @@ int main(int argc, char **argv) #endif { - ll_init_apr(); + ll_init_apr(); - // Set up llerror logging - { - LLError::initForApplication(".","."); - LLError::setDefaultLevel(LLError::LEVEL_INFO); -// LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); -// LLError::logToFile("slplugin.log"); - } + // Set up llerror logging + { + LLError::initForApplication(".","."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); +// LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); +// LLError::logToFile("slplugin.log"); + } #if LL_WINDOWS - if( strlen( lpCmdLine ) == 0 ) - { - LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; - }; - - U32 port = 0; - if(!LLStringUtil::convertToU32(lpCmdLine, port)) - { - LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; - }; - - // Insert our exception handler into the system so this plugin doesn't - // display a crash message if something bad happens. The host app will - // see the missing heartbeat and log appropriately. - initExceptionHandler(); + if( strlen( lpCmdLine ) == 0 ) + { + LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; + }; + + U32 port = 0; + if(!LLStringUtil::convertToU32(lpCmdLine, port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + }; + + // Insert our exception handler into the system so this plugin doesn't + // display a crash message if something bad happens. The host app will + // see the missing heartbeat and log appropriately. + initExceptionHandler(); #elif LL_DARWIN || LL_LINUX - if(argc < 2) - { - LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; - } - - U32 port = 0; - if(!LLStringUtil::convertToU32(argv[1], port)) - { - LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; - } - - // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. - signal(SIGILL, &crash_handler); // illegal instruction - signal(SIGFPE, &crash_handler); // floating-point exception - signal(SIGBUS, &crash_handler); // bus error - signal(SIGSEGV, &crash_handler); // segmentation violation - signal(SIGSYS, &crash_handler); // non-existent system call invoked + if(argc < 2) + { + LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; + } + + U32 port = 0; + if(!LLStringUtil::convertToU32(argv[1], port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + } + + // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. + signal(SIGILL, &crash_handler); // illegal instruction + signal(SIGFPE, &crash_handler); // floating-point exception + signal(SIGBUS, &crash_handler); // bus error + signal(SIGSEGV, &crash_handler); // segmentation violation + signal(SIGSYS, &crash_handler); // non-existent system call invoked #endif # if LL_DARWIN - signal(SIGEMT, &crash_handler); // emulate instruction executed + signal(SIGEMT, &crash_handler); // emulate instruction executed LLCocoaPlugin cocoa_interface; - cocoa_interface.setupCocoa(); - cocoa_interface.createAutoReleasePool(); + cocoa_interface.setupCocoa(); + cocoa_interface.createAutoReleasePool(); #endif //LL_DARWIN - LLPluginProcessChild *plugin = new LLPluginProcessChild(); + LLPluginProcessChild *plugin = new LLPluginProcessChild(); - plugin->init(port); + plugin->init(port); #if LL_DARWIN cocoa_interface.deleteAutoReleasePool(); #endif - LLTimer timer; - timer.start(); + LLTimer timer; + timer.start(); #if LL_WINDOWS - checkExceptionHandler(); + checkExceptionHandler(); #endif #if LL_DARWIN - - // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground. - // Use this to track the current frontmost window and bring this process to the front if it changes. + + // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground. + // Use this to track the current frontmost window and bring this process to the front if it changes. // cocoa_interface.mEventTarget = GetEventDispatcherTarget(); #endif - while(!plugin->isDone()) - { + while(!plugin->isDone()) + { #if LL_DARWIN - cocoa_interface.createAutoReleasePool(); + cocoa_interface.createAutoReleasePool(); #endif - timer.reset(); - plugin->idle(); + timer.reset(); + plugin->idle(); #if LL_DARWIN - { - cocoa_interface.processEvents(); + { + cocoa_interface.processEvents(); } #endif - F64 elapsed = timer.getElapsedTimeF64(); - F64 remaining = plugin->getSleepTime() - elapsed; - - if(remaining <= 0.0f) - { - // We've already used our full allotment. -// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; - - // Still need to service the network... - plugin->pump(); - } - else - { - -// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; -// timer.reset(); - - // This also services the network as needed. - plugin->sleep(remaining); - -// LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; - } - - + F64 elapsed = timer.getElapsedTimeF64(); + F64 remaining = plugin->getSleepTime() - elapsed; + + if(remaining <= 0.0f) + { + // We've already used our full allotment. +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; + + // Still need to service the network... + plugin->pump(); + } + else + { + +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; +// timer.reset(); + + // This also services the network as needed. + plugin->sleep(remaining); + +// LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; + } + + #if LL_WINDOWS - // More agressive checking of interfering exception handlers. - // Doesn't appear to be required so far - even for plugins - // that do crash with a single call to the intercept - // exception handler such as QuickTime. - //checkExceptionHandler(); + // More agressive checking of interfering exception handlers. + // Doesn't appear to be required so far - even for plugins + // that do crash with a single call to the intercept + // exception handler such as QuickTime. + //checkExceptionHandler(); #endif #if LL_DARWIN - cocoa_interface.deleteAutoReleasePool(); + cocoa_interface.deleteAutoReleasePool(); #endif - } - delete plugin; + } + delete plugin; - ll_cleanup_apr(); + ll_cleanup_apr(); - return 0; + return 0; } |