diff options
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 171 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 1 | 
2 files changed, 103 insertions, 69 deletions
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 7381504f01..6c0f101cd7 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -269,6 +269,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mPixelArea(1024.f),  	mInventory(NULL),  	mInventorySerialNum(0), +	mExpectedInventorySerialNum(0),  	mInvRequestState(INVENTORY_REQUEST_STOPPED),  	mInvRequestXFerId(0),  	mInventoryDirty(FALSE), @@ -2802,13 +2803,13 @@ void LLViewerObject::doUpdateInventory(  			{  				// best guess.  				perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); -				--mInventorySerialNum; +				--mExpectedInventorySerialNum;  			}  			else  			{  				// dummy it up.  				perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); -				--mInventorySerialNum; +				--mExpectedInventorySerialNum;  			}  		}  		LLViewerInventoryItem* oldItem = item; @@ -2816,7 +2817,11 @@ void LLViewerObject::doUpdateInventory(  		new_item->setPermissions(perm);  		mInventory->push_front(new_item);  		doInventoryCallback(); -		++mInventorySerialNum; +		++mExpectedInventorySerialNum; +	} +	else if (is_new) +	{ +		++mExpectedInventorySerialNum;  	}  } @@ -2883,7 +2888,7 @@ void LLViewerObject::moveInventory(const LLUUID& folder_id,  		if(!item->getPermissions().allowCopyBy(gAgent.getID()))  		{  			deleteInventoryItem(item_id); -			++mInventorySerialNum; +			++mExpectedInventorySerialNum;  		}  	}  } @@ -3146,74 +3151,95 @@ S32 LLFilenameAndTask::sCount = 0;  // static  void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)  { -	LLUUID task_id; -	msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); -	LLViewerObject* object = gObjectList.findObject(task_id); -	if(!object) -	{ -		LL_WARNS() << "LLViewerObject::processTaskInv object " -			<< task_id << " does not exist." << LL_ENDL; -		return; -	} +    LLUUID task_id; +    msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); +    LLViewerObject* object = gObjectList.findObject(task_id); +    if (!object) +    { +        LL_WARNS() << "LLViewerObject::processTaskInv object " +            << task_id << " does not exist." << LL_ENDL; +        return; +    } -	LLFilenameAndTask* ft = new LLFilenameAndTask; -	ft->mTaskID = task_id; -	// we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update -	msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); +    LLFilenameAndTask* ft = new LLFilenameAndTask; +    ft->mTaskID = task_id; +    // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update +    msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); -	if (ft->mSerial < object->mInventorySerialNum) -	{ -		// viewer did some changes to inventory that were not saved yet. -		LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; -		object->mInventorySerialNum = ft->mSerial; -	} +    if (ft->mSerial == object->mInventorySerialNum) +    { +        // Loop Protection. +        // We received same serial twice. +        // Viewer did some changes to inventory that couldn't be saved server side +        // or something went wrong to cause serial to be out of sync +        LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; +        object->mExpectedInventorySerialNum = ft->mSerial; +    } -	std::string unclean_filename; -	msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); -	ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); +    if (ft->mSerial < object->mExpectedInventorySerialNum) +    { +        // out of date message, record to current serial for loop protection, but do not load it +        // just drop xfer to restart on idle +        if (ft->mSerial < object->mInventorySerialNum) +        { +            LL_WARNS() << "Somehow task serial decreased, out of order packet?" << LL_ENDL; +        } +        object->mInventorySerialNum = ft->mSerial; +        object->mInvRequestXFerId = 0; +        object->mInvRequestState = INVENTORY_REQUEST_STOPPED; +    } +    else if (ft->mSerial >= object->mExpectedInventorySerialNum) +    { +        object->mInventorySerialNum = ft->mSerial; +        object->mExpectedInventorySerialNum = ft->mSerial; -	if(ft->mFilename.empty()) -	{ -		LL_DEBUGS() << "Task has no inventory" << LL_ENDL; -		// mock up some inventory to make a drop target. -		if(object->mInventory) -		{ -			object->mInventory->clear(); // will deref and delete it -		} -		else -		{ -			object->mInventory = new LLInventoryObject::object_list_t(); -		} -		LLPointer<LLInventoryObject> obj; -		obj = new LLInventoryObject(object->mID, LLUUID::null, -									LLAssetType::AT_CATEGORY, -									"Contents"); -		object->mInventory->push_front(obj); -		object->doInventoryCallback(); -		delete ft; -		return; -	} -	U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),  -								ft->mFilename, LL_PATH_CACHE, -								object->mRegionp->getHost(), -								TRUE, -								&LLViewerObject::processTaskInvFile, -								(void**)ft, -								LLXferManager::HIGH_PRIORITY); -	if (object->mInvRequestState == INVENTORY_XFER) -	{ -		if (new_id > 0 && new_id != object->mInvRequestXFerId) -		{ -			// we started new download. -			gXferManager->abortRequestById(object->mInvRequestXFerId, -1); -			object->mInvRequestXFerId = new_id; -		} -	} -	else -	{ -		object->mInvRequestState = INVENTORY_XFER; -		object->mInvRequestXFerId = new_id; -	} +        std::string unclean_filename; +        msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); +        ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); + +        if (ft->mFilename.empty()) +        { +            LL_DEBUGS() << "Task has no inventory" << LL_ENDL; +            // mock up some inventory to make a drop target. +            if (object->mInventory) +            { +                object->mInventory->clear(); // will deref and delete it +            } +            else +            { +                object->mInventory = new LLInventoryObject::object_list_t(); +            } +            LLPointer<LLInventoryObject> obj; +            obj = new LLInventoryObject(object->mID, LLUUID::null, +                LLAssetType::AT_CATEGORY, +                "Contents"); +            object->mInventory->push_front(obj); +            object->doInventoryCallback(); +            delete ft; +            return; +        } +        U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), +            ft->mFilename, LL_PATH_CACHE, +            object->mRegionp->getHost(), +            TRUE, +            &LLViewerObject::processTaskInvFile, +            (void**)ft, +            LLXferManager::HIGH_PRIORITY); +        if (object->mInvRequestState == INVENTORY_XFER) +        { +            if (new_id > 0 && new_id != object->mInvRequestXFerId) +            { +                // we started new download. +                gXferManager->abortRequestById(object->mInvRequestXFerId, -1); +                object->mInvRequestXFerId = new_id; +            } +        } +        else +        { +            object->mInvRequestState = INVENTORY_XFER; +            object->mInvRequestXFerId = new_id; +        } +    }  }  void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) @@ -3227,6 +3253,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS  		&& ft->mSerial >= object->mInventorySerialNum)  	{  		object->mInventorySerialNum = ft->mSerial; +		LL_DEBUGS() << "Receiving inventory task file for serial " << object->mInventorySerialNum << " taskid: " << ft->mTaskID << LL_ENDL; +		if (ft->mSerial < object->mExpectedInventorySerialNum) +		{ +			// User managed to change something while inventory was loading +			LL_DEBUGS() << "Processing file that is potentially out of date for task: " << ft->mTaskID << LL_ENDL; +		} +  		if (object->loadTaskInvFile(ft->mFilename))  		{ @@ -3376,7 +3409,7 @@ void LLViewerObject::removeInventory(const LLUUID& item_id)  	msg->addUUIDFast(_PREHASH_ItemID, item_id);  	msg->sendReliable(mRegionp->getHost());  	deleteInventoryItem(item_id); -	++mInventorySerialNum; +	++mExpectedInventorySerialNum;  }  bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 9aaf28f5d0..077b02e097 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -802,6 +802,7 @@ protected:  	typedef std::list<LLInventoryCallbackInfo*> callback_list_t;  	callback_list_t mInventoryCallbacks;  	S16 mInventorySerialNum; +	S16 mExpectedInventorySerialNum;  	enum EInventoryRequestState  	{  | 
