diff options
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;  } | 
