diff options
| author | Bryan O'Sullivan <bos@lindenlab.com> | 2009-07-24 15:39:56 -0700 | 
|---|---|---|
| committer | Bryan O'Sullivan <bos@lindenlab.com> | 2009-07-24 15:39:56 -0700 | 
| commit | b47dbc2acadb1fa478daf89dbc3d54225c6e4629 (patch) | |
| tree | 9bc0cbf4795e1ebdfcb80848fea8ffe092b4983d /indra | |
| parent | 9c394b3aaecacc9a70354c544bd728a4f4f966d2 (diff) | |
| parent | 90e25f6ba80b773117582d6a392037ac274fff39 (diff) | |
Merge with an oldish change of mine
Diffstat (limited to 'indra')
51 files changed, 979 insertions, 307 deletions
| diff --git a/indra/cmake/GoogleMock.cmake b/indra/cmake/GoogleMock.cmake new file mode 100644 index 0000000000..ca5a8034ba --- /dev/null +++ b/indra/cmake/GoogleMock.cmake @@ -0,0 +1,27 @@ +# -*- cmake -*- +include(Prebuilt) +include(Linking) + +use_prebuilt_binary(googlemock) + +set(GOOGLEMOCK_INCLUDE_DIRS  +    ${LIBS_PREBUILT_DIR}/include) + +if (LINUX) +    set(GOOGLEMOCK_LIBRARIES  +        gmock   +        gtest) +elseif(WINDOWS) +    set(GOOGLEMOCK_LIBRARIES  +        gmock) +    set(GOOGLEMOCK_INCLUDE_DIRS  +        ${LIBS_PREBUILT_DIR}/include +        ${LIBS_PREBUILT_DIR}/include/gmock +        ${LIBS_PREBUILT_DIR}/include/gmock/boost/tr1/tr1) +elseif(DARWIN) +    set(GOOGLEMOCK_LIBRARIES +        gmock +        gtest) +endif(LINUX) + + diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 4a61725e09..4da0824120 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -13,6 +13,8 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)    #    # WARNING: do NOT modify this code without working with poppy or daveh -    # there is another branch that will conflict heavily with any changes here. +INCLUDE(GoogleMock) +    IF(LL_TEST_VERBOSE)      MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}") @@ -32,8 +34,10 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)      ${LLMATH_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LIBS_OPEN_DIR}/test +    ${GOOGLEMOCK_INCLUDE_DIRS}      )    SET(alltest_LIBRARIES +    ${GOOGLEMOCK_LIBRARIES}      ${PTHREAD_LIBRARY}      ${WINDOWS_LIBRARIES}      ) @@ -42,6 +46,11 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)      ${CMAKE_SOURCE_DIR}/test/test.h      ) +  # Use the default flags +  if (LINUX) +    SET(CMAKE_EXE_LINKER_FLAGS "") +  endif (LINUX) +    # start the source test executable definitions    SET(${project}_TEST_OUTPUT "")    FOREACH (source ${sources}) @@ -84,9 +93,9 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)        MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")      ENDIF(LL_TEST_VERBOSE) +      # Setup target      ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES}) -      #      # Per-codefile additional / external project dep and lib dep property extraction      # diff --git a/indra/develop.py b/indra/develop.py index 1d7ac42c9c..b40e81bb07 100755 --- a/indra/develop.py +++ b/indra/develop.py @@ -451,9 +451,7 @@ class DarwinSetup(UnixSetup):              targets = ' '.join(['-target ' + repr(t) for t in targets])          else:              targets = '' -        # cmd = ('xcodebuild -parallelizeTargets ' # parallelizeTargets is suspected of non-deterministic build failures. + poppy 2009-06-05 -        cmd = ('xcodebuild ' -               '-configuration %s %s %s' % +        cmd = ('xcodebuild -configuration %s %s %s' %                 (self.build_type, ' '.join(opts), targets))          for d in self.build_dirs():              try: diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py index 1190d88663..4527b115f9 100644 --- a/indra/lib/python/indra/base/llsd.py +++ b/indra/lib/python/indra/base/llsd.py @@ -238,7 +238,7 @@ class LLSDXMLFormatter(object):      def MAP(self, v):          return self.elt(              'map', -            ''.join(["%s%s" % (self.elt('key', key), self.generate(value)) +            ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value))               for key, value in v.items()]))      typeof = type diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py index c4c40739ec..7e0e115d14 100644 --- a/indra/lib/python/indra/util/llsubprocess.py +++ b/indra/lib/python/indra/util/llsubprocess.py @@ -90,6 +90,17 @@ all the output, and get the result.                      child.tochild.close()          result = child.poll()          if result != -1: +            # At this point, the child process has exited and result +            # is the return value from the process. Between the time +            # we called select() and poll() the process may have +            # exited so read all the data left on the child process +            # stdout and stderr. +            last = child.fromchild.read() +            if last: +                out.append(last) +            last = child.childerr.read() +            if last: +                err.append(last)              child.tochild.close()              child.fromchild.close()              child.childerr.close() diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py index 693b483f79..5c19368240 100644 --- a/indra/lib/python/indra/util/named_query.py +++ b/indra/lib/python/indra/util/named_query.py @@ -48,8 +48,8 @@ from indra.base import llsd  from indra.base import config  DEBUG = False -NQ_FILE_SUFFIX = None -NQ_FILE_SUFFIX_LEN = None +NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') +NQ_FILE_SUFFIX_LEN  = len(NQ_FILE_SUFFIX)  _g_named_manager = None diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index 1d42298f4d..1ae0ddeea0 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -190,7 +190,7 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask)  	if (dot(mPelvisState->getJoint()->getWorldRotation(), mLastGoodPelvisRotation) < ROTATION_THRESHOLD)  	{  		mLastGoodPelvisRotation = mPelvisState->getJoint()->getWorldRotation(); -		mLastGoodPelvisRotation.normQuat(); +		mLastGoodPelvisRotation.normalize();  		mTrackAnkles = TRUE;  	}  	else if ((mCharacter->getCharacterPosition() - mLastGoodPosition).magVecSquared() > POSITION_THRESHOLD) diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 873f50a65e..7544ab1d11 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -118,6 +118,63 @@ public:  		THROTTLE_BLOCKED,		// rate exceed, block key  	}; +	F64 getActionCount(const T& id) +	{ +		U64 now = 0; +		if ( mIsRealtime ) +		{ +			now = LLKeyThrottleImpl<T>::getTime(); +		} +		else +		{ +			now = LLKeyThrottleImpl<T>::getFrame(); +		} + +		if (now >= (m.startTime + m.intervalLength)) +		{ +			if (now < (m.startTime + 2 * m.intervalLength)) +			{ +				// prune old data +				delete m.prevMap; +				m.prevMap = m.currMap; +				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + +				m.startTime += m.intervalLength; +			} +			else +			{ +				// lots of time has passed, all data is stale +				delete m.prevMap; +				delete m.currMap; +				m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; +				m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + +				m.startTime = now; +			} +		} + +		U32 prevCount = 0; + +		typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); +		if (prev != m.prevMap->end()) +		{ +			prevCount = prev->second.count; +		} + +		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + +		// curr.count is the number of keys in +		// this current 'time slice' from the beginning of it until now +		// prevCount is the number of keys in the previous +		// time slice scaled to be one full time slice back from the current  +		// (now) time. + +		// compute current, windowed rate +		F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); +		F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); +		return averageCount; +	} +  	// call each time the key wants use  	State noteAction(const T& id, S32 weight = 1)  	{ diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 291b019616..e650f911b7 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -43,7 +43,7 @@  // statics -BOOL            LLPerfBlock::sStatsEnabled = FALSE;    // Flag for detailed information +S32	            LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS;       // Control what is being recorded  LLPerfBlock::stat_map_t    LLPerfBlock::sStatMap;    // Map full path string to LLStatTime objects, tracks all active objects  std::string        LLPerfBlock::sCurrentStatPath = "";    // Something like "/total_time/physics/physics step" @@ -129,6 +129,7 @@ bool LLStatsConfigFile::loadFile()      F32 duration = 0.f;      F32 interval = 0.f; +	S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;      const char * w = "duration";      if (stats_config.has(w)) @@ -140,8 +141,18 @@ bool LLStatsConfigFile::loadFile()      {          interval = (F32)stats_config[w].asReal();      }  +    w = "flags"; +    if (stats_config.has(w)) +    { +		flags = (S32)stats_config[w].asInteger(); +		if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS && +			duration > 0) +		{   // No flags passed in, but have a duration, so reset to basic stats +			flags = LLPerfBlock::LLSTATS_BASIC_STATS; +		} +    }  -    mStatsp->setReportPerformanceDuration( duration ); +    mStatsp->setReportPerformanceDuration( duration, flags );      mStatsp->setReportPerformanceInterval( interval );      if ( duration > 0 ) @@ -253,13 +264,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()      }  } -// Set length of performance stat recording -void    LLPerfStats::setReportPerformanceDuration( F32 seconds ) +// Set length of performance stat recording.   +// If turning stats on, caller must provide flags +void    LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )  {   	if ( seconds <= 0.f )  	{  		mReportPerformanceStatEnd = 0.0; -		LLPerfBlock::setStatsEnabled( FALSE ); +		LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS);		// Make sure all recording is off  		mFrameStatsFile.close();  		LLPerfBlock::clearDynamicStats();  	} @@ -268,8 +280,8 @@ void    LLPerfStats::setReportPerformanceDuration( F32 seconds )  		mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);  		// Clear failure flag to try and create the log file once  		mFrameStatsFileFailure = FALSE; -		LLPerfBlock::setStatsEnabled( TRUE );  		mSkipFirstFrameStats = TRUE;		// Skip the first report (at the end of this frame) +		LLPerfBlock::setStatsFlags(flags);  	}  } @@ -611,11 +623,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta      }  } -// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key. -// These are also turned on or off via the switch passed in -LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL) +// Use this constructor for normal, optional LLPerfBlock time slices +LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)  { -    if (!sStatsEnabled) return; +    if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0) +	{	// These are off unless the base set is enabled +		return; +	} + +	initDynamicStat(key); +} + +	 +// Use this constructor for dynamically created LLPerfBlock time slices +// that are only enabled by specific control flags +LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL) +{ +    if ((sStatsFlags & flags) == 0) +	{ +		return; +	}      if (NULL == key2 || strlen(key2) == 0)      { @@ -629,10 +656,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat      }  } +// Set up the result data map if dynamic stats are enabled  void LLPerfBlock::initDynamicStat(const std::string& key)  {      // Early exit if dynamic stats aren't enabled. -    if (!sStatsEnabled) return; +    if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)  +		return;      mLastPath = sCurrentStatPath;		// Save and restore current path      sCurrentStatPath += "/" + key;		// Add key to current path diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 61aaac45bf..e2e904bb06 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -192,14 +192,23 @@ public:  	// Use this constructor for pre-defined LLStatTime objects  	LLPerfBlock(LLStatTime* stat); -	// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key -	LLPerfBlock( const char* key1, const char* key2 = NULL); +	// Use this constructor for normal, optional LLPerfBlock time slices +	LLPerfBlock( const char* key ); +	// Use this constructor for dynamically created LLPerfBlock time slices +	// that are only enabled by specific control flags +	LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );  	~LLPerfBlock(); -	static void setStatsEnabled( BOOL enable )		{ sStatsEnabled = enable;	}; -	static S32  getStatsEnabled()					{ return sStatsEnabled;		}; +	enum +	{	// Stats bitfield flags +		LLSTATS_NO_OPTIONAL_STATS	= 0x00,		// No optional stats gathering, just pre-defined LLStatTime objects +		LLSTATS_BASIC_STATS			= 0x01,		// Gather basic optional runtime stats +		LLSTATS_SCRIPT_FUNCTIONS	= 0x02,		// Include LSL function calls +	}; +	static void setStatsFlags( S32 flags )	{ sStatsFlags = flags;	}; +	static S32  getStatsFlags()				{ return sStatsFlags;	};  	static void clearDynamicStats();		// Reset maps to clear out dynamic objects  	static void addStatsToLLSDandReset( LLSD & stats,		// Get current information and clear time bin @@ -213,7 +222,7 @@ private:  	LLStatTime * 			mPredefinedStat;		// LLStatTime object to get data  	StatEntry *				mDynamicStat;   		// StatEntryobject to get data -	static BOOL				sStatsEnabled;			// Normally FALSE +	static S32				sStatsFlags;			// Control what is being recorded      static stat_map_t		sStatMap;				// Map full path string to LLStatTime objects  	static std::string		sCurrentStatPath;		// Something like "frame/physics/physics step"  }; @@ -236,7 +245,7 @@ public:      BOOL    frameStatsIsRunning()                                { return (mReportPerformanceStatEnd > 0.);        };      F32     getReportPerformanceInterval() const                { return mReportPerformanceStatInterval;        };      void    setReportPerformanceInterval( F32 interval )        { mReportPerformanceStatInterval = interval;    }; -    void    setReportPerformanceDuration( F32 seconds ); +    void    setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );      void    setProcessName(const std::string& process_name) { mProcessName = process_name; }      void    setProcessPID(S32 process_pid) { mProcessPID = process_pid; } diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 1b93c21982..900652d06d 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -178,8 +178,8 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),  							mMaxBytes(0),  							mRawDiscardLevel(-1),  							mRate(0.0f), -							mReversible(FALSE) -	 +							mReversible(FALSE), +							mAreaUsedForDataSizeCalcs(0)  {  	//We assume here that if we wanted to create via  	//a dynamic library that the approriate open calls were made @@ -195,6 +195,12 @@ LLImageJ2C::LLImageJ2C() : 	LLImageFormatted(IMG_CODEC_J2C),  	}  	mImpl = j2cimpl_create_func(); + +	// Clear data size table +	for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) +	{	// Array size is MAX_DISCARD_LEVEL+1 +		mDataSizes[i] = 0; +	}  }  // virtual @@ -367,9 +373,45 @@ S32 LLImageJ2C::calcHeaderSize()  	return calcHeaderSizeJ2C();  } + +// calcDataSize() returns how many bytes to read  +// to load discard_level (including header and higher discard levels)  S32 LLImageJ2C::calcDataSize(S32 discard_level)  { -	return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); +	discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); + +	if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth())  +		|| mDataSizes[0] == 0) +	{ +		mAreaUsedForDataSizeCalcs = getHeight() * getWidth(); +		 +		S32 level = MAX_DISCARD_LEVEL;	// Start at the highest discard +		while ( level >= 0 ) +		{ +			mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); +			level--; +		} + +		/* This is technically a more correct way to calculate the size required +		   for each discard level, since they should include the size needed for +		   lower levels.   Unfortunately, this doesn't work well and will lead to  +		   download stalls.  The true correct way is to parse the header.  This will +		   all go away with http textures at some point. + +		// Calculate the size for each discard level.   Lower levels (higher quality) +		// contain the cumulative size of higher levels		 +		S32 total_size = calcHeaderSizeJ2C(); + +		S32 level = MAX_DISCARD_LEVEL;	// Start at the highest discard +		while ( level >= 0 ) +		{	// Add in this discard level and all before it +			total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); +			mDataSizes[level] = total_size; +			level--; +		} +		*/ +	} +	return mDataSizes[discard_level];  }  S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 23f6ef5fd1..55df7f4429 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -87,6 +87,10 @@ protected:  	void updateRawDiscardLevel();  	S32 mMaxBytes; // Maximum number of bytes of data to use... +	 +	S32 mDataSizes[MAX_DISCARD_LEVEL+1];		// Size of data required to reach a given level +	U32 mAreaUsedForDataSizeCalcs;				// Height * width used to calculate mDataSizes +  	S8  mRawDiscardLevel;  	F32 mRate;  	BOOL mReversible; diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index 328ed4588b..2a27f3fc8d 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -277,6 +277,17 @@ BOOL LLPermissions::setOwnerAndGroup(  	return allowed;  } +//Fix for DEV-33917, last owner isn't used much and has little impact on +//permissions so it's reasonably safe to do this, however, for now,  +//limiting the functionality of this routine to objects which are  +//group owned. +void LLPermissions::setLastOwner(const LLUUID& last_owner) +{ +	if (isGroupOwned()) +		mLastOwner = last_owner; +} + +   // only call this if you know what you're doing  // there are usually perm-bit consequences when the   // ownerhsip changes diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index 5587f8c3c8..9280629e0c 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -229,6 +229,10 @@ public:  	// ownerhsip changes  	void yesReallySetOwner(const LLUUID& owner, bool group_owned); +	// Last owner doesn't have much in the way of permissions so it's  +	//not too dangerous to do this.  +	void setLastOwner(const LLUUID& last_owner); +  	// saves last owner, sets owner to uuid null, sets group  	// owned. group_id must be the group of the object (that's who it  	// is being deeded to) and the object must be group diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index cfd6183ec4..fdcc19d657 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -121,7 +121,7 @@ void	LLQuaternion::quantize16(F32 lower, F32 upper)  	mQ[VZ] = z;  	mQ[VS] = s; -	normQuat(); +	normalize();  }  void	LLQuaternion::quantize8(F32 lower, F32 upper) @@ -131,7 +131,7 @@ void	LLQuaternion::quantize8(F32 lower, F32 upper)  	mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper);  	mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper); -	normQuat(); +	normalize();  }  // LLVector3 Magnitude and Normalization Functions @@ -346,7 +346,7 @@ const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix4 &mat)  //    mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ);  //#endif  // -//	normQuat(); +//	normalize();  //	return (*this);  } diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 5db9c5be2e..0769f29f23 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -469,20 +469,30 @@ inline const LLQuaternion&	operator*=(LLQuaternion &a, const LLQuaternion &b)  	return a;  } +const F32 ONE_PART_IN_A_MILLION = 0.000001f; +  inline F32	LLQuaternion::normalize()  {  	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);  	if (mag > FP_MAG_THRESHOLD)  	{ -		F32 oomag = 1.f/mag; -		mQ[VX] *= oomag; -		mQ[VY] *= oomag; -		mQ[VZ] *= oomag; -		mQ[VS] *= oomag; +		// Floating point error can prevent some quaternions from achieving +		// exact unity length.  When trying to renormalize such quaternions we +		// can oscillate between multiple quantized states.  To prevent such +		// drifts we only renomalize if the length is far enough from unity. +		if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) +		{ +			F32 oomag = 1.f/mag; +			mQ[VX] *= oomag; +			mQ[VY] *= oomag; +			mQ[VZ] *= oomag; +			mQ[VS] *= oomag; +		}  	}  	else  	{ +		// we were given a very bad quaternion so we set it to identity  		mQ[VX] = 0.f;  		mQ[VY] = 0.f;  		mQ[VZ] = 0.f; @@ -499,11 +509,15 @@ inline F32	LLQuaternion::normQuat()  	if (mag > FP_MAG_THRESHOLD)  	{ -		F32 oomag = 1.f/mag; -		mQ[VX] *= oomag; -		mQ[VY] *= oomag; -		mQ[VZ] *= oomag; -		mQ[VS] *= oomag; +		if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) +		{ +			// only renormalize if length not close enough to 1.0 already +			F32 oomag = 1.f/mag; +			mQ[VX] *= oomag; +			mQ[VY] *= oomag; +			mQ[VZ] *= oomag; +			mQ[VS] *= oomag; +		}  	}  	else  	{ diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 88f83ba78e..81e518cf6e 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -221,6 +221,7 @@ IF (NOT LINUX AND VIEWER)        # llhttpclientadapter.cpp        lltrustedmessageservice.cpp        lltemplatemessagedispatcher.cpp +      llregionpresenceverifier.cpp        )      LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") @@ -228,3 +229,4 @@ IF (NOT LINUX AND VIEWER)      # Don't make llmessage depend on llsdmessage_test because ADD_COMM_BUILD_TEST depends on llmessage!      # ADD_COMM_BUILD_TEST(llsdmessage "" "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py")  ENDIF (NOT LINUX AND VIEWER) + diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 799bc83e20..82186fc503 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -76,11 +76,13 @@ public:  	LLCacheNameEntry();  public: -	bool mIsGroup; -	U32 mCreateTime;	// unix time_t -	std::string mFirstName; -	std::string mLastName; -	std::string mGroupName; +	bool isUnknown()			{ return (mFirstName.empty() +										  || mFirstName == std::string("(???)"));	}; + +	bool mIsGroup;				// true if this is a group ID/name +	U32 mCreateTime;			// unix time_t +	std::string mFirstName;		// Doubles as the group name +	std::string mLastName;		// Will be "" for groups  };  LLCacheNameEntry::LLCacheNameEntry() @@ -162,7 +164,7 @@ void ReplySender::send(const LLUUID& id,  	mMsg->addUUIDFast(_PREHASH_ID, id);  	if(mCurrIsGroup)  	{ -		mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName); +		mMsg->addStringFast(_PREHASH_GroupName, entry.mFirstName);  	}  	else  	{ @@ -222,6 +224,7 @@ public:  	void processPendingReplies();  	void sendRequest(const char* msg_name, const AskQueue& queue);  	bool isRequestPending(const LLUUID& id); +	void makeNameRequestForID(const LLUUID& id, bool isGroup, LLHost & fromHost);  	// Message system callbacks.  	void processUUIDRequest(LLMessageSystem* msg, bool isGroup); @@ -389,6 +392,7 @@ void LLCacheName::importFile(LLFILE* fp)  		entry->mCreateTime = create_time;  		entry->mFirstName = firstname;  		entry->mLastName = lastname; +		//llinfos << "Adding entry from file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl;  		impl.mCache[id] = entry;  		count++; @@ -425,6 +429,7 @@ bool LLCacheName::importFile(std::istream& istr)  		entry->mCreateTime = ctime;  		entry->mFirstName = agent[FIRST].asString();  		entry->mLastName = agent[LAST].asString(); +		//llinfos << "Adding name entry from XML file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl;  		impl.mCache[id] = entry;  		++count; @@ -445,7 +450,9 @@ bool LLCacheName::importFile(std::istream& istr)  		LLCacheNameEntry* entry = new LLCacheNameEntry();  		entry->mIsGroup = true;  		entry->mCreateTime = ctime; -		entry->mGroupName = group[NAME].asString(); +		entry->mFirstName = group[NAME].asString(); +		entry->mLastName = ""; +		//llinfos << "Adding group entry from XML file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl;  		impl.mCache[id] = entry;  		++count;  	} @@ -463,32 +470,32 @@ void LLCacheName::exportFile(std::ostream& ostr)  		// Only write entries for which we have valid data.  		LLCacheNameEntry* entry = iter->second;  		if(!entry -		   || (std::string::npos != entry->mFirstName.find('?')) -		   || (std::string::npos != entry->mGroupName.find('?'))) -		{ +		   || entry->isUnknown()) +		{	// No entry, or user or group name is unknown  			continue;  		}  		// store it  		LLUUID id = iter->first;  		std::string id_str = id.asString(); -		if(!entry->mFirstName.empty() && !entry->mLastName.empty()) -		{ +		if(entry->mIsGroup) +		{	// Save group name and ID +			data[GROUPS][id_str][NAME] = entry->mFirstName; +			data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; +		} +		else if(!entry->mLastName.empty()) +		{	// Save user names and ID  			data[AGENTS][id_str][FIRST] = entry->mFirstName;  			data[AGENTS][id_str][LAST] = entry->mLastName;  			data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime;  		} -		else if(entry->mIsGroup && !entry->mGroupName.empty()) -		{ -			data[GROUPS][id_str][NAME] = entry->mGroupName; -			data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; -		}  	}  	LLSDSerialize::toPrettyXML(data, ostr);  } +// DO NOT CALL THIS FOR GROUP NAMES  BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last)  {  	if(id.isNull()) @@ -511,11 +518,11 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las  		last.clear();  		if (!impl.isRequestPending(id))  		{ +			//llinfos << "**** adding name req for " << id << llendl;  			impl.mAskNameQueue.insert(id);  		}	 -		return FALSE;  	} - +	return FALSE;  }  BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) @@ -535,7 +542,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  	}  	LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id); -	if (entry && entry->mGroupName.empty()) +	if (entry && entry->mFirstName.empty())  	{  		// COUNTER-HACK to combat James' HACK in exportFile()...  		// this group name was loaded from a name cache that did not @@ -546,7 +553,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  	if (entry)  	{ -		group = entry->mGroupName; +		group = entry->mFirstName;  		return TRUE;  	}  	else  @@ -562,7 +569,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  // TODO: Make the cache name callback take a SINGLE std::string,  // not a separate first and last name. -void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data) +void LLCacheName::getNameFromUUID(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data)  {  	if(id.isNull())  	{ @@ -573,15 +580,8 @@ void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callb  	LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );  	if (entry)  	{ -		// id found in map therefore we can call the callback immediately. -		if (entry->mIsGroup) -		{ -			callback(id, entry->mGroupName, "", entry->mIsGroup, user_data); -		} -		else -		{ -			callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data); -		} +		// id found in map therefore we can call the callback immediately.  mLastName will be empty for groups +		callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data);  	}  	else  	{ @@ -590,13 +590,17 @@ void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callb  		{  			if (is_group)  			{ +				//llinfos << "Group queued for " << id << llendl;  				impl.mAskGroupQueue.insert(id);  			}  			else  			{ +				//llinfos << "Name queued for " << id << llendl;  				impl.mAskNameQueue.insert(id);  			}  		} + +		// There may be multiple replies for the same ID request  		impl.mReplyQueue.push_back(PendingReply(id, callback, user_data));  	}  } @@ -661,7 +665,7 @@ void LLCacheName::dump()  		{  			llinfos  				<< iter->first << " = (group) " -				<< entry->mGroupName +				<< entry->mFirstName  				<< " @ " << entry->mCreateTime  				<< llendl;  		} @@ -715,17 +719,7 @@ void LLCacheName::Impl::processPendingReplies()  		if (it->mCallback)  		{ -			if (!entry->mIsGroup) -			{ -				(it->mCallback)(it->mID, -					entry->mFirstName, entry->mLastName, -					FALSE, it->mData); -			} -			else { -				(it->mCallback)(it->mID, -					entry->mGroupName, "", -					TRUE, it->mData); -			} +			(it->mCallback)(it->mID, entry->mFirstName, entry->mLastName, entry->mIsGroup, it->mData);  		}  	} @@ -768,10 +762,12 @@ void LLCacheName::Impl::sendRequest(  		if(start_new_message)  		{  			start_new_message = false; +			//llinfos << "newMessageFast : " << msg_name << llendl;  			mMsg->newMessageFast(msg_name);  		}  		mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);  		mMsg->addUUIDFast(_PREHASH_ID, (*it)); +		//llinfos << " asking for ID: " << (*it) << llendl;  		if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))  		{ @@ -837,38 +833,102 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)  		{  			if (isGroup != entry->mIsGroup)  			{ -				llwarns << "LLCacheName - Asked for " -						<< (isGroup ? "group" : "user") << " name, " -						<< "but found " -						<< (entry->mIsGroup ? "group" : "user") -						<< ": " << id << llendl; +				if (entry->isUnknown()) +				{ +					Cache::iterator doomediter = mCache.find(id); +					if (doomediter != mCache.end()) +					{	// Kill existing unknown entry +						llwarns << "LLCacheName - Asked for " +								<< (isGroup ? "group" : "user") << " name, " +								<< "but found unknown " +								<< (entry->mIsGroup ? "group" : "user") +								<< " entry for: " << id  +								<< ", deleting bad entry" +								<< llendl; + +						delete entry; +						entry = NULL; +						mCache.erase(doomediter); + +						// Request it with (hopefully) the correct type +						makeNameRequestForID(id,isGroup,fromHost); +					} +				} +				else if (isGroup) +				{ +					llwarns << "LLCacheName - Asked for group name, but found user: " +							<< id  +							<< " named "  +							<< entry->mFirstName << " " << entry->mLastName  +							<< llendl; +				} +				else +				{ +					llwarns << "LLCacheName - Asked for user name, but found group: " +							<< id  +							<< " named "  +							<< entry->mFirstName +							<< llendl; +				}  			}  			else  			{  				// ...it's in the cache, so send it as the reply  				sender.send(id, *entry, fromHost); -			} -		} -		else -		{ -			if (!isRequestPending(id)) -			{ + +				/*  				if (isGroup)  				{ -					mAskGroupQueue.insert(id); +					llinfos << "Group ID " << id  +						<< " name " << entry->mFirstName +						<< " was already in cache" << llendl;  				}  				else  				{ -					mAskNameQueue.insert(id); +					llinfos << "Agent ID " << id  +						<< " name " << entry->mFirstName << " " << entry->mLastName  +						<< " was already in cache" << llendl;  				} +				*/  			} -			 -			mReplyQueue.push_back(PendingReply(id, fromHost)); +		} +		else +		{	/* +			if (isGroup) +			{ +				llinfos << "Group ID " << id << " is not in cache" << llendl; +			} +			else +			{ +				llinfos << "Agent ID " << id << " is not in cache" << llendl; +			} +			*/ +			makeNameRequestForID(id,isGroup,fromHost);  		}  	}  } +void LLCacheName::Impl::makeNameRequestForID(const LLUUID& id, bool isGroup, LLHost & fromHost) +{ +	if (!isRequestPending(id)) +	{ +		if (isGroup) +		{ +			//llinfos << "Adding group request for " << id << llendl; +			mAskGroupQueue.insert(id); +		} +		else +		{ +			//llinfos << "Adding name request for " << id << llendl; +			mAskNameQueue.insert(id); +		} +	} +	 +	// There may be multiple replys for the same ID request +	mReplyQueue.push_back(PendingReply(id, fromHost)); +} +  void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)  { @@ -878,35 +938,53 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)  		LLUUID id;  		msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);  		LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); +		bool add_new_entry_to_cache = false;  		if (!entry)  		{  			entry = new LLCacheNameEntry; -			mCache[id] = entry; +			add_new_entry_to_cache = true;  		} +		// Remove ID from pending queue  		mPendingQueue.erase(id); -		entry->mIsGroup = isGroup; -		entry->mCreateTime = (U32)time(NULL); -		if (!isGroup) -		{ -			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, entry->mFirstName, i); -			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName,  entry->mLastName, i); +		std::string first_name; +		std::string last_name; +		if (isGroup) +		{	// Group +			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, first_name, i); +			LLStringFn::replace_ascii_controlchars(first_name, LL_UNKNOWN_CHAR);  		}  		else -		{	// is group -			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i); -			LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR); +		{	// User +			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, first_name, i); +			msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, last_name, i);  		} - -		if (!isGroup) -		{ -			notifyObservers(id, entry->mFirstName, entry->mLastName, FALSE); +	 +		if (!add_new_entry_to_cache && +			(entry->mFirstName != first_name || +				entry->mLastName != last_name || +				entry->mIsGroup != isGroup)) +		{	// Hmmm, we already had an different entry for this ID.  Let's see what happened... +			llwarns << "Replacing existing entry in name cache for id " << id +				<< " first name was " << entry->mFirstName << ", now " << first_name +				<< " last name was " << entry->mLastName << ", now " << last_name +				<< " group flag was " << (S32) entry->mIsGroup << ", now " << (S32) isGroup +				<< llendl;  		} -		else + +		entry->mFirstName = first_name; +		entry->mLastName = last_name; +		entry->mIsGroup = isGroup; +		entry->mCreateTime = (U32)time(NULL); + +		if (add_new_entry_to_cache)  		{ -			notifyObservers(id, entry->mGroupName, "", TRUE); +			//llinfos << "Adding entry for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl; +			mCache[id] = entry;  		} + +		notifyObservers(id, entry->mFirstName, entry->mLastName, isGroup);  	}  } diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 2757b86a7c..bfa116ad4a 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -89,12 +89,8 @@ public:  	// If the data is currently available, may call the callback immediatly  	// otherwise, will request the data, and will call the callback when  	// available.  There is no garuntee the callback will ever be called. -	void get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data = NULL); +	void getNameFromUUID(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data = NULL); -	// LEGACY -	void getName(const LLUUID& id, LLCacheNameCallback callback, void* user_data = NULL) -			{ get(id, FALSE, callback, user_data); } -  	// This method needs to be called from time to time to send out  	// requests.  	void processPending(); diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index bbb56960df..5236a52164 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -1,5 +1,5 @@  /**  - * @file  + * @file llhttpclientadapter.cpp   * @brief    *   * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h index d5f3aeaf2c..c489dca32d 100644 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -1,5 +1,5 @@  /**  - * @file  + * @file llhttpclientadepter.h   * @brief    *   * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h index 1f13d46447..61826cc4b4 100644 --- a/indra/llmessage/llhttpclientinterface.h +++ b/indra/llmessage/llhttpclientinterface.h @@ -1,5 +1,5 @@  /**  - * @file  + * @file llhttpclientinterface.h   * @brief    *   * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 83dfa94f00..ce815cc85b 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -520,7 +520,7 @@ protected:  	 * seek orfor string assignment.  	 * @returns Returns true if a line was found.  	 */ -	bool readLine( +	bool readHeaderLine(  		const LLChannelDescriptors& channels,  		buffer_ptr_t buffer,  		U8* dest, @@ -591,7 +591,7 @@ LLHTTPResponder::~LLHTTPResponder()  	//lldebugs << "destroying LLHTTPResponder" << llendl;  } -bool LLHTTPResponder::readLine( +bool LLHTTPResponder::readHeaderLine(  	const LLChannelDescriptors& channels,  	buffer_ptr_t buffer,  	U8* dest, @@ -669,7 +669,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  #endif  		PUMP_DEBUG; -		if(readLine(channels, buffer, (U8*)buf, len)) +		if(readHeaderLine(channels, buffer, (U8*)buf, len))  		{  			bool read_next_line = false;  			bool parse_all = true; @@ -733,7 +733,13 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  					if(read_next_line)  					{  						len = HEADER_BUFFER_SIZE;	 -						readLine(channels, buffer, (U8*)buf, len); +						if (!readHeaderLine(channels, buffer, (U8*)buf, len)) +						{ +							// Failed to read the header line, probably too long. +							// readHeaderLine already marked the channel/buffer as bad. +							keep_parsing = false; +							break; +						}  					}  					if(0 == len)  					{ diff --git a/indra/llmessage/llmessagesenderinterface.h b/indra/llmessage/llmessagesenderinterface.h index 4082666339..d98d891563 100644 --- a/indra/llmessage/llmessagesenderinterface.h +++ b/indra/llmessage/llmessagesenderinterface.h @@ -1,5 +1,5 @@  /**  - * @file  + * @file llmessagesenderinterface.h   * @brief    *   * $LicenseInfo:firstyear=2008&license=viewergpl$ diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp index 552cf4cbdb..08c12f90da 100644 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ b/indra/llmessage/llregionpresenceverifier.cpp @@ -1,5 +1,5 @@  /**  - * @file  + * @file llregionpresenceverifier.cpp   * @brief    *   * $LicenseInfo:firstyear=2008&license=viewergpl$ @@ -25,11 +25,40 @@  #include "net.h"  #include "message.h" +namespace boost +{ +	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p) +	{ +		++p->mReferenceCount; +	} +	 +	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p) +	{ +		if(p && 0 == --p->mReferenceCount) +		{ +			delete p; +		} +	} +}; -LLRegionPresenceVerifier::RegionResponder::RegionResponder(ResponsePtr data) : mSharedData(data) +LLRegionPresenceVerifier::Response::~Response()  {  } +LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string& +														   uri, +														   ResponsePtr data, +														   S32 retry_count) : +	mUri(uri), +	mSharedData(data), +	mRetryCount(retry_count) +{ +} + +//virtual +LLRegionPresenceVerifier::RegionResponder::~RegionResponder() +{ +}  void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)  { @@ -42,26 +71,32 @@ void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)  	std::stringstream uri;  	uri << "http://" << destination.getString() << "/state/basic/"; -	mSharedData->getHttpClient().get(uri.str(), new VerifiedDestinationResponder(mSharedData, content)); +	mSharedData->getHttpClient().get( +		uri.str(), +		new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount));  } -void LLRegionPresenceVerifier::RegionResponder::completed( -	U32 status, -	const std::string& reason, -	const LLSD& content) +void LLRegionPresenceVerifier::RegionResponder::error(U32 status, +													 const std::string& reason)  { -	LLHTTPClient::Responder::completed(status, reason, content); -	 -	mSharedData->onCompletedRegionRequest(); +	// TODO: babbage: distinguish between region presence service and +	// region verification errors? +	mSharedData->onRegionVerificationFailed();  } - -LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(ResponsePtr data, const LLSD& content) : mSharedData(data), mContent(content) +LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, +	S32 retry_count): +	mUri(uri), +	mSharedData(data), +	mContent(content), +	mRetryCount(retry_count)   {  } - - +//virtual +LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder() +{ +}  void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content)  { @@ -76,13 +111,14 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD&  	{  		mSharedData->onRegionVerified(mContent);  	} -	else if (mSharedData->shouldRetry()) +	else if (mRetryCount > 0)  	{  		retry();  	}  	else  	{ -		llwarns << "Could not correctly look up region from region presence service. Region: " << mSharedData->getRegionUri() << llendl; +		llwarns << "Simulator verification failed. Region: " << mUri << llendl; +		mSharedData->onRegionVerificationFailed();  	}  } @@ -90,13 +126,21 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry()  {  	LLSD headers;  	headers["Cache-Control"] = "no-cache, max-age=0"; -	llinfos << "Requesting region information, get uncached for region " << mSharedData->getRegionUri() << llendl; -	mSharedData->decrementRetries(); -	mSharedData->getHttpClient().get(mSharedData->getRegionUri(), new RegionResponder(mSharedData), headers); +	llinfos << "Requesting region information, get uncached for region " +			<< mUri << llendl; +	--mRetryCount; +	mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers);  }  void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason)  { -	retry(); +	if(mRetryCount > 0) +	{ +		retry(); +	} +	else +	{ +		llwarns << "Failed to contact simulator for verification. Region: " << mUri << llendl; +		mSharedData->onRegionVerificationFailed(); +	}  } - diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h index d1de608ec6..f11eeef50c 100644 --- a/indra/llmessage/llregionpresenceverifier.h +++ b/indra/llmessage/llregionpresenceverifier.h @@ -1,5 +1,5 @@  /**  - * @file  + * @file llregionpresenceverifier.cpp   * @brief    *   * $LicenseInfo:firstyear=2008&license=viewergpl$ @@ -26,7 +26,7 @@  #include "llhttpclient.h"  #include <string>  #include "llsd.h" -#include <boost/shared_ptr.hpp> +#include <boost/intrusive_ptr.hpp>  class LLHTTPClientInterface; @@ -36,48 +36,57 @@ public:  	class Response  	{  	public: -		virtual ~Response() {} +		virtual ~Response() = 0;  		virtual bool checkValidity(const LLSD& content) const = 0;  		virtual void onRegionVerified(const LLSD& region_details) = 0; - -		virtual void decrementRetries() = 0; +		virtual void onRegionVerificationFailed() = 0;  		virtual LLHTTPClientInterface& getHttpClient() = 0; -		virtual std::string getRegionUri() const = 0; -		virtual bool shouldRetry() const = 0; -		virtual void onCompletedRegionRequest() {} +	public: /* but not really -- don't touch this */ +		U32 mReferenceCount;		  	}; -	typedef boost::shared_ptr<Response> ResponsePtr; +	typedef boost::intrusive_ptr<Response> ResponsePtr;  	class RegionResponder : public LLHTTPClient::Responder  	{  	public: -		RegionResponder(ResponsePtr data); +		RegionResponder(const std::string& uri, ResponsePtr data, +						S32 retry_count); +		virtual ~RegionResponder();   		virtual void result(const LLSD& content); -		virtual void completed( -			U32 status, -			const std::string& reason, -			const LLSD& content); +		virtual void error(U32 status, const std::string& reason);  	private:  		ResponsePtr mSharedData; +		std::string mUri; +		S32 mRetryCount;  	};  	class VerifiedDestinationResponder : public LLHTTPClient::Responder  	{  	public: -		VerifiedDestinationResponder(ResponsePtr data, const LLSD& content); +		VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, +									 const LLSD& content, S32 retry_count); +		virtual ~VerifiedDestinationResponder();  		virtual void result(const LLSD& content);  		virtual void error(U32 status, const std::string& reason); +		  	private:  		void retry();  		ResponsePtr mSharedData;  		LLSD mContent; +		std::string mUri; +		S32 mRetryCount;  	};  }; +namespace boost +{ +	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p); +	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p); +};  #endif //LL_LLREGIONPRESENCEVERIFIER_H diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index 615eff405d..da6d1c84a8 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -1,5 +1,5 @@  /**  - * @file  + * @file llstoredmessage.cpp   * @brief    *   * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index e817f19bd2..6a27698b03 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -1,5 +1,5 @@  /**  - * @file  + * @file llstoredmessage.h   * @brief    *   * $LicenseInfo:firstyear=2009&license=viewergpl$ diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index 70279a3c62..0872efba50 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -265,6 +265,31 @@ BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec)  	return changed;  } +// Return bits available in the channel +S32		LLThrottleGroup::getAvailable(S32 throttle_cat) +{ +	S32 retval = 0; + +	F32 category_bps = mCurrentBPS[throttle_cat]; +	F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; + +	// use a temporary bits_available +	// since we don't want to change mBitsAvailable every time +	F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]); +	F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time); + +	if (bits_available >= lookahead_bits) +	{ +		retval = (S32) gThrottleMaximumBPS[throttle_cat]; +	} +	else  +	{ +		retval = (S32) bits_available; +	} +	 +	return retval; +} +  BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits)  { diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h index 7d1679beb2..47a7c653b2 100644 --- a/indra/llmessage/llthrottle.h +++ b/indra/llmessage/llthrottle.h @@ -84,6 +84,8 @@ public:  	BOOL	dynamicAdjust();		// Shift bandwidth from idle channels to busy channels, TRUE if adjustment occurred  	BOOL	setNominalBPS(F32* throttle_vec);				// TRUE if any value was different, resets adjustment system if was different +	S32		getAvailable(S32 throttle_cat);					// Return bits available in the channel +  	void packThrottle(LLDataPacker &dp) const;  	void unpackThrottle(LLDataPacker &dp);  public: diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 3ab8057abb..81b7761ed5 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -51,6 +51,7 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;   * String constants   */  const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); +const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");  static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); @@ -247,7 +248,29 @@ LLIOPipe::EStatus LLURLRequest::process_impl(  	PUMP_DEBUG;  	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);  	//llinfos << "LLURLRequest::process_impl()" << llendl; -	if(!buffer) return STATUS_ERROR; +	if (!buffer) return STATUS_ERROR; +	 +	// we're still waiting or prcessing, check how many +	// bytes we have accumulated. +	const S32 MIN_ACCUMULATION = 100000; +	if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) +	{ +		 // This is a pretty sloppy calculation, but this +		 // tries to make the gross assumption that if data +		 // is coming in at 56kb/s, then this transfer will +		 // probably succeed. So, if we're accumlated +		 // 100,000 bytes (MIN_ACCUMULATION) then let's +		 // give this client another 2s to complete. +		 const F32 TIMEOUT_ADJUSTMENT = 2.0f; +		 mDetail->mByteAccumulator = 0; +		 pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT); +		 lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl; +		 if (mState == STATE_INITIALIZED) +		 { +			  llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl; +		 } +	} +  	switch(mState)  	{  	case STATE_INITIALIZED: @@ -286,27 +309,14 @@ LLIOPipe::EStatus LLURLRequest::process_impl(  			bool newmsg = mDetail->mCurlRequest->getResult(&result);  			if(!newmsg)  			{ -				// we're still waiting or prcessing, check how many -				// bytes we have accumulated. -				const S32 MIN_ACCUMULATION = 100000; -				if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) -				{ -					// This is a pretty sloppy calculation, but this -					// tries to make the gross assumption that if data -					// is coming in at 56kb/s, then this transfer will -					// probably succeed. So, if we're accumlated -					// 100,000 bytes (MIN_ACCUMULATION) then let's -					// give this client another 2s to complete. -					const F32 TIMEOUT_ADJUSTMENT = 2.0f; -					mDetail->mByteAccumulator = 0; -					pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT); -				} -  				// keep processing  				break;  			}  			mState = STATE_HAVE_RESPONSE; +			context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; +			context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; +			lldebugs << this << "Setting context to " << context << llendl;  			switch(result)  			{  				case CURLE_OK: @@ -353,10 +363,16 @@ LLIOPipe::EStatus LLURLRequest::process_impl(  		// we already stuffed everything into channel in in the curl  		// callback, so we are done.  		eos = true; +		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; +		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; +		lldebugs << this << "Setting context to " << context << llendl;  		return STATUS_DONE;  	default:  		PUMP_DEBUG; +		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; +		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; +		lldebugs << this << "Setting context to " << context << llendl;  		return STATUS_ERROR;  	}  } @@ -369,6 +385,8 @@ void LLURLRequest::initialize()  	mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);  	mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);  	mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this); +	mRequestTransferedBytes = 0; +	mResponseTransferedBytes = 0;  }  bool LLURLRequest::configure() @@ -471,6 +489,7 @@ size_t LLURLRequest::downCallback(  		req->mDetail->mChannels.out(),  		(U8*)data,  		bytes); +	req->mResponseTransferedBytes += bytes;  	req->mDetail->mByteAccumulator += bytes;  	return bytes;  } @@ -494,6 +513,7 @@ size_t LLURLRequest::upCallback(  		req->mDetail->mLastRead,  		(U8*)data,  		bytes); +	req->mRequestTransferedBytes += bytes;  	return bytes;  } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 86ef71f085..cb3c466440 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -45,6 +45,12 @@  #include "llchainio.h"  #include "llerror.h" + +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_DEST_URI_SD_LABEL; +extern const std::string CONTEXT_RESPONSE; +extern const std::string CONTEXT_TRANSFERED_BYTES; +  class LLURLRequestDetail;  class LLURLRequestComplete; @@ -208,6 +214,8 @@ protected:  	ERequestAction mAction;  	LLURLRequestDetail* mDetail;  	LLIOPipe::ptr_t mCompletionCallback; +	 S32 mRequestTransferedBytes; +	 S32 mResponseTransferedBytes;  private:  	/**  diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 08c9192c9f..209bdb2249 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -760,30 +760,36 @@ static bool remove_prefix(std::string& filename, const std::string& prefix)  static bool verify_cache_filename(const std::string& filename)  {  	//NOTE: This routine is only used to check file names that our own -	// code places in the cache directory.  As such, it can be limited -	// to this very restrictive file name pattern.  It does not need to -	// handle other characters. - +	// code places in the cache directory.	As such, it can be limited +	// to this very restrictive file name pattern.	It does not need to +	// handle other characters. The only known uses of this are (with examples): +	//	sim to sim object pass:			fc0b72d8-9456-63d9-a802-a557ef847313.tmp +	//	sim to viewer mute list:		mute_b78eacd0-1244-448e-93ca-28ede242f647.tmp +	//	sim to viewer task inventory:	inventory_d8ab59d2-baf0-0e79-c4c2-a3f99b9fcf45.tmp +	 +	//IMPORTANT: Do not broaden the filenames accepted by this routine +	// without careful analysis. Anything allowed by this function can +	// be downloaded by the viewer. +	  	size_t len = filename.size(); -	//const boost::regex expr("[a-zA-Z0-9][-_.a-zA-Z0-9]<0,49>"); -	if (len < 1 || len > 50) -	{ +	//const boost::regex expr("[0-9a-zA-Z_-]<1,46>\.tmp"); +	if (len < 5 || len > 50) +	{	  		return false;  	} -	for(unsigned i=0; i<len; ++i) -	{ +	for(size_t i=0; i<(len-4); ++i) +	{	  		char c = filename[i]; -		bool ok = isalnum(c); -		if (!ok && i > 0) -		{ -			ok = '_'==c || '-'==c || '.'==c; -		} +		bool ok = isalnum(c) || '_'==c || '-'==c;  		if (!ok)  		{  			return false;  		}  	} -	return true; +	return filename[len-4] == '.' +		&& filename[len-3] == 't' +		&& filename[len-2] == 'm' +		&& filename[len-1] == 'p';  }  void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/) diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h new file mode 100644 index 0000000000..2f55e97fcc --- /dev/null +++ b/indra/llmessage/tests/llmockhttpclient.h @@ -0,0 +1,61 @@ +/**  + * @file  + * @brief  + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2008, Linden Research, Inc. + *  + * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of + * this source code is governed by the Linden Lab Source Code Disclosure + * Agreement ("Agreement") previously entered between you and Linden + * Lab. By accessing, using, copying, modifying or distributing this + * software, you acknowledge that you have been informed of your + * obligations under the Agreement and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/* Macro Definitions */ +#ifndef LL_LLMOCKHTTPCLIENT_H +#define LL_LLMOCKHTTPCLIENT_H + +#include "linden_common.h" +#include "llhttpclientinterface.h" + +#include <gmock/gmock.h> + +class LLMockHTTPClient : public LLHTTPClientInterface +{ +public: +  MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder)); +  MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)); +  MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)); +}; + +// A helper to match responder types +template<typename T> +struct ResponderType +{ +	bool operator()(LLCurl::ResponderPtr ptr) const +	{ +		T* p = dynamic_cast<T*>(ptr.get()); +		return p != NULL; +	} +}; + +inline bool operator==(const LLSD& l, const LLSD& r) +{ +	std::ostringstream ls, rs; +	ls << l; +	rs << r; +	return ls.str() == rs.str(); + +} + + +#endif //LL_LLMOCKHTTPCLIENT_H + diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp new file mode 100644 index 0000000000..b7602ef15c --- /dev/null +++ b/indra/llmessage/tests/llregionpresenceverifier_test.cpp @@ -0,0 +1,111 @@ +/**  + * @file  + * @brief  + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2001-2008, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../test/lltut.h" +#include "llregionpresenceverifier.h" +#include "llcurl_stub.cpp" +#include "llhost.cpp" +#include "net.cpp" +#include "lltesthttpclientadapter.cpp" + +class LLTestResponse : public LLRegionPresenceVerifier::Response +{ +public: + +	virtual bool checkValidity(const LLSD& content) const +	{ +		return true; +	} + +	virtual void onRegionVerified(const LLSD& region_details) +	{ +	} + +	virtual void onRegionVerificationFailed() +	{ +	} +	 +	virtual LLHTTPClientInterface& getHttpClient() +	{ +		return mHttpInterface; +	} + +	LLTestHTTPClientAdapter mHttpInterface; +}; + +namespace tut +{ +	struct LLRegionPresenceVerifierData +	{ +		LLRegionPresenceVerifierData() : +			mResponse(new LLTestResponse()), +			mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse), +					   LLSD(), 3) +		{ +		} +		 +		LLTestResponse* mResponse; +		LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder; +	}; + +	typedef test_group<LLRegionPresenceVerifierData> factory; +	typedef factory::object object; +} + +namespace +{ +	tut::factory tf("LLRegionPresenceVerifier test"); +} + +namespace tut +{ +	// Test that VerifiedDestinationResponder does retry +    // on error when shouldRetry returns true. +	template<> template<> +	void object::test<1>() +	{ +		mResponder.error(500, "Internal server error"); +		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1); +	} + +	// Test that VerifiedDestinationResponder only retries +	// on error until shouldRetry returns false. +	template<> template<> +	void object::test<2>() +	{ +		mResponder.error(500, "Internal server error"); +		mResponder.error(500, "Internal server error"); +		mResponder.error(500, "Internal server error"); +		mResponder.error(500, "Internal server error"); +		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3); +	} +} + diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 13facc0d58..58aaf97a76 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1314,6 +1314,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)  		return (size == 16);  	case PARAMS_SCULPT:  		return (size == 17); +	case PARAMS_LIGHT_IMAGE: +		return (size == 28);  	}  	return FALSE; @@ -1646,3 +1648,79 @@ bool LLSculptParams::fromLLSD(LLSD& sd)  	return false;  } +//============================================================================ + +LLLightImageParams::LLLightImageParams() +{ +	mType = PARAMS_LIGHT_IMAGE; +	mParams.setVec(F_PI*0.5f, 0.f, 0.f); +} + +BOOL LLLightImageParams::pack(LLDataPacker &dp) const +{ +	dp.packUUID(mLightTexture, "texture"); +	dp.packVector3(mParams, "params"); + +	return TRUE; +} + +BOOL LLLightImageParams::unpack(LLDataPacker &dp) +{ +	dp.unpackUUID(mLightTexture, "texture"); +	dp.unpackVector3(mParams, "params"); +	 +	return TRUE; +} + +bool LLLightImageParams::operator==(const LLNetworkData& data) const +{ +	if (data.mType != PARAMS_LIGHT_IMAGE) +	{ +		return false; +	} +	 +	const LLLightImageParams *param = (const LLLightImageParams*)&data; +	if ( (param->mLightTexture != mLightTexture) ) +	{ +		return false; +	} + +	if ( (param->mParams != mParams ) ) +	{ +		return false; +	} +	 +	return true; +} + +void LLLightImageParams::copy(const LLNetworkData& data) +{ +	const LLLightImageParams *param = (LLLightImageParams*)&data; +	mLightTexture = param->mLightTexture; +	mParams = param->mParams; +} + + + +LLSD LLLightImageParams::asLLSD() const +{ +	LLSD sd; +	 +	sd["texture"] = mLightTexture; +	sd["params"] = mParams.getValue(); +		 +	return sd; +} + +bool LLLightImageParams::fromLLSD(LLSD& sd) +{ +	if (sd.has("texture")) +	{ +		setLightTexture( sd["texture"] ); +		setParams( sd["params"] ); +		return true; +	}  +	 +	return false; +} + diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index c25df0a40f..01389a0e04 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -107,7 +107,8 @@ public:  	{  		PARAMS_FLEXIBLE = 0x10,  		PARAMS_LIGHT    = 0x20, -		PARAMS_SCULPT   = 0x30 +		PARAMS_SCULPT   = 0x30, +		PARAMS_LIGHT_IMAGE = 0x40,  	};  public: @@ -267,6 +268,28 @@ public:  	U8 getSculptType()                      { return mSculptType; }  }; +class LLLightImageParams : public LLNetworkData +{ +protected: +	LLUUID mLightTexture; +	LLVector3 mParams; +	 +public: +	LLLightImageParams(); +	/*virtual*/ BOOL pack(LLDataPacker &dp) const; +	/*virtual*/ BOOL unpack(LLDataPacker &dp); +	/*virtual*/ bool operator==(const LLNetworkData& data) const; +	/*virtual*/ void copy(const LLNetworkData& data); +	LLSD asLLSD() const; +	operator LLSD() const { return asLLSD(); } +	bool fromLLSD(LLSD& sd); + +	void setLightTexture(const LLUUID& id) { mLightTexture = id; } +	LLUUID getLightTexture() const         { return mLightTexture; } +	void setParams(const LLVector3& params) { mParams = params; } +	LLVector3 getParams() const			   { return mParams; } +	 +};  class LLPrimitive : public LLXform diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index c9632ebdad..b02d4c50bd 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -134,13 +134,12 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te)  {  	if (S32(index) >= mEntryList.size())  	{ -		// TODO -- assert here  		S32 current_size = mEntryList.size(); -		llerrs << "index = " << S32(index) << "  current_size = " << current_size << llendl; +		llwarns << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << llendl;  		return TEM_CHANGE_NONE;  	} -	// we're changing an existing entry +		// we're changing an existing entry  	llassert(mEntryList[index]);  	delete (mEntryList[index]);  	if  (&te) @@ -386,8 +385,18 @@ void LLPrimTextureList::setSize(S32 new_size)  		mEntryList.resize(new_size);  		for (S32 index = current_size; index < new_size; ++index)  		{ -			LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); -			mEntryList[index] = new_entry; +			if (current_size > 0 +				&& mEntryList[current_size - 1]) +			{ +				// copy the last valid entry for the new one +				mEntryList[index] = mEntryList[current_size - 1]->newCopy(); +			} +			else +			{ +				// no valid enries to copy, so we new one up +				LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); +				mEntryList[index] = new_entry; +			}  		}  	}  	else if (new_size < current_size) diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp index e231002a52..452594c7e7 100755 --- a/indra/llvfs/llpidlock.cpp +++ b/indra/llvfs/llpidlock.cpp @@ -61,7 +61,7 @@ class LLPidLockFile  			mSaving(FALSE), mWaiting(FALSE),   			mClean(TRUE), mPID(getpid())  		{ -			mLockName = gDirUtilp->getTempDir() + "/savelock"; +			mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock";  		}  		bool requestLock(LLNameTable<void *> *name_table, bool autosave,  						bool force_immediate=FALSE, F32 timeout=300.0); diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h index ba2c46bef2..a54ebd5831 100644 --- a/indra/lscript/lscript_byteformat.h +++ b/indra/lscript/lscript_byteformat.h @@ -556,7 +556,7 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] =  // http_request string constants  extern const char* URL_REQUEST_GRANTED;  extern const char* URL_REQUEST_DENIED; -extern const U64 LSL_HTTP_REQUEST_TIMEOUT; +extern const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC;  #endif diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index e291d4c6f8..7fa115bb20 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -631,9 +631,7 @@ static void print_cil_cast(LLFILE* fp, LSCRIPTType srcType, LSCRIPTType targetTy  		switch(targetType)  		{  		case LST_INTEGER: -			//fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n"); -			fprintf(fp, "conv.i4\n"); // TODO replace this line with the above -			// we the entire grid is > 1.25.1 +			fprintf(fp, "call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)\n");  			break;  		case LST_STRING:  			fprintf(fp, "call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ToString(float32)\n"); @@ -8375,10 +8373,18 @@ void LLScriptStateChange::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTComp  			chunk->addInteger(mIdentifier->mScopeEntry->mCount);  		}  		break; +	case LSCP_TYPE: +		mReturnType = basetype; +		break;  	case LSCP_EMIT_CIL_ASSEMBLY:  		fprintf(fp, "ldarg.0\n");  		fprintf(fp, "ldstr \"%s\"\n", mIdentifier->mName);  		fprintf(fp, "call instance void class [LslUserScript]LindenLab.SecondLife.LslUserScript::ChangeState(string)\n"); +		// We are doing a state change. In the LSL interpreter, this is basically a longjmp. We emulate it +		// here using a call to the ChangeState followed by a short cut return of the current method. To +		// maintain type safety we need to push an arbitrary variable of the current method's return type +		// onto the stack before returning. This will be ignored and discarded. +		print_cil_init_variable(fp, mReturnType);  		fprintf(fp, "ret\n");  		break;  	default: diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h index 12c16908af..a667e1eb5b 100644 --- a/indra/lscript/lscript_compile/lscript_tree.h +++ b/indra/lscript/lscript_compile/lscript_tree.h @@ -1888,6 +1888,7 @@ public:  	S32 getSize();  	LLScriptIdentifier *mIdentifier; +	LSCRIPTType mReturnType;  };  class LLScriptJump : public LLScriptStatement diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h index 9a631c4c8f..8549482299 100644 --- a/indra/lscript/lscript_execute.h +++ b/indra/lscript/lscript_execute.h @@ -369,8 +369,7 @@ class LLScriptExecute  {  public:  	LLScriptExecute(); -	virtual ~LLScriptExecute() {;} - +	virtual ~LLScriptExecute()  = 0;  	virtual S32 getVersion() const = 0;  	virtual void deleteAllEvents() = 0;  	virtual void addEvent(LLScriptDataCollection* event) = 0; diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp index 05fee9a419..1f908eb675 100644 --- a/indra/lscript/lscript_execute/lscript_execute.cpp +++ b/indra/lscript/lscript_execute/lscript_execute.cpp @@ -41,6 +41,8 @@  #include "lscript_library.h"  #include "lscript_heapruntime.h"  #include "lscript_alloc.h" +#include "llstat.h" +  // Static  const	S32	DEFAULT_SCRIPT_TIMER_CHECK_SKIP = 4; @@ -72,7 +74,7 @@ const char* URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED";  const char* URL_REQUEST_DENIED = "URL_REQUEST_DENIED";  // HTTP Requests to LSL scripts will time out after 25 seconds. -const U64 LSL_HTTP_REQUEST_TIMEOUT = 25 * USEC_PER_SEC;  +const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC = 25 * USEC_PER_SEC;   LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp)  { @@ -110,6 +112,7 @@ LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size)  	init();  } +LLScriptExecute::~LLScriptExecute() {}  LLScriptExecuteLSL2::~LLScriptExecuteLSL2()  {  	delete[] mBuffer; @@ -4234,19 +4237,16 @@ S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer)  	return 4;  } -BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) + +// Shared code for run_calllib() and run_calllib_two_byte() +BOOL run_calllib_common(U8 *buffer, S32 &offset, const LLUUID &id, U16 arg)  { -	if (b_print) -		printf("[0x%X]\tCALLLIB ", offset); -	offset++; -	U8 arg = safe_instruction_bytestream2byte(buffer, offset);  	if (arg >= gScriptLibrary.mNextNumber)  	{  		set_fault(buffer, LSRF_BOUND_CHECK_ERROR);  		return FALSE;  	} -	if (b_print) -		printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName); +	LLScriptLibraryFunction *function = gScriptLibrary.mFunctions[arg];  	// pull out the arguments and the return values  	LLScriptLibData	*arguments = NULL; @@ -4254,14 +4254,14 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)  	S32 i, number; -	if (gScriptLibrary.mFunctions[arg]->mReturnType) +	if (function->mReturnType)  	{  		returnvalue = new LLScriptLibData;  	} -	if (gScriptLibrary.mFunctions[arg]->mArgs) +	if (function->mArgs)  	{ -		number = (S32)strlen(gScriptLibrary.mFunctions[arg]->mArgs);		/*Flawfinder: ignore*/ +		number = (S32)strlen(function->mArgs);		//Flawfinder: ignore  		arguments = new LLScriptLibData[number];  	}  	else @@ -4271,24 +4271,18 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)  	for (i = number - 1; i >= 0; i--)  	{ -		lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg]->mArgs[i]); +		lscript_pop_variable(&arguments[i], buffer, function->mArgs[i]);  	} -	if (b_print) -	{ -		printf("%s\n", gScriptLibrary.mFunctions[arg]->mDesc); -	} +	// Actually execute the function call +	function->mExecFunc(returnvalue, arguments, id); -	{ -		// LLFastTimer time_in_libraries1(LLFastTimer::FTM_TEMP7); -		gScriptLibrary.mFunctions[arg]->mExecFunc(returnvalue, arguments, id); -	} -	add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg]->mEnergyUse); -	add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg]->mSleepTime); +	add_register_fp(buffer, LREG_ESR, -(function->mEnergyUse)); +	add_register_fp(buffer, LREG_SLR, function->mSleepTime);  	if (returnvalue)  	{ -		returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg]->mReturnType); +		returnvalue->mType = char2type(*function->mReturnType);  		lscript_push_return_variable(returnvalue, buffer);  	} @@ -4305,72 +4299,32 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)  } -BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) +BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)  { -	if (b_print) -		printf("[0x%X]\tCALLLIB ", offset);  	offset++; -	U16 arg = safe_instruction_bytestream2u16(buffer, offset); -	if (arg >= gScriptLibrary.mNextNumber) -	{ -		set_fault(buffer, LSRF_BOUND_CHECK_ERROR); -		return FALSE; -	} -	if (b_print) -		printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName); - -	// pull out the arguments and the return values -	LLScriptLibData	*arguments = NULL; -	LLScriptLibData	*returnvalue = NULL; - -	S32 i, number; - -	if (gScriptLibrary.mFunctions[arg]->mReturnType) -	{ -		returnvalue = new LLScriptLibData; -	} - -	if (gScriptLibrary.mFunctions[arg]->mArgs) +	U16 arg = (U16) safe_instruction_bytestream2byte(buffer, offset); +	if (b_print && +		arg < gScriptLibrary.mNextNumber)  	{ -		number = (S32)strlen(gScriptLibrary.mFunctions[arg]->mArgs);		/*Flawfinder: ignore*/ -		arguments = new LLScriptLibData[number]; -	} -	else -	{ -		number = 0; -	} - -	for (i = number - 1; i >= 0; i--) -	{ -		lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg]->mArgs[i]); -	} - -	if (b_print) -	{ -		printf("%s\n", gScriptLibrary.mFunctions[arg]->mDesc); -	} - -	{ -		// LLFastTimer time_in_libraries2(LLFastTimer::FTM_TEMP8); -		gScriptLibrary.mFunctions[arg]->mExecFunc(returnvalue, arguments, id); +		printf("[0x%X]\tCALLLIB ", offset); +		LLScriptLibraryFunction *function = gScriptLibrary.mFunctions[arg]; +		printf("%d (%s)\n", (U32)arg, function->mName); +		printf("%s\n", function->mDesc);  	} -	add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg]->mEnergyUse); -	add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg]->mSleepTime); +	return run_calllib_common(buffer, offset, id, arg); +} -	if (returnvalue) +BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id) +{ +	offset++; +	U16 arg = safe_instruction_bytestream2u16(buffer, offset); +	if (b_print && +		arg < gScriptLibrary.mNextNumber)  	{ -		returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg]->mReturnType); -		lscript_push_return_variable(returnvalue, buffer); +		printf("[0x%X]\tCALLLIB ", (offset-1)); +		LLScriptLibraryFunction *function = gScriptLibrary.mFunctions[arg]; +		printf("%d (%s)\n", (U32)arg, function->mName); +		printf("%s\n", function->mDesc);  	} - -	delete [] arguments; -	delete returnvalue; - -	// reset the BP after calling the library files -	S32 bp = lscript_pop_int(buffer); -	set_bp(buffer, bp); - -	// pop off the spot for the instruction pointer -	lscript_poparg(buffer, 4); -	return FALSE; +	return run_calllib_common(buffer, offset, id, arg);  } diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 06c1b2c12b..9d6c26d834 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3063,7 +3063,7 @@ bool LLDispatchEstateUpdateInfo::operator()(  	regionp->setOwner(owner_id);  	// Update estate owner name in UI  	const BOOL is_group = FALSE; -	gCacheName->get(owner_id, is_group, LLPanelEstateInfo::callbackCacheName); +	gCacheName->getNameFromUUID(owner_id, is_group, LLPanelEstateInfo::callbackCacheName);  	U32 estate_id = strtoul(strings[2].c_str(), NULL, 10);  	panel->setEstateID(estate_id); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index a90ea39265..5b3f3952c9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -932,7 +932,8 @@ void LLIMMgr::inviteToSession(  	{  		if (caller_name.empty())  		{ -			gCacheName->getName(caller_id, onInviteNameLookup, new LLSD(payload)); +			BOOL is_group = FALSE;		// Inviter must be a person +			gCacheName->getNameFromUUID(caller_id, is_group, onInviteNameLookup, new LLSD(payload));  		}  		else  		{ diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 40b1c64146..a840b59140 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -566,7 +566,7 @@ BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, co  			else  			{  				// not in cache, lookup name from cache -				gCacheName->get(agent_id, FALSE, notify_automute_callback, (void *)reason); +				gCacheName->getNameFromUUID(agent_id, FALSE, notify_automute_callback, (void *)reason);  			}  		}  		else diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index bbfd480e0b..7664d7ee07 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1040,7 +1040,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  	// * we can't build two messages at once.  	if (2 == button)  	{ -		gCacheName->get(mFromID, mFromGroup, inventory_offer_mute_callback, this); +		gCacheName->getNameFromUUID(mFromID, mFromGroup, inventory_offer_mute_callback, this);  	}  	LLMessageSystem* msg = gMessageSystem; @@ -4428,7 +4428,7 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use  			LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);  			gMeanCollisionList.push_front(mcd);  			const BOOL is_group = FALSE; -			gCacheName->get(perp, is_group, mean_name_callback); +			gCacheName->getNameFromUUID(perp, is_group, mean_name_callback);  		}  	}  } @@ -5375,7 +5375,7 @@ void process_load_url(LLMessageSystem* msg, void**)  	// Add to list of pending name lookups  	gLoadUrlList.push_back(payload); -	gCacheName->get(owner_id, owner_is_group, callback_load_url_name); +	gCacheName->getNameFromUUID(owner_id, owner_is_group, callback_load_url_name);  } @@ -5469,7 +5469,9 @@ void process_covenant_reply(LLMessageSystem* msg, void**)  	LLPanelLandCovenant::updateLastModified(last_modified);  	LLFloaterBuyLand::updateLastModified(last_modified); -	gCacheName->getName(estate_owner_id, callbackCacheEstateOwnerName); +	// Estates can't be owned by groups +	BOOL is_group = FALSE; +	gCacheName->getNameFromUUID(estate_owner_id, is_group, callbackCacheEstateOwnerName);  	// load the actual covenant asset data  	const BOOL high_priority = TRUE; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 94407ed08c..232885b3f6 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -6901,7 +6901,8 @@ void LLVoiceClient::notifyFriendObservers()  void LLVoiceClient::lookupName(const LLUUID &id)  { -	gCacheName->getName(id, onAvatarNameLookup); +	BOOL is_group = FALSE; +	gCacheName->getNameFromUUID(id, is_group, onAvatarNameLookup);  }  //static diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 49a0a8f361..53109ca196 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -14,6 +14,7 @@ include(LScript)  include(Linking)  include(Tut)  include(Boost) +include(GoogleMock)  include_directories(      ${LLCOMMON_INCLUDE_DIRS} @@ -24,6 +25,7 @@ include_directories(      ${LLVFS_INCLUDE_DIRS}      ${LLXML_INCLUDE_DIRS}      ${LSCRIPT_INCLUDE_DIRS} +    ${GOOGLEMOCK_INCLUDE_DIRS}      )  set(test_SOURCE_FILES @@ -121,6 +123,7 @@ target_link_libraries(test      ${LLXML_LIBRARIES}      ${LSCRIPT_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${GOOGLEMOCK_LIBRARIES}      ${APRICONV_LIBRARIES}      ${PTHREAD_LIBRARY}      ${WINDOWS_LIBRARIES} @@ -137,12 +140,18 @@ endif (WINDOWS)  get_target_property(TEST_EXE test LOCATION) +SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR}) + +SET(TEST_LD_CMD  +  ${CMAKE_COMMAND}  +  -DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib +  -DTEST_CMD:STRING="${TEST_CMD}"  +  -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake +  ) +  add_custom_command(    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt -  COMMAND ${TEST_EXE} -  ARGS -    --output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt -    --touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt +  COMMAND ${TEST_LD_CMD}    DEPENDS test    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}    COMMENT "C++ unit tests" diff --git a/indra/test/test.cpp b/indra/test/test.cpp index ba81c6e49e..c9e985c914 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -54,6 +54,9 @@  #	include "ctype_workaround.h"  #endif +#include <gmock/gmock.h> +#include <gtest/gtest.h> +  namespace tut  {  	std::string sSourceDir; @@ -238,6 +241,9 @@ void wouldHaveCrashed(const std::string& message)  int main(int argc, char **argv)  { +	// The following line must be executed to initialize Google Mock +	// (and Google Test) before running the tests. +	::testing::InitGoogleMock(&argc, argv);  	LLError::initForApplication(".");  	LLError::setFatalFunction(wouldHaveCrashed);  	LLError::setDefaultLevel(LLError::LEVEL_ERROR); | 
